@naeil/ui 0.5.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/DESIGN.md +7 -3
  3. package/README.md +19 -10
  4. package/contracts/naeil-chrome.v1.json +12 -0
  5. package/dist/chunk-HSTDPY56.js +74 -0
  6. package/dist/chunk-OLKTEYLS.js +413 -0
  7. package/dist/{chunk-CE73AEJZ.js → chunk-QQQQZEPV.js} +249 -3
  8. package/dist/{chunk-S64H3OYQ.js → chunk-VWIUN35X.js} +4 -343
  9. package/dist/components/index.d.ts +2 -2
  10. package/dist/components/index.js +11 -9
  11. package/dist/components/naeil-footer.d.ts +16 -0
  12. package/dist/components/naeil-footer.js +76 -0
  13. package/dist/components/naeil-header.d.ts +23 -5
  14. package/dist/components/naeil-header.js +5 -2
  15. package/dist/components/ui/index.d.ts +2 -2
  16. package/dist/components/ui/index.js +6 -6
  17. package/dist/lib/ui-release.d.ts +1 -0
  18. package/dist/lib/ui-release.js +1 -0
  19. package/dist/naeil-header-content-BvISJ4RV.d.ts +4 -0
  20. package/dist/{navigation-CL10a6Eb.d.ts → navigation-CgPeL9tF.d.ts} +1 -1
  21. package/dist/{site-footer-B67meCDv.d.ts → site-footer-vXDa_6yr.d.ts} +4 -2
  22. package/dist/source/components/footer.js +1 -2
  23. package/dist/source/components/naeil-footer.d.ts +16 -0
  24. package/dist/source/components/naeil-footer.js +95 -0
  25. package/dist/source/components/naeil-header-account.d.ts +26 -0
  26. package/dist/source/components/naeil-header-account.js +67 -0
  27. package/dist/source/components/naeil-header.d.ts +2 -1
  28. package/dist/source/components/naeil-header.js +6 -1
  29. package/dist/source/components/ui/site-footer.d.ts +4 -2
  30. package/dist/source/components/ui/site-footer.js +6 -2
  31. package/dist/source/lib/ui-release.d.ts +6 -0
  32. package/dist/source/lib/ui-release.js +4 -0
  33. package/docs/components/README.md +4 -1
  34. package/docs/components/application-layout.md +103 -0
  35. package/docs/components/common.md +2 -2
  36. package/docs/components/naeil-footer.md +20 -0
  37. package/docs/components/naeil-header.md +22 -6
  38. package/docs/components/navigation.md +8 -8
  39. package/docs/design/v2-migration.md +24 -25
  40. package/docs/package-release.md +12 -6
  41. package/package.json +16 -4
  42. package/src/styles/components.css +39 -4
  43. package/src/styles/theme.css +3 -1
  44. package/dist/chunk-QSTGUEEI.js +0 -323
@@ -0,0 +1,103 @@
1
+ # Application frame and shared navigation/footer
2
+
3
+ This guide targets the **@naeil/ui 0.7.0 candidate**, including the width update approved on 2026-10-16. Use the matching registry release or tested local archive. See [consumer setup](../design/v2-migration.md) for CSS, Tailwind sources and fonts.
4
+
5
+ ## Choose the shared composition first
6
+
7
+ | Application need | Use |
8
+ | --- | --- |
9
+ | The actual naeil.dev brand, project catalog and controls | `NaeilHeader` from `@naeil/ui/naeil-header` |
10
+ | A product's own menu | `Navigation` from `@naeil/ui/ui` |
11
+ | Owned naeil service footer | `NaeilFooter` from `@naeil/ui/naeil-footer` |
12
+ | Different product footer or explicit content override | `SiteFooter` from `@naeil/ui/ui` |
13
+ | An existing Next/next-intl consumer | Keep its `Nav` / `Footer` adapters |
14
+
15
+ Choose one header per application frame. Supply menu data, links, route guards, authentication and supported locale state through props/slots. Local adapters are appropriate; copies of the menu, responsive sheet, controls or footer implementation are not. Extend the shared component when a reusable behavior is missing.
16
+
17
+ ## Width contract
18
+
19
+ | Region | Default | CSS contract |
20
+ | --- | --- | --- |
21
+ | Header, main, footer outer frame | Maximum 1600px, including gutters | `--ui-width-frame` |
22
+ | Inline gutters | `clamp(16px, 2.4vw, 40px)` | `--ui-frame-gutter` |
23
+ | Reading / settings | Maximum 640px | `data-ui-layout="reading"` / `"settings"` |
24
+ | Short form | Maximum 480px | `data-ui-layout="short-form"` |
25
+ | List / dashboard / table region | Available space inside the frame, capped at 1600px | `data-ui-layout="list"` |
26
+ | Intentionally unrestricted region | Available parent width | `data-ui-layout="fluid"` |
27
+
28
+ Use `.ui-app-frame` on main. Shared header/footer already apply the frame internally; **do not wrap them in another padded frame**. Put purpose-specific sections inside main. At 1920px the default frame has 1520px available after its 40px gutters. Small screens shrink the frame and reduce gutters to at least 16px. A narrow form must not constrain or move navigation.
29
+
30
+ Reserve a consistent scrollbar gutter in the consumer's global CSS when routes can alternate between short and tall content:
31
+
32
+ ```css
33
+ html { scrollbar-gutter: stable; }
34
+ ```
35
+
36
+ This keeps a centered frame from shifting when a classic scrollbar appears. The document scroll policy belongs to the application; the shared components do not set it implicitly. In a 1920px Chromium viewport with a 15px scrollbar, the frame starts at 152.5px with this policy in both short and tall states. Without it, the start changes from 160px to 152.5px. Overlay-scrollbar platforms may reserve no extra space.
37
+
38
+ ## Canonical naeil application starter
39
+
40
+ ```tsx
41
+ import type { ReactNode } from "react";
42
+ import { NaeilHeader } from "@naeil/ui/naeil-header";
43
+ import { NaeilFooter } from "@naeil/ui/naeil-footer";
44
+
45
+ // Render inside the existing next-themes ThemeProvider.
46
+ // Connect Link/onNavigate, locale and authSlot to real application state.
47
+ export function ApplicationLayout({ children }: { children: ReactNode }) {
48
+ return <>
49
+ <NaeilHeader locale="en" />
50
+ <main className="ui-app-frame"
51
+ style={{ marginTop: "calc(var(--ui-navigation-height) + 1px)" }}>
52
+ {children}
53
+ </main>
54
+ <NaeilFooter locale="en" variant="compact" />
55
+ </>;
56
+ }
57
+
58
+ <ApplicationLayout>
59
+ <section data-ui-layout="settings">{/* Settings form */}</section>
60
+ </ApplicationLayout>
61
+ ```
62
+
63
+ `NaeilHeader` is fixed; reserve its 65px height and account for it in sticky areas and focus/anchor scroll margins. Default destinations are official naeil.dev URLs. Preserve routing/unsaved-change guards using the [header contract](naeil-header.md). Only pass `onLocaleChange` when the application supports its complete language set.
64
+
65
+ For a different product menu, use the [generic Navigation composition](navigation.md) with the same main/footer structure. Generic Navigation is in document flow by default and needs no fixed-header clearance. The [standalone React example](https://github.com/naeil-dev/naeil-ui/tree/main/examples/react) exercises the installed header, narrow form and SiteFooter together.
66
+
67
+ ## Deliberate overrides
68
+
69
+ Apply overrides on a common ancestor or document root so header, main and footer inherit them together. Explicit `containerClassName` overrides still work. Do not give each route its own header cap or gutter.
70
+
71
+ ```css
72
+ /* Product exception: record why this cap is needed. */
73
+ .product-shell {
74
+ --ui-width-frame: 1280px;
75
+ --ui-frame-gutter: 24px;
76
+ }
77
+ /* An existing focused list can retain its previous content cap. */
78
+ .focused-list { --ui-width-list: 1200px; }
79
+ ```
80
+
81
+ The new frame/list caps replace the previous 1280px branded header and 1200px list defaults. Remove old `max-w-7xl` or `px-6` frame overrides when adopting the new default. Shared numeric values belong in `src/tokens/ui.json`; regenerate CSS with `pnpm build:tokens`.
82
+
83
+ ## Consumer agent instructions
84
+
85
+ Put this in the **consumer application's** `AGENTS.md` (or equivalent repository instructions). Installing a package does not automatically load this repository's agent rules.
86
+
87
+ ```markdown
88
+ ## Shared application layout
89
+ - Read the installed @naeil/ui/DESIGN.md and docs/components/application-layout.md before UI layout work.
90
+ - Use @naeil/ui/naeil-header for the canonical naeil header; use Navigation from @naeil/ui/ui for a different product menu. Use NaeilFooter from @naeil/ui/naeil-footer for owned service footers; SiteFooter remains the generic primitive. Keep existing Next Nav/Footer compatibility adapters when applicable.
91
+ - Local wrappers supply menu data, routing/guards, locale, auth and slots. Do not copy the menu, mobile sheet, controls or footer implementation. Extend the shared component for reusable missing behavior.
92
+ - Use ui-app-frame on main; navigation/footer own their internal frames. Keep reading/settings/short-form sections inside that frame. Apply frame overrides consistently across routes.
93
+ - Check the installed package version and CSS before creating a replacement for an apparently missing component.
94
+ - Verify actual shared navigation/footer rendering and stable anchors across routes, themes and supported sizes. An import alone is not adoption evidence. Record intentional route exceptions.
95
+ ```
96
+
97
+ ## Adoption checks
98
+
99
+ For each consumer, record its installed version, layout adapter, shared imports, CSS entrypoints and intentional exceptions. In that consumer's browser CI, check that expected application routes render `[data-slot="navigation"]` and `[data-slot="site-footer"]`, and that anchors remain stable between wide lists and narrow forms. Include narrow/zoomed screens, localized labels and tall content that introduces a scrollbar. Keep table overflow local.
100
+
101
+ A blanket ban on `<header>`, `<nav>` or `<footer>` would also reject valid section landmarks and adapters. Review the root composition and its rendered output instead. This repository checks packed React/Next examples; external applications still need their own upgrades, adapter migrations and CI. Publication and deployment are separate work.
102
+
103
+ See [canonical footer content and save interception](naeil-footer.md). 0.7.0 candidate adds package/contract identity; publication and per-service operational rollout are separate.
@@ -1,12 +1,12 @@
1
1
  # Shared usage contract
2
2
 
3
- These guides target the **@naeil/ui 0.5.0 release candidate**; final archive verification and registry publication are pending. The [hosted Docs](https://naeil-dev.github.io/naeil-ui/) were last verified for [0.4.0 on 2026-10-11](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.4.0), while `pnpm storybook` shows the current candidate. Start with the [consumer setup and migration](../design/v2-migration.md). Primitives and generic Navigation/SiteFooter are exported from `@naeil/ui/ui`; the actual branded whole header uses the opt-in [NaeilHeader](naeil-header.md) entry `@naeil/ui/naeil-header`. Both are React-only. The legacy root needs the optional Next/next-intl peers. Examples import real wrappers; product state, validation and network requests belong to consumers.
3
+ These guides target the **@naeil/ui 0.6.0**; release identities and publication evidence are recorded in the [release record](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.6.0). The [hosted Docs](https://naeil-dev.github.io/naeil-ui/) were last verified for [0.5.0 on 2026-10-15](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.5.0), while `pnpm storybook` shows this checkout. Start with the [consumer setup and migration](../design/v2-migration.md). Primitives and generic Navigation/SiteFooter are exported from `@naeil/ui/ui`; the actual branded whole header uses the opt-in [NaeilHeader](naeil-header.md) entry `@naeil/ui/naeil-header`. Both are React-only. The legacy root needs the optional Next/next-intl peers. Examples import real wrappers; product state, validation and network requests belong to consumers.
4
4
 
5
5
  ## Styling, themes and overrides
6
6
 
7
7
  Import `@naeil/ui/globals.css` once and register `@source` for the installed package's `dist` in your Tailwind 4 build. Alternatively load both theme.css and components.css alongside your existing Tailwind setup. Deliver Pretendard and, for Japanese, Noto Sans JP locally through your app's font pipeline; the package does not fetch fonts. Keep font OFL notices with redistributed binaries. The independent React example demonstrates consumer-owned delivery.
8
8
 
9
- Use `.light`/`.dark` on the document root to override OS theme. Root `data-ui-density="compact"` changes spacing, not text size: default controls are 40px, compact 36px, small screens/coarse pointers at least 44px. Portals use document-level styles/density, so a locally themed subtree alone does not theme portaled content. Purpose-specific reading/settings/list widths are 640/640/1200px caps that shrink to available space; the product owns its application frame.
9
+ Use `.light`/`.dark` on the document root to override OS theme. Root `data-ui-density="compact"` changes spacing, not text size: default controls are 40px, compact 36px, small screens/coarse pointers at least 44px. Portals use document-level styles/density, so a locally themed subtree alone does not theme portaled content. Header, main and footer share a 1600px maximum outer frame and `clamp(16px, 2.4vw, 40px)` gutters. Use `ui-app-frame` on main; shared header/footer components apply that frame internally. Reading/settings sections remain capped at 640px, short forms at 480px, and lists at 1600px within the available frame space. Product root token overrides and explicit component classes remain supported. The [application layout guide](application-layout.md) explains composition, adoption and consistent overrides.
10
10
 
11
11
  `className` is merged by `cn` (clsx + tailwind-merge). Consumer classes and primitive props remain available. Recheck specificity, text/control/focus contrast, mobile targets and portaled content after overriding. Override semantic color companions together; do not replace only an action hue or remove focus outlines. Reduced-motion rules remove shared transitions/animations. Custom consumer animation still needs its own reduced-motion treatment.
12
12
 
@@ -0,0 +1,20 @@
1
+ # NaeilFooter — canonical service footer
2
+
3
+ New in the **0.7.0 candidate** (not published). React-only opt-in entry:
4
+
5
+ ```tsx
6
+ import { NaeilFooter } from '@naeil/ui/naeil-footer';
7
+ <NaeilFooter locale="ja" variant="compact" Link={GuardedLink} />
8
+ ```
9
+
10
+ Use with [NaeilHeader](naeil-header.md) on owned user-facing services. Both `full` and `compact` contain the .naeil home link, Projects, Blog and the official naeil GitHub link. Full also displays the existing tagline. Compact reduces spacing/description, not the destinations. No social account or legal claim is invented. The website's former generic X homepage icon is not a canonical account link.
11
+
12
+ `locale` selects `en`, `ko`, or `ja`. `resolveHref(path)` defaults to official localized naeil.dev destinations; a local website router may resolve unlocalized paths itself. `Link` handles **every** canonical anchor, including absolute GitHub URLs. It must forward href, target, rel, onClick, className and children. GitHub opens a new tab with noopener/noreferrer. The shared implementation does not itself trigger navigation or await saves.
13
+
14
+ `onNavigate(event, item)` reaches the brand and all group links. An application can synchronously preventDefault, flush its draft, and navigate only after successful saving. Preserve defaultPrevented, modified/middle clicks and target behavior according to the application's established guard. Do not run both adapter and onNavigate guards twice. Native explicit `external:true` links in generic SiteFooter bypass Link for compatibility, but **still call onNavigate**. This closes the former missing interception path.
15
+
16
+ `variant`, `className`, `containerClassName`, standard footer attributes, `meta` and children remain available. Product status/legal information belongs in meta; no private build data belongs in the UI. Canonical content has no arbitrary replacement groups/brand. Existing generic SiteFooter and Next/next-intl Footer keep their override APIs. Record intentional departures from the canonical composition as rollout exceptions; same component imports alone are not adoption evidence.
17
+
18
+ Footer owns its internal 1600px/clamp frame. Do not wrap it in an additional padded container. Its `data-naeil-footer`, `data-naeil-ui-version` and `data-naeil-ui-contract` identify the actual rendering. `@naeil/ui/release` exports `uiRelease` for the application-owned public artifact identity endpoint. That endpoint exposes only schemaVersion, appId, artifactId, sourceRevision and ui. Release version is not proof of deployment without the matching app artifact and rendered checks.
19
+
20
+ Actual shared examples: **Brand / NaeilHeader / ReferenceFull, ReferenceCompact, JapaneseApplication**. Full legacy Footer examples remain compatibility checks. Consumer saves, failures, auth, real supported locales and modified clicks require product tests.
@@ -1,14 +1,17 @@
1
1
  # NaeilHeader — branded whole-header composition
2
2
 
3
- This guide targets the **@naeil/ui 0.5.0 release candidate**. Final archive verification and registry publication are pending. Import this opt-in React-only entry when an application inherits the actual naeil.dev header. Generic `Navigation` from `/ui` remains available for different product menus.
3
+ This guide includes the **@naeil/ui 0.7.1 candidate**, whose unchanged frame comes from published 0.6.0. See the [release record](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.6.0) for archive and publication evidence. Import this opt-in React-only entry when an application inherits the actual naeil.dev header. Generic `Navigation` from `/ui` remains available for different product menus.
4
4
 
5
5
  ```tsx
6
- import { NaeilHeader } from '@naeil/ui/naeil-header';
6
+ import { NaeilHeader, NaeilHeaderAccountControl } from '@naeil/ui/naeil-header';
7
7
  import '@naeil/ui/globals.css';
8
8
 
9
9
  // Inside the consumer's existing next-themes ThemeProvider:
10
10
  <NaeilHeader locale="ja" Link={GuardedLink} currentHref={pathname}
11
- authSlot={<LogoutButton />} />
11
+ authSlot={<NaeilHeaderAccountControl locale="ja" Link={GuardedLink}
12
+ account={authenticated
13
+ ? { status: 'signed-in', onLogout: () => { void guardedLogout(); }, busy: leaving }
14
+ : { status: 'signed-out', loginHref: '/login' }} />} />
12
15
  ```
13
16
 
14
17
  Load shared styles once. Apps that already own their Tailwind/base styles may import both `@naeil/ui/theme.css` and `@naeil/ui/components.css` instead of globals. Tailwind 4 consumers must register the installed `dist` with `@source`; see [setup](../design/v2-migration.md#시작하기).
@@ -19,7 +22,7 @@ The module owns the brand, five-project catalog and header-only translations, pr
19
22
 
20
23
  Consumers provide an existing next-themes provider, routing/dirty-save guard, current locale and real authentication behavior. Default destinations point to `https://naeil.dev/{locale}`; the site's localized Link instead uses `resolveHref={path => path}`. A supplied `Link` handles default official destinations, including cross-origin URLs. `onNavigate` can intercept brand and menu links; honor modified clicks and target behavior. Explicit `external: true` project overrides and `projectsExternal` use native anchors, so intercept them with `onNavigate` when a dirty guard is required.
21
24
 
22
- Only provide `onLocaleChange` when the application's interface supports all three canonical locales (`en`, `ko`, `ja`). Omitting it removes the locale control; the component does not create application translations or shared preferences. `authSlot` contains the consumer's real session action and must retain at least 44px touch targets. It does not integrate site SSO, share credentials or create accounts. Theme preferences remain consumer-origin state. Without a working provider, rendering alone does not establish theme switching.
25
+ Only provide `onLocaleChange` when the application's interface supports all three canonical locales (`en`, `ko`, `ja`). Omitting it removes the locale control; the component does not create application translations or shared preferences. `authSlot` uses `NaeilHeaderAccountControl` in owned applications: a shared44px neutral account trigger and localized Radix logout menu. Consumers supply their real session state/callbacks, not alternative account markup. The legacy slot remains public for deliberate compatibility overrides. It does not integrate site SSO, share credentials or create accounts. Theme preferences remain consumer-origin state. Without a working provider, rendering alone does not establish theme switching.
23
26
 
24
27
  | Prop | Contract |
25
28
  | --- | --- |
@@ -27,7 +30,7 @@ Only provide `onLocaleChange` when the application's interface supports all thre
27
30
  | `resolveHref` | Resolves canonical unlocalized paths; defaults to the official localized site. |
28
31
  | `Link`, `currentHref`, `onNavigate` | Routing adapter, active destination and navigation interception inherited from Navigation. |
29
32
  | `onLocaleChange` | Optional supported-language callback; omit for a single-language application. |
30
- | `authSlot` | Consumer-owned authentication action in the default toolbar. |
33
+ | `authSlot` | Canonical `NaeilHeaderAccountControl`, with consumer-owned auth state/actions. Legacy arbitrary markup remains supported. |
31
34
  | `brandHref`, `brandSlot`, `brandLinkProps`, `brandLinkComponent` | Explicit brand destination/content/anchor overrides; default accessible brand name is `.naeil`. |
32
35
  | `projects`, `projectsExternal`, `showProjects`, `showBlog` | Legacy catalog/visibility/native-link overrides; defaults use the complete canonical catalog. |
33
36
  | `subNav`, `currentProjectKey`, `currentProjectHref` | Legacy extra links and current-project destination. |
@@ -37,9 +40,20 @@ Only provide `onLocaleChange` when the application's interface supports all thre
37
40
 
38
41
  Standard header attributes and the remaining inherited [Navigation props](navigation.md) remain available. Compatibility overrides preserve existing consumers; new applications normally use the canonical composition.
39
42
 
43
+ ## Account presentation
44
+
45
+ `NaeilHeaderAccountControl` accepts `locale`, optional routing `Link`, and `account`:
46
+
47
+ - `{ status: 'signed-out', loginHref }` renders the shared login link through that adapter.
48
+ - `{ status: 'signed-in', onLogout, busy?, displayName?, email? }` renders the same account icon in every app; optional identity appears only inside its menu. There is no shared identity or avatar fetch.
49
+ - `onLogout` starts the app's guarded action; the app handles async errors, cancellation, session endpoints and redirects. `busy` disables the menu action while keeping the trigger available, with `aria-busy`, for inspection and focus restoration. Cancel/failure clears busy and permits retry.
50
+ - Callback invocation closes the menu and returns focus to the trigger. Mobile navigation may remain open during a failed action. The account menu uses the existing Radix overlay/inert implementation.
51
+
52
+ Keep errors visible in the consumer's recovery UI or toast. The package never calls an authentication endpoint. Compare signed-in and signed-out render states separately; anonymous-only acceptance cannot establish authenticated parity. `AccountStates` is a synthetic Storybook example for pending/cancel/error/retry.
53
+
40
54
  ## Frame and content clearance
41
55
 
42
- The fixed header is 65px: the current 64px navigation token plus a 1px border. Clear it in the application's main, sticky regions and focus/anchor scroll margins with `calc(var(--ui-navigation-height) + 1px)`. The branded header uses the actual site's 1280px cap and 24px gutters; body/footer widths belong to the product. A 1600px workspace body does not change this header cap or create a new shared foundation token.
56
+ The fixed header is 65px: the current 64px navigation token plus a 1px border. Clear it in the application's main, sticky regions and focus/anchor scroll margins with `calc(var(--ui-navigation-height) + 1px)`. The header, main and footer now share a 1600px maximum outer frame, including responsive `clamp(16px, 2.4vw, 40px)` gutters. Put `ui-app-frame` on main and reading/settings or short-form sections inside it; the header and shared footer apply their own internal frame. Do not wrap them in another padded frame. Apply deliberate `--ui-width-frame` / `--ui-frame-gutter` overrides on a common ancestor. Remove old `max-w-7xl` or `px-6` overrides to adopt the new defaults. This width update supersedes the previous 1280px/24px branded frame. See the [application layout starter](application-layout.md).
43
57
 
44
58
  ## Artwork and package boundary
45
59
 
@@ -48,3 +62,5 @@ The five decorative images reference `https://naeil.dev/images/{coral,jellyfish,
48
62
  This entry requires no Next.js, next-intl, site session/auth backend, full application message catalog, hero or site public folder. Generic `/ui` imports do not import its catalog. The local Storybook provides **Brand / NaeilHeader / Docs, Usage, JapaneseApplication**; the Japanese example omits unsupported locale switching and uses a consumer-owned auth slot. Candidate examples do not establish hosted deployment.
49
63
 
50
64
  Verify actual packed consumption, Storybook behavior and rendered comparisons at matching viewport/language/theme. Source imports alone do not prove visual parity. Native Safari, devices, assistive technology, full OAuth and unresolved accessibility observations retain the [documented support limits](../design/public-ui-support.md).
65
+
66
+ Pair owned-service headers with [NaeilFooter](naeil-footer.md). The 0.7.1 candidate emits package/contract identifiers for actual rendered validation.
@@ -1,6 +1,6 @@
1
1
  # Navigation and SiteFooter
2
2
 
3
- This guide targets the **0.5.0 release candidate**; final archive verification and publication are pending. These are generic product-menu primitives. Applications inheriting the actual naeil.dev brand/catalog/control composition use the canonical opt-in [NaeilHeader](naeil-header.md) from `@naeil/ui/naeil-header`, with its fixed 65px/1280px frame and official artwork URL dependency.
3
+ This guide targets the **@naeil/ui 0.6.0**; release identities and publication evidence are recorded in the [release record](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.6.0). These are generic product-menu primitives. Applications inheriting the actual naeil.dev brand/catalog/control composition use the canonical opt-in [NaeilHeader](naeil-header.md) from `@naeil/ui/naeil-header`, with fixed positioning, a 65px height, the shared application frame and official artwork URL dependency.
4
4
 
5
5
  `Navigation` and `SiteFooter` are React-only exports from `@naeil/ui/ui` (also `@naeil/ui/components/ui/navigation` and `@naeil/ui/components/ui/site-footer`). They require shared theme/components CSS and the normal consumer font/Tailwind setup. They do not import Next, next-intl, authentication, product routes or message dictionaries.
6
6
 
@@ -15,7 +15,6 @@ import { Navigation, SiteFooter } from "@naeil/ui/ui";
15
15
  { id: "keys", label: "API keys", href: "/keys" },
16
16
  ] }]}
17
17
  currentHref={pathname}
18
- containerClassName="product-frame"
19
18
  toolbar={<ProductControls />}
20
19
  onNavigate={(event, item) => {
21
20
  if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
@@ -23,26 +22,25 @@ import { Navigation, SiteFooter } from "@naeil/ui/ui";
23
22
  guardedNavigate(item.href);
24
23
  }}
25
24
  />
26
- <main className="product-frame">
25
+ <main className="ui-app-frame">
27
26
  <section data-ui-layout="settings">{/* narrow form inside stable frame */}</section>
28
27
  </main>
29
28
  <SiteFooter
30
29
  brand={<ProductBrand />}
31
30
  variant="compact"
32
31
  meta="Product information"
33
- containerClassName="product-frame"
34
32
  />
35
33
  ```
36
34
 
37
- These are composition snippets: `pathname`, controls, brand, frame and `guardedNavigate` belong to the application. Keep its unsaved-change guard and modified-click behavior. Alternatively supply a `Link` adapter which forwards anchor props, `onClick`, `aria-current`, `className`, target and children. Links explicitly marked `external: true` render native anchors; an absolute URL alone does not bypass the supplied `Link`. `active` overrides exact `currentHref` matching when a route family needs custom matching.
35
+ These are composition snippets: `pathname`, controls, brand and `guardedNavigate` belong to the application. Keep its unsaved-change guard and modified-click behavior. Alternatively supply a `Link` adapter which forwards anchor props, `onClick`, `aria-current`, `className`, target and children. Links explicitly marked `external: true` render native anchors; an absolute URL alone does not bypass the supplied `Link`. `active` overrides exact `currentHref` matching when a route family needs custom matching.
38
36
 
39
37
  `Navigation` accepts links and one level of labeled groups, optional description/icon/badge, `toolbar`, `mobileToolbar` and `mobileFooter`. Brand is a slot; the component does not invent a home destination or label. Groups use Radix Popover with actual links (Tab navigation, Escape and focus return); they are not action menus. Mobile uses a modal Radix Dialog with scroll locking, trapped focus and a labeled close control. The sheet closes on destination selection, currentHref changes or a return to desktop.
40
38
 
41
39
  Desktop groups open on mouse hover without moving keyboard focus. Leaving both the trigger and panel closes the hover preview after the standard 180ms token duration, allowing travel across the portal gap. Entering the panel cancels the pending close. Mouse clicks keep the menu open while the pointer remains in the trigger/panel and do not pin it: leaving still dismisses it. Keyboard-activating a hovered trigger takes over the open menu and focuses its first link; subsequent keyboard activation, Escape, outside interaction or navigation dismisses it. A menu being used with keyboard focus remains open when the pointer leaves. Mouse dismissal preserves the previous focus; keyboard activation retains Radix focus return. Touch uses click/tap, and the mobile sheet behavior is unchanged. Reduced motion disables visual transitions while retaining pointer travel tolerance.
42
40
 
43
- Container queries select desktop layout at 48rem of available header content width. Product frame classes control max width and gutters. Header height uses `ui.navigation-height` (64px); toolbar controls should remain short, with volatile counts in the content area. Navigation itself is in document flow; `className` can make it sticky or fixed. Fixed consumers must reserve its height in page composition. A narrow form must not constrain the header. Explicit className/style remain consumer overrides.
41
+ Container queries select desktop layout at 48rem of available header content width. Navigation, main and footer share a maximum 1600px outer frame and `clamp(16px, 2.4vw, 40px)` gutters by default. Use `ui-app-frame` on main; do not wrap Navigation or SiteFooter in another padded frame. Reading/settings sections inside main retain their 640px cap. The [application layout guide](application-layout.md) covers composition and consistent root token overrides. Header height uses `ui.navigation-height` (64px); toolbar controls should remain short, with volatile counts in the content area. Navigation itself is in document flow; `className` can make it sticky or fixed. Fixed consumers must reserve its height in page composition. A narrow form must not constrain the header. Explicit className/style remain consumer overrides.
44
42
 
45
- `SiteFooter` supports `brand`, `description`, `groups: [{ id, label, links }]`, `meta`, children, `Link`, `containerClassName` and `variant="full|compact"`. Each link group is a labeled navigation landmark. Translated titles, destinations, legal/version text and social links belong to the consumer. A product may place a compact footer in its mobile sheet; a full marketing footer is not mandatory in a dashboard.
43
+ `SiteFooter` supports `brand`, `description`, `groups: [{ id, label, links }]`, `meta`, children, `Link`, `containerClassName`, `variant="full|compact"` and `onNavigate(event, item)` (0.7.0 candidate, including explicit external anchors). Each link group is a labeled navigation landmark. Translated titles, destinations, legal/version text and social links belong to the consumer. A product may place a compact footer in its mobile sheet; a full marketing footer is not mandatory in a dashboard.
46
44
 
47
45
  Desktop reserves `ui.navigation-brand-width` (160px) for the brand, followed by the existing 16px row gap. With matching frame, viewport and font conditions, `.naeil` and `.naeil Home` therefore start their first menu at the same position. Mobile keeps intrinsic brand width. For a larger custom brand, override `--ui-navigation-brand-width` on the header or shared product frame; use the same value across related compositions and ensure the brand fits the reserved area.
48
46
 
@@ -50,10 +48,12 @@ Desktop reserves `ui.navigation-brand-width` (160px) for the brand, followed by
50
48
 
51
49
  Menu groups accept `columns?: 1 | 2` (default 1). The candidate sample uses 2 for the website project catalog and 1 for Home's functional menu; the mobile sheet remains one column. Menu widths use `ui.navigation-menu-width` (320px) and `ui.navigation-menu-wide-width` (640px), capped by available space. Group links share a 40px icon area, 16px icon-to-copy gap, title/description hierarchy and badges beside the title. Supply decorated brand artwork through `icon`; the shared package does not own product illustrations. Current group links use background, semibold title and a check indicator, retaining `aria-current` and keyboard focus without underlining descriptions.
52
50
 
53
- Existing `Nav` and `Footer` imports and props remain. `Nav` adapts the canonical NaeilHeader, which renders this generic core; `Footer` composes SiteFooter. `Nav` retains its fixed positioning and max-w-7xl site frame; menus gain keyboard/focus support, an opaque shared surface, 16px labels and a 64px minimum row. Its `projects` prop replaces the old default inventory; the old naeil projects remain the fallback for existing consumers. Optional `labels`, `className` and `containerClassName` support localization and frame overrides.
51
+ Existing `Nav` and `Footer` imports and props remain. `Nav` adapts the canonical NaeilHeader, which renders this generic core; `Footer` composes SiteFooter. `Nav` retains its fixed positioning and uses the shared 1600px application frame; menus gain keyboard/focus support, an opaque shared surface, 16px labels and a 64px minimum row. Its `projects` prop replaces the old default inventory; the old naeil projects remain the fallback for existing consumers. Optional `labels`, `className` and `containerClassName` support localization and frame overrides. Remove old `max-w-7xl` or `px-6` frame overrides to adopt the new defaults.
54
52
 
55
53
  `Footer` adds `brandSlot`, `description`, `groups`, `socialSlot`, `meta`, `variant`, `className` and `containerClassName`. Use empty groups or null description/socialSlot to omit defaults. Existing linksExternal behavior remains for the default naeil links. Custom groups define their own absolute destinations and external/target settings.
56
54
 
57
55
  `Nav`/`Footer` continue to need Next/next-intl as documented. React-only services use this core for their own product menus or `/naeil-header` for the canonical branded composition. ThemeProvider, ThemeToggleIcon, LocaleSwitcher and Logo remain available through their existing React-safe deep imports. Reusing controls does not synchronize theme/language/authentication between origins.
58
56
 
59
57
  Storybook: `UI/Navigation` (website, Home composition, long labels), `UI/SiteFooter` (full and compact). Naeil Home is a synthetic composition based on the inspected live menu, not proof of a deployed migration. The repository task note `docs/design/navigation-footer-integration.md` tracks rollout; it is not included in the npm package.
58
+
59
+ Owned naeil services use [NaeilFooter](naeil-footer.md) for the common content preset. Generic and legacy content overrides remain supported.
@@ -2,25 +2,21 @@
2
2
 
3
3
  이 안내는 `@naeil/ui`의 기본 모양과 재사용 규칙을 설명한다. 패키지 소비와 소비 사이트 배포는 별도 작업이다.
4
4
 
5
- 이 안내는 **@naeil/ui 0.5.0 릴리스 후보**의 CSS·API·패키지 경계를 대상으로 한다. 최종 소스·archive 검증과 registry 게시, 새 Docs·운영 사이트 배포는 아직 완료로 기록하지 않는다. 2026-10-11에 확인한 npm 0.4.0 게시·latest와 당시 소비 앱·Docs·운영 사이트 결과는 [0.4.0 게시 기록](https://github.com/naeil-dev/naeil-ui/blob/main/docs/design/naeil-brand-0.4.0-publication.md)으로 유지한다. UI v2는 디자인 세대 이름이며 npm 2.0을 뜻하지 않는다.
5
+ 이 안내는 **@naeil/ui 0.6.0**의 CSS·API·패키지 경계를 대상으로 한다. UI v2는 디자인 세대 이름이며 npm 2.0을 뜻하지 않는다. 소스·archive와 실제 게시·배포 결과는 [릴리스 기록](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.6.0)에서 구분한다. 이전 0.5.0은 2026-10-15에 게시되었으며, 이번 버전에서 공통 1600px 프레임과 적용 규칙을 추가한다.
6
6
 
7
7
  ## 시작하기
8
8
 
9
- React 19/ReactDOM 19와 Tailwind 4 앱에서 `/ui` 또는 선택적 `/naeil-header`를 사용한다. API 키와 Next.js는 필요 없다. 후보 검증 중에는 저장소에서 빌드·pack한 archive를 소비 앱에 설치한다.
9
+ React 19/ReactDOM 19와 Tailwind 4 앱에서 `/ui` 또는 선택적 `/naeil-header`를 사용한다. API 키와 Next.js는 필요 없다.
10
10
 
11
11
  ```sh
12
- # 이 저장소에서:
13
- pnpm build:pkg
14
- npm pack --ignore-scripts --pack-destination /tmp
15
- # 소비 앱에서:
16
- pnpm add --save-exact /tmp/naeil-ui-0.5.0.tgz
12
+ pnpm add --save-exact @naeil/ui@0.6.0
17
13
  ```
18
14
 
19
- 0.5.0 registry 게시가 실제 확인된 뒤에는 `pnpm add --save-exact @naeil/ui@0.5.0`을 사용한다. 설치 명령을 문서에 쓰는 것만으로 게시가 완료되지는 않는다. [독립 React 예제](https://github.com/naeil-dev/naeil-ui/blob/81fd395031dc5b20074c4d915a8585360ce2d28a/examples/react/README.md)와 [검증/릴리스 정책](../package-release.md)을 참고한다.
15
+ 로컬 후보를 검증할 때는 저장소에서 `pnpm build:pkg`와 `npm pack --ignore-scripts --pack-destination /tmp`를 실행하고 `/tmp/naeil-ui-0.6.0.tgz`를 설치한다. [독립 React 예제](https://github.com/naeil-dev/naeil-ui/tree/main/examples/react)와 [검증/릴리스 정책](../package-release.md)을 참고한다.
20
16
 
21
17
  공통 UI 소비에는 Supabase, 21st 또는 다른 API 키가 필요하지 않다. React/ReactDOM 19는 소비 앱의 peer이며, Next 15/16과 next-intl 4는 호환 경로에 필요한 선택적 peer다. next-themes 0.4와 tailwind-merge 3은 공통 런타임 의존성으로 설치된다. 사이트의 Supabase·MDX·Three 의존성과 코드는 공통 소비 경계에서 제외했다.
22
18
 
23
- 버전을 생략한 설치는 registry의 latest 태그를 따른다. 이 안내와 동일한 경계를 사용하려면 검증된 0.5.0 후보 archive를 사용하고, 게시 확인 후에는 0.5.0을 지정한다. 업그레이드 전에 [변경 기록](../../CHANGELOG.md)을 확인한다.
19
+ 버전을 생략한 설치는 registry의 latest 태그를 따른다. 이 안내와 동일한 경계를 사용하려면 0.6.0을 명시하거나 같은 버전의 검증된 로컬 archive를 사용한다. 업그레이드 전에 [변경 기록](../../CHANGELOG.md)을 확인한다.
24
20
 
25
21
  Tailwind 4를 사용하는 앱의 전역 CSS에서 공통 스타일을 한 번 불러온다.
26
22
 
@@ -54,7 +50,8 @@ Select는 값 선택, DropdownMenu는 행동 선택에 사용한다. Switch와 C
54
50
  - 본문·입력·버튼 16px, 보조 14px, 메타정보 13px. 작은 화면에서도 입력 글씨를 줄이지 않는다.
55
51
  - 기본 컨트롤 높이 40px. 문서 루트에 `data-ui-density="compact"`를 주면 36px가 된다. 작은 화면과 거친 포인터에서는 최소 44px를 유지한다. 데스크톱에서 `className="h-8"` 같은 높이 재정의는 적용되며, 모바일의 44px 최소 터치 크기는 유지된다.
56
52
  - `.light`/`.dark`는 OS 테마보다 우선한다. 기존 ThemeProvider를 사용할 수 있다.
57
- - `data-ui-layout="reading|settings|list|short-form|fluid"`로 콘텐츠 폭을 적용한다. 각각 최대 640/640/1200/480px 또는 가용 폭이다. 이 속성은 전체 앱의 레이아웃을 강제하지 않는다.
53
+ - 공통 바깥 틀은 최대 1600px, 좌우 여백은 `clamp(16px, 2.4vw, 40px)`다. 본문의 `.ui-app-frame`과 공통 헤더·푸터 내부 프레임이 같은 토큰을 사용한다.
54
+ - `data-ui-layout="reading|settings|list|short-form|fluid"`로 내부 콘텐츠 폭을 적용한다. 각각 최대 640/640/1600/480px 또는 가용 폭이다. 목록은 바깥 틀의 여백을 제외한 공간을 사용하고, 설정·읽기 영역은 그 안에서 좁게 유지한다.
58
55
  - 레이블·도움말·오류 문구는 소비 화면이 연결한다. Input의 `aria-invalid`와 `aria-describedby`를 사용하고, 로딩 중에는 Button의 `disabled`와 `aria-busy`를 함께 지정한다.
59
56
  - 성공·경고·오류·안내에는 Badge의 `success`, `warning`, `error`, `info` variant를 사용할 수 있다. 색만으로 의미를 전달하지 않는다.
60
57
 
@@ -85,37 +82,39 @@ Next.js 소비자는 layout의 metadata title 기본값/템플릿과 페이지
85
82
 
86
83
  실제 naeil.dev 브랜드 헤더를 이어받는 앱은 선택적 React 전용 `@naeil/ui/naeil-header`의 `NaeilHeader`를 사용한다. 전체 프로젝트 메뉴·헤더 번역·테마/선택적 언어 컨트롤·toolbar·반응형 스타일을 한 모듈에서 제공하므로 소비 앱에 다시 복사하지 않는다. 소비 앱은 기존 theme provider, 라우팅·저장 guard, 현재 언어와 실제 인증 슬롯을 연결한다. 언어 변경을 지원하지 않으면 `onLocaleChange`를 생략한다. [전체 헤더 계약](../components/naeil-header.md)을 참조한다.
87
84
 
88
- 이 브랜드 헤더는 고정 높이 65px, 최대 폭 1280px, 좌우 여백 24px를 사용한다. 본문·푸터의 제품별 폭과 독립적이다. 소비 앱은 main·sticky 영역과 초점/anchor 이동에 `calc(var(--ui-navigation-height) + 1px)`만큼 여유를 둔다. 다섯 장식 이미지는 공식 `https://naeil.dev/images/*.png` URL을 참조하므로 네트워크가 필요하다. 이미지 바이트는 npm에 포함하지 않으며 재배포 출처·권리 미해결 사항은 [제3자 고지](../../THIRD_PARTY_NOTICES.md)에 유지한다.
85
+ 2026-10-16 승인한 기본 프레임은 최대 1600px(여백 포함), 좌우 `clamp(16px, 2.4vw, 40px)`다. 브랜드 헤더·범용 Navigation·SiteFooter·본문 `.ui-app-frame`이 `--ui-width-frame`, `--ui-frame-gutter`를 함께 사용한다. 브랜드 헤더의 고정 높이는 65px이므로 main·sticky 영역과 초점/anchor 이동에 `calc(var(--ui-navigation-height) + 1px)`만큼 여유를 둔다. 다섯 장식 이미지는 공식 `https://naeil.dev/images/*.png` URL을 참조하므로 네트워크가 필요하다. 이미지 바이트는 npm에 포함하지 않으며 재배포 출처·권리 미해결 사항은 [제3자 고지](../../THIRD_PARTY_NOTICES.md)에 유지한다.
89
86
 
90
87
  다른 제품 메뉴에는 `@naeil/ui/ui`의 범용 `Navigation`과 `SiteFooter`를 조합하고 제품 메뉴 데이터·번역·폭을 소유한다. 기존 `Nav`·`Footer`는 Next/next-intl 호환 API를 유지한다. [범용 API와 마이그레이션 안내](../components/navigation.md)를 참조한다. Naeil Home 운영 적용은 아직 완료되지 않았으며 저장소의 `docs/design/navigation-footer-integration.md`에서 추적한다.
91
88
 
92
89
  앱의 공통 헤더·메뉴·좌우 여백과 본문의 읽기/설정/목록 폭은 별도로 관리한다. 같은 앱 틀을 사용하는 페이지는 같은 화면 크기·언어·테마에서 메뉴 위치가 유지되어야 한다. 설정 폼을 640px로 제한할 때 헤더까지 그 폭에 종속시키지 않는다. 변동하는 계정 수·상태 요약도 메뉴를 밀어내지 않도록 배치한다.
93
90
 
94
- 아래는 소비 앱의 구성 예이며 새 패키지 API가 아니다. `product-frame`과 최대 폭·여백은 제품에서 소유하고 정한다. 공통 숫자 토큰은 `src/tokens/*.json`을 기준으로 한다.
91
+ 아래처럼 실제 공통 컴포넌트로 앱 틀을 구성한다. 공통 헤더·푸터는 내부에 프레임이 있으므로 다른 패딩 컨테이너로 다시 감싸지 않는다. `items`, `pathname`, `ProductControls`는 제품이 제공한다. 고정형 브랜드 헤더를 사용하는 완성 예제와 소비 앱에 복사할 `AGENTS.md` 규칙은 [Application layout](../components/application-layout.md)에 있다.
95
92
 
96
93
  ```tsx
94
+ import { Navigation, SiteFooter } from "@naeil/ui/ui";
95
+
97
96
  <>
98
- <header>
99
- <div className="product-frame"><ProductNavigation /></div>
100
- </header>
101
- <main className="product-frame">
97
+ <Navigation brand={<a href="/">My product</a>}
98
+ items={items} currentHref={pathname} toolbar={<ProductControls />}
99
+ labels={{ navigation: "주 메뉴", menu: "메뉴", close: "닫기" }} />
100
+ <main className="ui-app-frame">
102
101
  <section data-ui-layout="settings">{/* 설정 폼 */}</section>
103
102
  </main>
103
+ <SiteFooter variant="compact" meta="Product information" />
104
104
  </>
105
105
  ```
106
106
 
107
107
  ```css
108
- /* 제품이 결정한 --product-frame-max, --product-gutter를 사용한다. */
109
- .product-frame {
110
- box-sizing: border-box;
111
- width: 100%;
112
- max-width: var(--product-frame-max, 100%);
113
- margin-inline: auto;
114
- padding-inline: var(--product-gutter, 0);
108
+ /* 의도적인 제품 예외는 세 영역의 공통 조상에서 재정의한다. */
109
+ .product-shell {
110
+ --ui-width-frame: 1280px;
111
+ --ui-frame-gutter: 24px;
115
112
  }
116
113
  ```
117
114
 
118
- 대시보드라는 이유만으로 전체 폭을 쓰거나, 다른 제품의 1600px를 공통 기준으로 가져오지 않는다. 실제 과업·정보량·짧은/긴 내용으로 폭을 판단한다. 내부 카드·보고서 열 수는 모니터 폭보다 실제 콘텐츠 영역 폭에 맞춘다. 필요한 경우 container query를 사용한다.
115
+ 이번 1600px는 사용자가 Naeil Home의 실제 폭을 비교한 뒤 공통 기본값으로 선택한 결정이다. 1920px 화면에서는 여백을 제외한 영역이 1520px다. 실제 과업·정보량·짧은/긴 내용으로 내부 구성을 판단한다. 내부 카드·보고서 열 수는 모니터 폭보다 실제 콘텐츠 영역 폭에 맞추며, 필요한 경우 container query를 사용한다.
116
+
117
+ 이전 1280px 헤더·24px 여백과 1200px 목록 기본값이 변경된다. 새 기본값을 적용할 때 기존 `max-w-7xl`·`px-6` 프레임 재정의를 제거한다. 기존 레이아웃을 유지해야 하면 위 프레임 토큰 및 `--ui-width-list: 1200px`를 명시한다. 공개 import·props·소비자 className 재정의는 유지된다. 설치된 패키지와 CSS를 먼저 확인하고, 메뉴·모바일 시트·푸터 구현을 복사하는 대신 공통 API와 슬롯으로 연결한다.
119
118
 
120
119
  레이아웃 수정의 검증 기준:
121
120
 
@@ -170,7 +169,7 @@ Storybook의 로컬 폰트 import는 예시다. 그대로 앱 전역에 모든
170
169
 
171
170
  ## 0.3 package boundary
172
171
 
173
- The heading retains the original 0.3 migration anchor; the allowlist below reflects the 0.5.0 candidate additions. `/ui` is the React core. The opt-in `/naeil-header` is the canonical complete branded header, also React-only. Root imports preserve Nav, Footer, Logo, LocaleSwitcher, ThemeProvider, ThemeToggle, ThemeToggleIcon, PageTitle, SectionTitle and their class helpers, but root has static Next/next-intl dependencies. React-only apps must use `/ui`, `/utils` and appropriate shared deep modules. `next-themes` is a React runtime library; it does not require Next.js. Fonts remain consumer-owned.
172
+ The heading retains the original 0.3 migration anchor; the allowlist below reflects the 0.6.0 package boundary. `/ui` is the React core. The opt-in `/naeil-header` is the canonical complete branded header, also React-only. Root imports preserve Nav, Footer, Logo, LocaleSwitcher, ThemeProvider, ThemeToggle, ThemeToggleIcon, PageTitle, SectionTitle and their class helpers, but root has static Next/next-intl dependencies. React-only apps must use `/ui`, `/utils` and appropriate shared deep modules. `next-themes` is a React runtime library; it does not require Next.js. Fonts remain consumer-owned.
174
173
 
175
174
  Next.js `^15 || ^16` and next-intl `^4` are optional peers. Install both when using root, Nav, Footer or `i18n/routing`. This is an existing compatibility contract, not a claim that every peer combination has browser validation; the clean Next fixture checks Next 16.1.7. React/ReactDOM `^19` come from the host. Tailwind 4 is the documented styling pipeline. Explicit `className`, Radix props, Toaster options and theme-provider props remain consumer overrides.
176
175
 
@@ -1,11 +1,13 @@
1
1
  # Package verification and release policy
2
2
 
3
- This policy covers the intended **@naeil/ui 0.5.0 release candidate**. Final source/archive verification, registry publication and new hosted deployments are pending. Verified 0.4.0 (2026-10-11) and 0.3.0 publication evidence below remains dated history. UI v2 names a design generation, not an npm major. Future breaking changes require an explicit migration and version decision. Version-scoped installation is in the [README](../README.md#use-the-ui).
3
+ The current implementation candidate is **@naeil/ui 0.7.0**, adding the canonical footer and release identity contract. It is unpublished and requires an explicit migration/release decision. The completed **0.6.0** [release record](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.6.0) remains the evidence for the published application frame; do not republish it. Verified 0.5.0, 0.4.0 and 0.3.0 evidence remains dated history. UI v2 names a design generation, not an npm major. Future breaking changes require an explicit migration and version decision. Version-scoped installation is in the [README](../README.md#use-the-ui).
4
4
 
5
5
  ## Architecture
6
6
 
7
7
  One repository contains the shared package and the separate Next.js brand/example website. `@naeil/ui/ui` provides React primitives and generic Navigation/SiteFooter. The opt-in React-only `@naeil/ui/naeil-header` provides the complete actual naeil.dev branded header; see [its consumer contract](components/naeil-header.md). The legacy root is a framework compatibility entry with static Next/next-intl imports, even when selecting only Logo or a heading; React-only consumers use the documented shared deep modules. Next and next-intl are optional peers, not optional behavior inside the root. Supply them when importing that entry, Nav, Footer, or i18n/routing. Theme controls and Toaster use the framework-independent React library next-themes, retained as a runtime dependency.
8
8
 
9
+ Owned services use `@naeil/ui/naeil-footer` for the canonical localized destinations in full/compact variants; generic SiteFooter and legacy Footer retain their APIs. Footer navigation adapters preserve application save/flush decisions and modified-click behavior. `@naeil/ui/release` is server-safe metadata; it contains no application artifact, credential or environment. Applications compile their own allowlisted artifact/source identity. See [the footer contract](components/naeil-footer.md). The release coordinator remains disabled until its concrete policy, source mappings, immutable artifacts, deployment bridges and recovery targets are reviewed. Publishing a package, creating an update PR or merging it never establishes complete consumer rollout.
10
+
9
11
  Website tools remain development dependencies so maintainers can develop both products. npm tarball consumers install only component runtime dependencies and their host React/ReactDOM. Build entries, package exports and packed checks constrain the public boundary. There is no bundled website action, Supabase helper, Three/hero/cursor module, blog engine or full application message catalog. The opt-in header includes only its three header dictionaries and canonical project catalog. Its five decorative images reference official `https://naeil.dev/images/*.png` URLs and require network access; no image bytes are bundled, and unresolved artwork redistribution provenance remains in [third-party notices](../THIRD_PARTY_NOTICES.md).
10
12
 
11
13
  ## Checks
@@ -48,9 +50,13 @@ The explicit font-notice regression gate copies the real React fixture config in
48
50
 
49
51
  ## Publication and deployment
50
52
 
51
- ### Intended 0.5.0 release — pending
53
+ ### 0.6.0 release scope — 2026-10-16
54
+
55
+ The owner authorized publication and deployment of the shared 1600px frame, responsive gutters and navigation/footer adoption improvements. Use the exact reviewed source and frozen archive; record npm, GitHub Release, Pages and production results independently. Existing consumer applications need their own upgrade and composition migration. The minor increment marks the deliberate default-width change and added public frame tokens/class.
56
+
57
+ ### Verified 0.5.0 publication — 2026-10-15
52
58
 
53
- The owner authorized npm publication, reviewed main integration and naeil.dev deployment for the whole-header change. Authentication and actual execution are separate from authorization. At this documentation checkpoint no 0.5.0 registry version, tag/release, new hosted Docs, production site deployment or final archive identity is claimed. Freeze and verify the complete candidate before following the procedure below; record each external outcome independently.
59
+ Registry metadata and the [0.5.0 release](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.5.0) were rechecked on 2026-10-16. npm published at `2026-10-15T21:48:55.614Z`; the release points to `04229adbecac302efbf50ab2b8a3a40edb0a04bb`. Its archive SHA-256 is `8c9203192d967dc4fae65cc00ae80743244e0ae2363fee8c2c0edd9541d07cf9`. Production deployment7093004444 and Pages deployment7093190956 succeeded for that source; the release retains their detailed verification assets. Earlier pending-publication statements describe the preparation checkpoint, not current registry state.
54
60
 
55
61
  ### Verified 0.4.0 publication — 2026-10-11
56
62
 
@@ -80,7 +86,7 @@ The immutable npm archive's bundled guides are the release-preparation snapshot.
80
86
 
81
87
  ### Release procedure
82
88
 
83
- The deployed Storybook's component guide URL base uses the 0.3.0 publication-status documentation snapshot `04c5b8cce145a4c387763db6f28d29e62f7664c7`. Runtime/API source-authority links retain tested component snapshot `81fd395031dc5b20074c4d915a8585360ce2d28a`; those foundation links remain valid and were rechecked during 0.4.0 hosted verification. The README documentation index points to the maintained main-branch index. Verify targets at their respective revisions and preserve original sources, dated approval scope and runtime evidence. Freeze subsequent documentation changes separately from immutable release archives.
89
+ Storybook resolves relative Markdown guide links against the release's `v0.6.0` source tag. The tag must point to the reviewed release source, and hosted verification checks that guide links resolve. Historical foundation/source-authority links remain at their original revisions. Freeze subsequent documentation changes separately from immutable release archives.
84
90
 
85
91
  The authorized 0.3.0 release completed main merge, npm 0.3.0, a GitHub Release and hosted Docs as recorded above. The release maintainer performs external authentication and publication; documentation preparation does not itself execute those operations. The automatic verification workflow does not publish or deploy. Record native/manual observations with their actual scope and carry unrun checks as limitations; do not substitute automated WebKit/axe checks or publication authorization for human certification.
86
92
 
@@ -112,7 +118,7 @@ Run the command from this checkout after installing its dependencies. It serves
112
118
 
113
119
  ### Authorized GitHub Pages publication
114
120
 
115
- The public Docs destination [https://naeil-dev.github.io/naeil-ui/](https://naeil-dev.github.io/naeil-ui/) serves source `e8fe5afc13788a0cac0244b72e78975812f4a2ee` following the 2026-10-11 [Pages run 38114879574](https://github.com/naeil-dev/naeil-ui/actions/runs/38114879574). The [0.4.0 release](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.4.0) records deployed source and hosted HTTP/navigation checks; the 0.3.0 deployment above remains history. Pages uses `build_type=workflow` and a **github-pages** main-only deployment branch policy. See [Docs workflow status](https://github.com/naeil-dev/naeil-ui/actions/workflows/publish-docs-manual.yml) for subsequent deployments; preview artifact checks above establish local artifact behavior only.
121
+ The public Docs destination [https://naeil-dev.github.io/naeil-ui/](https://naeil-dev.github.io/naeil-ui/) last completed [Pages run38737502303](https://github.com/naeil-dev/naeil-ui/actions/runs/38737502303) for0.5.0 source `04229adbecac302efbf50ab2b8a3a40edb0a04bb`, rechecked2026-10-16. Subsequent deployments belong to their release records. Pages uses `build_type=workflow` and a **github-pages** main-only deployment branch policy. See [workflow status](https://github.com/naeil-dev/naeil-ui/actions/workflows/publish-docs-manual.yml).
116
122
 
117
123
  `.github/workflows/publish-docs-manual.yml` is an explicit `workflow_dispatch` recipe with no PR/push trigger. Pages is configured to use **GitHub Actions**; the **github-pages** environment permits deployment from main only. Run the authorized workflow from main with the exact reviewed source SHA; configuration alone does not establish a successful deployment. The workflow file does not enable Pages itself. A default-branch merge can separately invoke the brand site's existing Vercel integration; that production deployment and its asset/font provenance require separate handling.
118
124
 
@@ -123,7 +129,7 @@ Select **Publish reviewed UI docs (manual only)** in Actions (or use the command
123
129
  gh workflow run publish-docs-manual.yml -f reviewed_sha=FULL_REVIEWED_COMMIT_SHA -f confirmation=PUBLISH_REVIEWED_DOCS
124
130
  ```
125
131
 
126
- After a 0.5.0 deployment, verify the manager and iframe under `/naeil-ui/`, all 15 UI and 2 Brand Docs pages, their Usage examples and NaeilHeader JapaneseApplication, canonical artwork and official image references, Docs links, local fonts and exact LICENSE/THIRD_PARTY_NOTICES/font notices. Retain the deployment URL, source SHA and observed HTTP/navigation results. Hosted Storybook uses simulated data and requires no Supabase project, design API key or external font server. Only the reviewed Storybook directory is uploaded; website public assets stay excluded.
132
+ After a 0.6.0 deployment, verify the manager and iframe under `/naeil-ui/`, all 15 UI and 2 Brand Docs pages, their Usage examples and NaeilHeader JapaneseApplication, canonical artwork and official image references, Docs links, local fonts and exact LICENSE/THIRD_PARTY_NOTICES/font notices. Retain the deployment URL, source SHA and observed HTTP/navigation results. Hosted Storybook uses simulated data and requires no Supabase project, design API key or external font server. Only the reviewed Storybook directory is uploaded; website public assets stay excluded.
127
133
 
128
134
  Normal builds are network-independent after dependency installation. Vite collects notices for actual preview modules; checked-in manager notices conservatively cover named embedded packages and versions from Storybook 10.4.6's original source lock. `check-storybook` fails if a named embedded module lacks a full notice. Four vendored tiny modules have no embedded version in that lock/comments; their original npm notice source is explicitly marked, without an exact-version claim. The exact use-composed-ref@1.4.0 tarball/repository provides MIT metadata but no standalone notice; its metadata plus full declared terms are retained without inventing a year/holder. The client-only@0.0.1 React marker retains its exact metadata and the original React MIT notice. Other missing notices fail the build; no generic MIT fallback passes arbitrary packages.
129
135
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naeil/ui",
3
- "version": "0.5.0",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "sideEffects": [
@@ -137,12 +137,20 @@
137
137
  "./naeil-header": {
138
138
  "types": "./dist/components/naeil-header.d.ts",
139
139
  "import": "./dist/components/naeil-header.js"
140
+ },
141
+ "./naeil-footer": {
142
+ "types": "./dist/components/naeil-footer.d.ts",
143
+ "import": "./dist/components/naeil-footer.js"
144
+ },
145
+ "./release": {
146
+ "types": "./dist/lib/ui-release.d.ts",
147
+ "import": "./dist/lib/ui-release.js"
140
148
  }
141
149
  },
142
150
  "scripts": {
143
151
  "dev": "next dev",
144
152
  "build": "next build",
145
- "build:pkg": "pnpm check:brand && tsup && tsup --config tsup.deep.config.ts && tsx scripts/fix-deep-imports.ts && pnpm build:tokens",
153
+ "build:pkg": "pnpm build:release && pnpm check:brand && tsup && tsup --config tsup.deep.config.ts && tsx scripts/fix-deep-imports.ts && pnpm build:tokens && node scripts/build-release-entry.mjs",
146
154
  "start": "next start",
147
155
  "lint": "eslint",
148
156
  "test": "vitest run",
@@ -157,7 +165,10 @@
157
165
  "check:consumers": "tsx scripts/check-consumers.ts",
158
166
  "preview:storybook": "tsx scripts/serve-storybook.ts",
159
167
  "build:brand": "tsx scripts/build-brand.ts",
160
- "check:brand": "tsx scripts/build-brand.ts --check"
168
+ "check:brand": "tsx scripts/build-brand.ts --check",
169
+ "build:release": "node scripts/build-ui-release.mjs",
170
+ "rollout": "node scripts/rollout/rollout.mjs",
171
+ "test:rollout": "node --test scripts/rollout/*.test.mjs scripts/verify-ui-production.test.mjs"
161
172
  },
162
173
  "peerDependencies": {
163
174
  "next": "^15 || ^16",
@@ -234,7 +245,8 @@
234
245
  "docs/design/component-demand.md",
235
246
  "docs/design/public-ui-stage4-verification.md",
236
247
  "docs/design/public-ui-final-verification.md",
237
- "docs/design/public-ui-release-validation.md"
248
+ "docs/design/public-ui-release-validation.md",
249
+ "contracts/"
238
250
  ],
239
251
  "pnpm": {
240
252
  "onlyBuiltDependencies": [
@@ -13,9 +13,6 @@
13
13
  inset-inline: 0;
14
14
  width: 100%;
15
15
  }
16
- .naeil-header-frame {
17
- max-width: 80rem;
18
- }
19
16
  .naeil-header-controls {
20
17
  display: flex;
21
18
  align-items: center;
@@ -31,6 +28,41 @@
31
28
  height: var(--spacing-4-value);
32
29
  background: var(--border);
33
30
  }
31
+ .naeil-header-account-trigger {
32
+ display: inline-flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ flex: none;
36
+ width: var(--ui-touch-target);
37
+ height: var(--ui-touch-target);
38
+ padding: 0;
39
+ border: 0;
40
+ border-radius: var(--radius-md-value);
41
+ background: transparent;
42
+ color: var(--foreground);
43
+ cursor: pointer;
44
+ }
45
+ .naeil-header-account-trigger:hover,
46
+ .naeil-header-account-trigger[data-state="open"] {
47
+ background: var(--surface-subtle);
48
+ }
49
+ .naeil-header-account-avatar {
50
+ display: flex;
51
+ align-items: center;
52
+ justify-content: center;
53
+ width: var(--spacing-8-value);
54
+ height: var(--spacing-8-value);
55
+ border-radius: 50%;
56
+ background: var(--secondary);
57
+ color: var(--secondary-foreground);
58
+ }
59
+ .naeil-header-account-avatar svg {
60
+ width: var(--spacing-4-value);
61
+ height: var(--spacing-4-value);
62
+ }
63
+ .naeil-header-login {
64
+ font-weight: var(--font-weight-medium);
65
+ }
34
66
  .naeil-header-project-icon {
35
67
  display: flex;
36
68
  align-items: center;
@@ -40,11 +72,14 @@
40
72
  border: 1px solid;
41
73
  border-radius: var(--radius-lg-value);
42
74
  }
75
+ .ui-app-frame,
43
76
  .ui-navigation-frame,
44
77
  .ui-site-footer-frame {
78
+ box-sizing: border-box;
45
79
  width: 100%;
80
+ max-width: var(--ui-width-frame);
46
81
  margin-inline: auto;
47
- padding-inline: var(--spacing-6-value);
82
+ padding-inline: var(--ui-frame-gutter);
48
83
  }
49
84
  .ui-navigation-frame {
50
85
  container-type: inline-size;