@naeil/ui 0.11.0 → 0.13.0
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.
- package/CHANGELOG.md +38 -2
- package/DESIGN.md +13 -3
- package/README.md +13 -11
- package/THIRD_PARTY_NOTICES.md +4 -2
- package/dist/{chunk-KWEWR46R.js → chunk-5BXZPDHZ.js} +68 -8
- package/dist/{chunk-U3IZCFM4.js → chunk-A2DCQVTP.js} +1 -1
- package/dist/{chunk-KPE4KKYM.js → chunk-Y5LW3ADW.js} +24 -15
- package/dist/components/index.d.ts +3 -3
- package/dist/components/index.js +4 -4
- package/dist/components/naeil-footer.d.ts +2 -2
- package/dist/components/naeil-footer.js +1 -1
- package/dist/components/naeil-header.d.ts +23 -8
- package/dist/components/naeil-header.js +7 -5
- package/dist/components/ui/index.d.ts +22 -5
- package/dist/components/ui/index.js +181 -34
- package/dist/lib/ui-release.d.ts +1 -1
- package/dist/lib/ui-release.js +1 -1
- package/dist/lib/utils.js +1 -7
- package/dist/naeil-locale/checker.js +1 -1
- package/dist/naeil-locale/chrome.d.ts +25 -8
- package/dist/naeil-locale/chrome.js +91 -22
- package/dist/naeil-locale/{chunk-4U64K4J3.js → chunk-24IL53QO.js} +1 -1
- package/dist/naeil-locale/{chunk-U65OQHZY.js → chunk-WT6QXR7O.js} +14 -8
- package/dist/naeil-locale/client.js +45 -15
- package/dist/naeil-locale/index.js +1 -1
- package/dist/naeil-locale/messages.js +2 -2
- package/dist/naeil-locale/server.js +6 -6
- package/dist/{navigation-D8N1tMTu.d.ts → navigation-CXZapKac.d.ts} +3 -1
- package/dist/{site-footer-s113FZgC.d.ts → site-footer-C4jgkGDU.d.ts} +1 -1
- package/dist/source/components/naeil-header-core.d.ts +23 -8
- package/dist/source/components/naeil-header-core.js +66 -6
- package/dist/source/components/naeil-header.d.ts +6 -4
- package/dist/source/components/naeil-header.js +4 -2
- package/dist/source/components/typography.d.ts +1 -1
- package/dist/source/components/typography.js +1 -1
- package/dist/source/components/ui/button.js +7 -7
- package/dist/source/components/ui/card.js +1 -1
- package/dist/source/components/ui/dialog.d.ts +4 -2
- package/dist/source/components/ui/dialog.js +10 -6
- package/dist/source/components/ui/index.d.ts +1 -0
- package/dist/source/components/ui/index.js +22 -0
- package/dist/source/components/ui/navigation.d.ts +3 -1
- package/dist/source/components/ui/navigation.js +17 -8
- package/dist/source/components/ui/sheet.d.ts +20 -0
- package/dist/source/components/ui/sheet.js +176 -0
- package/dist/source/components/ui/sonner.js +2 -2
- package/dist/source/lib/ui-release.d.ts +1 -1
- package/dist/source/lib/ui-release.js +1 -1
- package/docs/components/README.md +4 -1
- package/docs/components/application-layout.md +27 -28
- package/docs/components/avatar.md +1 -1
- package/docs/components/badge.md +5 -1
- package/docs/components/button.md +9 -1
- package/docs/components/card.md +5 -1
- package/docs/components/checkbox.md +1 -1
- package/docs/components/common.md +22 -1
- package/docs/components/dialog.md +14 -4
- package/docs/components/dropdown-menu.md +1 -1
- package/docs/components/input.md +1 -1
- package/docs/components/naeil-footer.md +4 -2
- package/docs/components/naeil-header.md +41 -12
- package/docs/components/naeil-locale.md +36 -0
- package/docs/components/navigation.md +10 -4
- package/docs/components/select.md +1 -1
- package/docs/components/sheet.md +50 -0
- package/docs/components/sonner.md +7 -1
- package/docs/components/switch.md +1 -1
- package/docs/components/tabs.md +1 -1
- package/docs/components/textarea.md +1 -1
- package/docs/design/public-ui-support.md +3 -1
- package/docs/design/v2-migration.md +13 -7
- package/docs/package-release.md +24 -8
- package/package.json +11 -10
- package/src/styles/components.css +40 -2
- package/src/styles/globals.css +6 -2
- package/src/styles/theme.css +6 -0
- package/licenses/Nunito-Sans-OFL.txt +0 -93
- package/licenses/React-MIT.txt +0 -21
- package/licenses/Storybook-MIT.txt +0 -21
- package/licenses/popper-MIT.txt +0 -25
- package/licenses/store2-MIT.txt +0 -22
- package/licenses/toggle-selection-MIT.txt +0 -21
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# NaeilHeader — branded whole-header composition
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Product navigation and controlled mobile APIs are available since 0.8.0; shared root reservation is available since 0.9.0. See [release identities and publication status](../package-release.md#publication-and-deployment) for the current published release; hosted Docs and service activation have separate receipts.
|
|
4
4
|
|
|
5
5
|
```tsx
|
|
6
6
|
import { NaeilHeader, NaeilHeaderAccountControl } from '@naeil/ui/naeil-header';
|
|
@@ -26,6 +26,7 @@ Only provide `onLocaleChange` when the application's interface supports all thre
|
|
|
26
26
|
|
|
27
27
|
| Prop | Contract |
|
|
28
28
|
| --- | --- |
|
|
29
|
+
| `service` | Opt-in `NaeilService`: `abstorm`, `home`, `estimate`, `jev`; exported readonly `naeilServices` lists these ids. Owns lowercase suffix/name, local `/` brand default and product-only tabs. |
|
|
29
30
|
| `locale` | Required `en`, `ko` or `ja`; selects header-only copy. |
|
|
30
31
|
| `resolveHref` | Resolves canonical unlocalized paths; defaults to the official localized site. |
|
|
31
32
|
| `Link`, `currentHref`, `onNavigate` | Routing adapter, active destination and navigation interception inherited from Navigation. |
|
|
@@ -33,16 +34,45 @@ Only provide `onLocaleChange` when the application's interface supports all thre
|
|
|
33
34
|
| `authSlot` | Canonical `NaeilHeaderAccountControl`, with consumer-owned auth state/actions. Legacy arbitrary markup remains supported. |
|
|
34
35
|
| `brandHref`, `brandSlot`, `brandLinkProps`, `brandLinkComponent` | Explicit brand destination/content/anchor overrides; default accessible brand name is `.naeil`. |
|
|
35
36
|
| `projects`, `projectsExternal`, `showProjects`, `showBlog` | Legacy catalog/visibility/native-link overrides; defaults use the complete canonical catalog. |
|
|
36
|
-
| `appNavigation` (0.8.0) | `NavigationItem[]` passed unchanged after catalog/blog and before flat `subNav`. Owned
|
|
37
|
+
| `appNavigation` (0.8.0) | `NavigationItem[]` passed unchanged after catalog/blog and before flat `subNav`. Owned services set `service` and supply only their own tabs. |
|
|
37
38
|
| `brandSuffix` (0.8.0) | Product qualifier inside the brand link; the package owns its 14px type, 4px gap and optical alignment. Ignored when `brandSlot` replaces the complete content. Set `brandLinkProps["aria-label"]` for a product name. |
|
|
38
39
|
| `statusSlot` (0.8.0) | Exactly once, outside and 8px after the brand link at every width. The consumer owns the content and accessible status. No wrapper is added when omitted. |
|
|
39
|
-
| `mobileOpen`, `onMobileOpenChange` (0.8.0) | Controlled/uncontrolled sheet state, also on generic Navigation. Omit `mobileOpen` for internal state; a callback alone observes it. Accepted transitions notify once. In controlled mode callbacks request a change against the committed prop, so another close request is reported if the parent rejects or delays the previous one; an external prop update emits no request. Route changes, ordinary links, close/overlay/Escape dismiss. Desktop crossing dismisses when the desktop navigation gains width; an empty menu retains B1's open sheet until Escape/close/overlay/route change. Modified/middle clicks preserve it; nested menus consume the first Escape. |
|
|
40
|
+
| `mobileOpen`, `onMobileOpenChange` (0.8.0) | Controlled/uncontrolled sheet state, also on generic Navigation. Omit `mobileOpen` for internal state; a callback alone observes it. Accepted transitions notify once. In controlled mode callbacks request a change against the committed prop, so another close request is reported if the parent rejects or delays the previous one; an external prop update emits no request. Route changes, ordinary links, close/overlay/Escape dismiss. Desktop crossing dismisses when the desktop navigation gains width; without `service`, an empty menu retains B1's open sheet until Escape/close/overlay/route change. Modified/middle clicks preserve it; nested menus consume the first Escape. |
|
|
40
41
|
| `subNav`, `currentProjectKey`, `currentProjectHref` | Legacy extra links and current-project destination. |
|
|
41
42
|
| `translations`, `labels` | Legacy header/project lookup overrides and navigation/menu/close accessible labels. |
|
|
42
43
|
| `toolbarSlot` | Replaces the complete default theme/locale/auth toolbar. |
|
|
43
44
|
| `mobileFooter`, `className`, `containerClassName` | Inherited mobile slot and style overrides; recheck frame/behavior after changes. |
|
|
44
45
|
|
|
45
|
-
Standard header attributes and
|
|
46
|
+
Standard header attributes and appropriate inherited [Navigation props](navigation.md) remain available. Omitting `service` preserves all legacy overrides and output.
|
|
47
|
+
|
|
48
|
+
## Owned-service profiles
|
|
49
|
+
|
|
50
|
+
| Profile | Left brand | Center | Brand default |
|
|
51
|
+
| --- | --- | --- | --- |
|
|
52
|
+
| naeil.dev (no `service`) | Logo + `.naeil` | Projects / Blog | Official localized site |
|
|
53
|
+
| `service="abstorm"` | Logo + `.naeil` + `abstorm` | Service's own tabs | `/` |
|
|
54
|
+
| `service="home"` | Logo + `.naeil` + `home` | Service's own tabs | `/` |
|
|
55
|
+
| `service="estimate"` | Logo + `.naeil` + `estimate` | Service's own flat/grouped tabs | `/` |
|
|
56
|
+
| `service="jev"` | Logo + `.naeil` + `jev` | Empty for this single-screen service | `/` |
|
|
57
|
+
|
|
58
|
+
The accessible brand name is `.naeil <id>`. `brandHref` can override the local destination. No status dot or extra brand indicator is allowed. The DS fixes tab shape, position, size, spacing and all interaction states. Theme / locale / account retain the canonical presentation; the app supplies routing/guards, locale and shared account state.
|
|
59
|
+
|
|
60
|
+
`NaeilHeaderProps` remains an extensible legacy interface with `service?: undefined`; `NaeilServiceHeaderProps` is the strict service type. Both are exported from the standalone and provider chrome entries. The component overloads accept the strict service type first and the legacy interface last, so `ComponentProps<typeof NaeilHeader>` remains `NaeilHeaderProps` for existing wrappers. Type service props explicitly as `NaeilServiceHeaderProps`.
|
|
61
|
+
|
|
62
|
+
The `service` discriminated branch rejects `brandSuffix`, `statusSlot`, `brandSlot`, `toolbarSlot`, `subNav`, `brandLinkComponent`, `projects`, `projectsExternal`, `showProjects`, `showBlog`, `translations`, `className` and `containerClassName`. It also rejects inline `style`, `brandLinkProps`, `mobileFooter` and the inherited empty-navigation policy override. JavaScript/cast attempts are ignored, with one warning per prop name in development and none in production. Root `data-slot`, `data-global-header` and `data-naeil-*` markers cannot be replaced. Root attributes such as `id`, `aria-*` and `dir`, plus the consumer `Link` and `authSlot` markup, remain consumer-owned and must not be used to restyle shared chrome. Labels, currentHref/onNavigate, brandHref, appNavigation, locale callbacks and controlled mobile state remain available. Unknown, empty or null runtime service values fall back to the legacy profile without a `service` attribute or stripped legacy props, with one development-only warning.
|
|
63
|
+
|
|
64
|
+
`statusSlot`, `brandSuffix`, `brandSlot`, `toolbarSlot`, `subNav` and `brandLinkComponent` are deprecated for owned services and retained for legacy compatibility. They remain functional without `service`.
|
|
65
|
+
|
|
66
|
+
With no `appNavigation`, the desktop center stays empty and the toolbar remains right-aligned. The mobile menu button stays available; its sheet contains the toolbar without an empty navigation landmark/list. Desktop crossing restores focus to a visible toolbar control when the center has no links/buttons. Resizing to desktop dismisses a service sheet by observing the desktop toolbar, including an empty-center profile. Legacy empty-menu headers retain the B1 resize exception described below.
|
|
67
|
+
|
|
68
|
+
## Standalone theme and locale controls
|
|
69
|
+
|
|
70
|
+
`NaeilHeaderThemeControl` and `NaeilHeaderLocaleControl` are public exports from `@naeil/ui/naeil-header` and `@naeil/ui/naeil-locale/chrome`. The latter uses the shared provider’s selected messages; the standalone entry supplies its own common dictionaries. Prefer the complete header’s default toolbar.
|
|
71
|
+
|
|
72
|
+
- `NaeilHeaderThemeControl({ locale })` accepts `en | ko | ja`, reads the consumer’s next-themes provider and toggles its resolved light/dark theme. The localized 44px icon button is disabled until mount.
|
|
73
|
+
- `NaeilHeaderLocaleControl({ locale, onLocaleChange })` requires the same locale union and a `(locale) => void` callback. It renders the shared three-language Select; routing, persistence and supported application translations belong to the consumer.
|
|
74
|
+
|
|
75
|
+
See [the locale runtime](naeil-locale.md) before using provider-backed chrome in an owned Next service.
|
|
46
76
|
|
|
47
77
|
## Account presentation
|
|
48
78
|
|
|
@@ -67,7 +97,7 @@ The fixed header is 65px: the current 64px navigation token plus a 1px border. C
|
|
|
67
97
|
|
|
68
98
|
The 0.7.2 default catalog contains naeil-ui and references only `https://naeil.dev/images/whale.png`. Rendering that decorative image requires network access to the official origin. Its bytes are not redistributed in npm; [third-party notices](../../THIRD_PARTY_NOTICES.md) retain unresolved artwork provenance and redistribution limits. Brand marks are not relicensed by the repository MIT license. Captions and links remain usable when images fail.
|
|
69
99
|
|
|
70
|
-
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. Storybook provides **Brand / NaeilHeader / Docs, Usage, JapaneseApplication, AccountStates, ReferenceFull, ReferenceCompact**; the Japanese example omits unsupported locale switching and supplies application state to the shared account control. Local examples do not establish hosted deployment.
|
|
100
|
+
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. Storybook provides **Brand / NaeilHeader / Docs, Usage, JapaneseApplication, AccountStates, Abstorm, Home, Estimate, Jev, ReferenceFull, ReferenceCompact**; the Japanese example omits unsupported locale switching and supplies application state to the shared account control. Local examples do not establish hosted deployment.
|
|
71
101
|
|
|
72
102
|
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).
|
|
73
103
|
|
|
@@ -82,20 +112,19 @@ Marker-and-language-scoped final typography uses a package-local font stack and
|
|
|
82
112
|
|
|
83
113
|
A controlled mobile sheet defers its shared account action until the account menu and sheet finish closing and restore a surviving header control. The consumer still owns dirty state, confirmation, logout, busy state and the request lock; `onLogout` must tolerate this asynchronous handoff. When a confirmation saves its opener, its restoration policy must also handle a viewport change hiding that opener. Verify normal and reduced motion, cancellation after a desktop transition, pending requests, reopen and retry in the actual application; package verification does not replace actual product acceptance.
|
|
84
114
|
|
|
85
|
-
|
|
115
|
+
Without `service`, the empty-menu desktop exception is intentional B1 compatibility: a zero-width desktop navigation cannot signal the crossing, so the sheet stays open. Escape, its close button, the overlay or a `currentHref` change still close it. Home owns the confirmation's desktop cancel fallback to the visible row account trigger; the package supplies a visible, focusable control and does not implement the confirmation's restoration policy.
|
|
86
116
|
|
|
87
117
|
```tsx
|
|
88
|
-
<NaeilHeader locale={locale} currentHref={pathname} Link={GuardedLink}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
statusSlot={readinessStatus} mobileOpen={mobileOpen} onMobileOpenChange={setMobileOpen}
|
|
118
|
+
<NaeilHeader service="home" locale={locale} currentHref={pathname} Link={GuardedLink}
|
|
119
|
+
appNavigation={navigationItems}
|
|
120
|
+
mobileOpen={mobileOpen} onMobileOpenChange={setMobileOpen}
|
|
92
121
|
onLocaleChange={changeLanguage}
|
|
93
122
|
authSlot={<NaeilHeaderAccountControl locale={locale} account={account} />} />
|
|
94
123
|
```
|
|
95
124
|
|
|
96
|
-
Keep the
|
|
125
|
+
Keep the shared theme/locale/separator/account toolbar; the service profile rejects toolbar replacement. Omitting all new props preserves the 0.7.2 canonical profile, apart from markers, language correction, release identity and Radix-generated IDs. SVG/Logo IDs and consumer-supplied IDs are not normalized away. See the `docs/superpowers/specs/2026-10-28-canonical-home-chrome.md` acceptance contract for gates and the four allowed Home differences.
|
|
97
126
|
|
|
98
|
-
## Page-root frame policy (0.9.0
|
|
127
|
+
## Page-root frame policy (since 0.9.0)
|
|
99
128
|
|
|
100
129
|
Both supported CSS paths obtain the stable root rule and scoped Radix duplicate-compensation correction from `components.css`. Theme-only and JS-only imports do not set document scrolling. Declare `<html data-naeil-scrollbar-gutter="auto">` before first paint to disable both pieces for a custom policy. See [application layout](application-layout.md) for custom-body/scroller/helper-class limits, fallback and the [adopted contract](https://github.com/naeil-dev/naeil-ui/blob/434b7d07235316097ca3a55265ee02c1422b0cfd/docs/superpowers/specs/2026-10-29-page-root-scrollbar-gutter.md) for required probes and capture ordering.
|
|
101
130
|
|
|
@@ -35,6 +35,8 @@ Use `createNaeilRequestConfig({namespace: "estimate", messages: {en: () => impor
|
|
|
35
35
|
|
|
36
36
|
Render complete paths with `localePath` for same-service navigation and `localeHref` for owned service links. Pass those paths to base Next Link/router or anchors without another locale option. The controller performs `router.replace(href, {scroll: false})`, serializes requests and waits for the matching provider arrival. It restores a stable `data-naeil-focus-id`, input `name`, or `id`. Only a successful explicit selection may write preference; history, prefetch and direct visits do not. Storage failure cannot block a path change.
|
|
37
37
|
|
|
38
|
+
Compatibility note: timeout releases the pending lock but retains the failed intent so a matching late provider arrival clears the error and applies the normal preference-write opt-in. The full destination (including query and fragment) must match. Cancel, history navigation, departure to another logical route, or a newer selection discards that late-arrival eligibility. `retry()` now uses the latest failed request, including unsupported-route failures and destination options; if the URL already has the requested locale, it clears the error and returns `false` without starting another navigation. A URL change alone never writes preference: a matching provider must commit.
|
|
39
|
+
|
|
38
40
|
The canonical chrome can be imported from `/naeil-locale/chrome` under the shared provider. Existing `/naeil-header` and `/naeil-footer` remain standalone compatibility adapters and include the small three-language common dictionary. Consumer Link, auth, save guards, frame overrides, desktop/mobile account locks and project data remain consumer-owned.
|
|
39
41
|
|
|
40
42
|
## AB Storm registration (0.11.0 candidate)
|
|
@@ -47,6 +49,40 @@ The inventory was checked against AB Storm source `087e67239db26506a73c51fde7a6d
|
|
|
47
49
|
|
|
48
50
|
The proxy runs exact existing protocol boundaries first, strips external private markers, strictly classifies UI paths, applies the existing app authorizer, and then runs next-intl. Protected entries without an authorizer fail closed. A marker is only a rendering hint: every protected server data read must independently authorize. RSC denial renders a valid localized access boundary and retains the root draft; it must not send login HTML or redirect an in-progress editor to another document. Keep the root beforeunload guard active during RSC failure and access recovery.
|
|
49
51
|
|
|
52
|
+
Compatibility note: a protocol hook returning `NextResponse.next({request: {headers}})` or `NextResponse.rewrite(url, {request: {headers}})` now preserves the complete supplied request header set, including deletions and replacements. Internal locale/access markers are still removed. Plain `NextResponse.next()` without request overrides retains the sanitized incoming headers.
|
|
53
|
+
|
|
50
54
|
`localePath` is not an auth-return validator. Keep existing exact return/invite/callback/relay origin and envelope validation. Protocol paths stay outside `[locale]`; localized protocol aliases are rejected. Public metadata advertises only available translations. Protected/auth/error UI is noindex without SEO alternates.
|
|
51
55
|
|
|
56
|
+
Compatibility note: literal backslashes in UI query strings and fragments are preserved by `resolveLocaleUrl` and `localePath`; backslashes in the pathname remain invalid. Encoded locale and protocol-prefix segments are rejected using the registered locale and protocol inventories, including consumer `protocolPrefixes`. This also applies to dynamic UI segments; use the literal spelling of reserved segments.
|
|
57
|
+
|
|
58
|
+
## Proxy matcher and public files
|
|
59
|
+
|
|
60
|
+
The proxy passes these unlocalized prefixes (exact path or descendants) through without locale rewriting: `/api`, `/auth`, `/_next`, `/_vercel`, `/.well-known`, `/health`, `/invite`, `/return`, `/webhook`, `/images`, `/fonts`, plus the service's `protocolPrefixes`. Exact registered `uiProtocolExceptions`, such as Estimate's `/auth/complete`, remain UI routes. The built-in exact public files are `/favicon.ico`, `/favicon.svg`, `/icon.svg`, `/apple-icon.png`, `/robots.txt` and `/sitemap.xml`. Compatibility note: `/favicon.svg` is now included so Estimate's error-document favicon passes through the same proxy that emitted it.
|
|
61
|
+
|
|
62
|
+
Other public files, including manifests, Open Graph images and extra icons, must be excluded by the consumer's matcher or explicitly passed by its protocol hook or service `protocolPrefixes`. Unknown paths are otherwise rejected with 404, even when they contain a file extension. A protocol hook runs before classification; keep its allowlist exact and preserve existing auth/invite/return checks.
|
|
63
|
+
|
|
64
|
+
The site uses the following catch-all matcher and passes its additional public files in the protocol hook. This is the recommended starting point when existing security checks must run on every request:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
// proxy.ts — retain existing protocol/security checks before this asset branch.
|
|
68
|
+
import { NextResponse, type NextRequest } from "next/server";
|
|
69
|
+
import { createNaeilLocaleProxy } from "@naeil/ui/naeil-locale/server";
|
|
70
|
+
|
|
71
|
+
async function protocol(request: NextRequest) {
|
|
72
|
+
const path = new URL(request.url).pathname;
|
|
73
|
+
// App-owned examples; replace these with the application's actual public files.
|
|
74
|
+
if (path.startsWith("/svg/") || ["/manifest.webmanifest", "/og.png"].includes(path)) {
|
|
75
|
+
return NextResponse.next();
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default createNaeilLocaleProxy({ service: "main", protocol /*, authorize: existingAuthorizer */ });
|
|
81
|
+
export const config = { matcher: ["/:path*"] };
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Keep the existing authorizer when integrating this example. If the matcher excludes assets instead, those requests bypass both the locale proxy and its protocol hook; exclude only paths that need neither. Passing a path through does not create or serve the file: the consumer still owns its static asset or handler.
|
|
85
|
+
|
|
86
|
+
## Activation
|
|
87
|
+
|
|
52
88
|
Receiver deployment and sending are separate gates. `preferenceWritesEnabled` defaults to false. Before first exposure, validate a separate receiver-compatible fallback or the previous build's safe rejection of new paths. After all required receiver and auth receipts pass, enable the reviewed cross-service links and explicit preference writes. Keep package, source, hosted Docs, app identities, activation times and rollback receipts separate. Home and Baby are outside this migration.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Navigation and SiteFooter
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
See [release identities and publication status](../package-release.md#publication-and-deployment) for the current published release. 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
|
|
|
@@ -36,19 +36,25 @@ These are composition snippets: `pathname`, controls, brand and `guardedNavigate
|
|
|
36
36
|
|
|
37
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.
|
|
38
38
|
|
|
39
|
+
`mobileOpen?: boolean` controls the mobile sheet; omit it for internal state. `onMobileOpenChange?: (open: boolean) => void` observes internal changes or requests controlled changes. External prop updates emit no request; a parent that delays or rejects closure can receive another close request. Modified/middle clicks preserve the sheet. Desktop dismissal depends on the desktop navigation gaining width; an empty menu retains the open sheet until close, overlay, Escape or route change.
|
|
40
|
+
|
|
41
|
+
`omitEmptyNavigation?: boolean` opts into omitting empty navigation landmarks and dismissing toolbar-only sheets on desktop crossing. Its default `false` preserves B1 empty-menu behavior.
|
|
42
|
+
|
|
43
|
+
`NavigationSheetAction` is a public React context exported only from the deep entry `@naeil/ui/components/ui/navigation`. Its value is `undefined` outside a controlled mobile toolbar. Within that toolbar, calling the context function with `action: () => void` returns `{ menuClosed: () => void, cancel: () => void }`. Call `menuClosed()` after the nested menu releases focus to request sheet closure; the action waits for both layers and focus handoff. `cancel()` cancels the queued action. Reopening, another dismissal or unmounting also cancels it. The shared account control already uses this coordination; ordinary navigation links need no context integration. See [the source](https://github.com/naeil-dev/naeil-ui/blob/main/src/components/ui/navigation.tsx).
|
|
44
|
+
|
|
39
45
|
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.
|
|
40
46
|
|
|
41
47
|
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.
|
|
42
48
|
|
|
43
|
-
`SiteFooter` supports `brand`, `description`, `groups: [{ id, label, links }]`, `meta`, children, `Link`, `containerClassName`, `variant="full|compact"` and `onNavigate(event, item)` (0.7.
|
|
49
|
+
`SiteFooter` supports `brand`, `description`, `groups: [{ id, label, links }]`, `meta`, children, `Link`, `containerClassName`, `variant="full|compact"` and `onNavigate(event, item)` (available since 0.7.1, 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.
|
|
44
50
|
|
|
45
51
|
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.
|
|
46
52
|
|
|
47
53
|
## Compatibility
|
|
48
54
|
|
|
49
|
-
Menu groups accept `columns?: 1 | 2` (default 1). The
|
|
55
|
+
Menu groups accept `columns?: 1 | 2` (default 1). The 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.
|
|
50
56
|
|
|
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
|
|
57
|
+
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 default inventory; the fallback is the single-project naeil-ui catalog from [the shared catalog source](https://github.com/naeil-dev/naeil-ui/blob/main/src/components/naeil-header-data.ts), available since 0.7.2. 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.
|
|
52
58
|
|
|
53
59
|
`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.
|
|
54
60
|
|
|
@@ -10,7 +10,7 @@ Select/Value/Group alias Radix parts. Root: `value`/`defaultValue`/`onValueChang
|
|
|
10
10
|
|
|
11
11
|
Inherited [Select 2.2.6 declaration](https://unpkg.com/@radix-ui/react-select@2.2.6/dist/index.d.ts).
|
|
12
12
|
|
|
13
|
-
The [shared usage contract](common.md) covers setup, inherited/native prop typing, themes, density, font delivery and overrides. [Wrapper source](https://github.com/naeil-dev/naeil-ui/blob/
|
|
13
|
+
The [shared usage contract](common.md) covers setup, inherited/native prop typing, themes, density, font delivery and overrides. [Wrapper source](https://github.com/naeil-dev/naeil-ui/blob/main/src/components/ui/select.tsx) is the API authority.
|
|
14
14
|
|
|
15
15
|
## Composition
|
|
16
16
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Sheet
|
|
2
|
+
|
|
3
|
+
Use Sheet for supporting detail or evidence that belongs at the edge of the current task. AB Storm's repeated 480px evidence panel is the demonstrated composition need. Prefer an inline panel for ordinary editing and [Dialog](dialog.md) for a centered interruption. Available since 0.12.0. See [release identities and publication status](../package-release.md#publication-and-deployment) for the current published release.
|
|
4
|
+
|
|
5
|
+
## API and wrapper defaults
|
|
6
|
+
|
|
7
|
+
Exports: `Sheet`, `SheetTrigger`, `SheetClose`, `SheetPortal`, `SheetOverlay`, `SheetContent`, `SheetHeader`, `SheetFooter`, `SheetTitle`, `SheetDescription`.
|
|
8
|
+
|
|
9
|
+
Root forwards Radix `open`/`defaultOpen`/`onOpenChange`/`modal`; wrapper adds no root defaults. Trigger/Close accept primitive button props including `asChild`. Content forwards primitive props, refs and focus/outside/Escape handlers and creates its own Portal and Overlay. Content adds:
|
|
10
|
+
|
|
11
|
+
| Prop | Default | Behavior |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| `side` | `"right"` | `"right"`, `"left"`, `"top"` or `"bottom"`; exposed as `data-side` |
|
|
14
|
+
| `showCloseButton` | `true` | Shows the built-in X close button |
|
|
15
|
+
| `closeLabel` | `"Close"` | Screen-reader name of the built-in X; consumer supplies the UI language |
|
|
16
|
+
|
|
17
|
+
Right/left occupy the full viewport height and `min(100%, var(--ui-width-short-form))` width (480px default). Top/bottom occupy the full width, grow with content and stop at `100dvh`. All sides scroll internally. Raised surfaces, strong edge borders, inner-edge panel rounding and token padding (24px comfortable, 20px compact) follow the shared theme. `className` overrides the defaults. Content uses shared 120ms opacity motion and respects reduced motion. The X is 40px, at least 44px on small screens/coarse pointers.
|
|
18
|
+
|
|
19
|
+
Header/Footer are divs; Footer has no implicit action or close label. Title/Description wrap Radix semantic elements. Content does not expose a portal `container` prop; the separately exported SheetPortal is for a custom composition.
|
|
20
|
+
|
|
21
|
+
Inherited [Dialog 1.1.15 declaration](https://unpkg.com/@radix-ui/react-dialog@1.1.15/dist/index.d.ts). The [shared usage contract](common.md) covers setup, inherited/native prop typing, themes, density, font delivery and overrides. The wrapper source `src/components/ui/sheet.tsx` is the API authority.
|
|
22
|
+
|
|
23
|
+
## Composition
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
<Sheet>
|
|
27
|
+
<SheetTrigger asChild><Button type="button">근거 보기</Button></SheetTrigger>
|
|
28
|
+
<SheetContent closeLabel="닫기" lang="ko">
|
|
29
|
+
<SheetHeader>
|
|
30
|
+
<SheetTitle>근거</SheetTitle>
|
|
31
|
+
<SheetDescription>보고서에 사용한 자료를 확인합니다.</SheetDescription>
|
|
32
|
+
</SheetHeader>
|
|
33
|
+
<p>소비자가 제공하는 근거와 출처</p>
|
|
34
|
+
</SheetContent>
|
|
35
|
+
</Sheet>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Import the named components from `@naeil/ui/ui` or `@naeil/ui/components/ui/sheet` (Button from `/ui`). Variables/handlers and evidence data belong to consumers. Run **UI / Sheet / Usage**, **LocalizedClose** and **Sides** in Storybook; its Docs page renders this same guide. For a visible footer close, set `showCloseButton={false}` and compose `<SheetFooter><SheetClose asChild><Button>닫기</Button></SheetClose></SheetFooter>`.
|
|
39
|
+
|
|
40
|
+
## Keyboard, focus and accessible content
|
|
41
|
+
|
|
42
|
+
With Radix's modal defaults, opening moves focus inside; Tab/Shift+Tab stay inside, Escape dismisses, and focus returns to Trigger. Preserve default focus handlers unless you supply an equivalent destination. Always provide SheetTitle and a relevant SheetDescription; use `aria-describedby={undefined}` only when intentionally omitting a description. A triggerless controlled sheet requires a consumer focus-return destination. Portals inherit document-level theme/density; set the content language explicitly when needed.
|
|
43
|
+
|
|
44
|
+
## States, resilience and mistakes
|
|
45
|
+
|
|
46
|
+
Disabled applies to triggers/actions; loading/error/empty are consumer-owned content states. Keep failed input and retry actions inside the sheet. Long evidence scrolls internally; wrap long URLs and metadata rather than widening the page. Choose one close affordance: the built-in X, or an explicit SheetClose with the X disabled. Never remove every close action.
|
|
47
|
+
|
|
48
|
+
Localize `closeLabel`: Korean `닫기`, Japanese `閉じる`, English `Close`. Never leave English defaults in Korean or Japanese UI. SheetFooter has no implicit English button. Avoid casually nesting modal roots or preventing Escape without an accessible exit; consumer outside-dismissal/focus overrides need keyboard review.
|
|
49
|
+
|
|
50
|
+
Check light/dark, comfortable/compact, 320/390px mobile and long Korean, English and Japanese content. Follow the [shared override and acceptance guidance](common.md#styling-themes-and-overrides); automated keyboard/axe checks do not replace assistive-technology acceptance.
|
|
@@ -10,7 +10,7 @@ Accepts Sonner `ToasterProps`. Wrapper defaults: theme from next-themes (falls b
|
|
|
10
10
|
|
|
11
11
|
Inherited [Sonner 2.0.7 declarations](https://unpkg.com/sonner@2.0.7/dist/index.d.ts). Installed Sonner implements polite notifications and Alt+T as its default focus hotkey; these are primitive behaviors, not new wrapper defaults.
|
|
12
12
|
|
|
13
|
-
The [shared usage contract](common.md) covers setup, inherited/native prop typing, themes, density, font delivery and overrides. [Wrapper source](https://github.com/naeil-dev/naeil-ui/blob/
|
|
13
|
+
The [shared usage contract](common.md) covers setup, inherited/native prop typing, themes, density, font delivery and overrides. [Wrapper source](https://github.com/naeil-dev/naeil-ui/blob/main/src/components/ui/sonner.tsx) is the API authority.
|
|
14
14
|
|
|
15
15
|
## Composition
|
|
16
16
|
|
|
@@ -35,3 +35,9 @@ Sonner creates its notification region; meaningful text should convey status wit
|
|
|
35
35
|
Demonstrate success/info/warning/error, loading updated by the same id, and an action. Toaster has no disabled/loading prop; those belong to toast calls and initiating controls. With no notifications it renders no message. Keep long multilingual text wrap-safe, use mobileOffset deliberately, avoid duplicate toasters and move persistent errors/retry to the page. Custom style/icons/animations need contrast and reduced-motion verification.
|
|
36
36
|
|
|
37
37
|
Check this example in light/dark, comfortable/compact and mobile, including long Korean, English and Japanese text. Consumer overrides remain supported; follow the [shared override and acceptance guidance](common.md#styling-themes-and-overrides). Actual engine results and manual limits are in the [support matrix](../design/public-ui-support.md).
|
|
38
|
+
|
|
39
|
+
## Touch target compatibility (2026-11-12)
|
|
40
|
+
|
|
41
|
+
Styled toast dismiss and action/cancel controls now have at least 44px pointer targets. Pseudo-elements preserve the existing visible 20px dismiss and 24px action heights; action/cancel width is at least 44px. The close target extends inward from the toast corner to stay inside mobile viewport offsets. This can add a few pixels to very short action labels. Keep space between actions, and recheck target overlap with custom toast content, offsets, stacking or styles. Unstyled/custom toast rendering owns its target sizing.
|
|
42
|
+
|
|
43
|
+
Toaster also honors next-themes `forcedTheme` before its configured/system theme, keeping the dismiss icon legible when a preview or consumer forces dark mode. Explicit consumer `theme` still overrides this default.
|
|
@@ -8,7 +8,7 @@ Export: `Switch`. Forwards Radix Root props: `checked`/`defaultChecked`/`onCheck
|
|
|
8
8
|
|
|
9
9
|
Inherited [Switch 1.2.6 declaration](https://unpkg.com/@radix-ui/react-switch@1.2.6/dist/index.d.ts).
|
|
10
10
|
|
|
11
|
-
The [shared usage contract](common.md) covers setup, inherited/native prop typing, themes, density, font delivery and overrides. [Wrapper source](https://github.com/naeil-dev/naeil-ui/blob/
|
|
11
|
+
The [shared usage contract](common.md) covers setup, inherited/native prop typing, themes, density, font delivery and overrides. [Wrapper source](https://github.com/naeil-dev/naeil-ui/blob/main/src/components/ui/switch.tsx) is the API authority.
|
|
12
12
|
|
|
13
13
|
## Composition
|
|
14
14
|
|
package/docs/components/tabs.md
CHANGED
|
@@ -10,7 +10,7 @@ The wrappers set only slots/classes. Installed [Radix Tabs 1.1.13 declarations](
|
|
|
10
10
|
|
|
11
11
|
`forceMount` retains children and makes inactive panels present too. Consumers must explicitly hide inactive content, for example `hidden={value !== 'draft'}`, so it cannot receive focus or appear as a second visible panel. Root has no group-wide `disabled` prop; disable individual triggers. Keep matching values, generated IDs/roles and focus handlers intact.
|
|
12
12
|
|
|
13
|
-
The [shared usage contract](common.md) covers setup, inherited/native prop typing, themes, density, font delivery and overrides. [Wrapper source](https://github.com/naeil-dev/naeil-ui/blob/
|
|
13
|
+
The [shared usage contract](common.md) covers setup, inherited/native prop typing, themes, density, font delivery and overrides. [Wrapper source](https://github.com/naeil-dev/naeil-ui/blob/main/src/components/ui/tabs.tsx) is the API authority.
|
|
14
14
|
|
|
15
15
|
## Composition
|
|
16
16
|
|
|
@@ -8,7 +8,7 @@ Export: `Textarea`. Accepts `React.ComponentProps<"textarea">`, including React
|
|
|
8
8
|
|
|
9
9
|
The wrapper sets only slot/classes; **omitted `rows` retains the native two-row default**. It defaults to vertical resizing, full available width, 16px text, 25px line height and 8px vertical padding. Root density supplies the existing 40/36px minimum, raised to at least 44px on mobile/coarse pointers; rows and text determine the actual multiline height. It has no fixed control height or content autosizing. Consumer `rows`, resizing classes, padding and styles remain available. No label, error, value, validation or disabled default is invented.
|
|
10
10
|
|
|
11
|
-
The [shared usage contract](common.md) covers setup, inherited/native prop typing, themes, density, font delivery and overrides. [Wrapper source](https://github.com/naeil-dev/naeil-ui/blob/
|
|
11
|
+
The [shared usage contract](common.md) covers setup, inherited/native prop typing, themes, density, font delivery and overrides. [Wrapper source](https://github.com/naeil-dev/naeil-ui/blob/main/src/components/ui/textarea.tsx) is the API authority. Native props are defined by the installed React 19 declarations and HTML textarea behavior.
|
|
12
12
|
|
|
13
13
|
## Composition
|
|
14
14
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Public UI support and manual acceptance
|
|
2
2
|
|
|
3
|
-
This support matrix targets published `@naeil/ui@0.4.0` (2026-10-11); the [release](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.4.0) and [publication report](https://github.com/naeil-dev/naeil-ui/blob/main/docs/design/naeil-brand-0.4.0-publication.md) identify its source, npm archive, independent brand 1.1.1 and deployed Docs/site.
|
|
3
|
+
This support matrix targets published `@naeil/ui@0.4.0` (2026-10-11); the [release](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.4.0) and [publication report](https://github.com/naeil-dev/naeil-ui/blob/main/docs/design/naeil-brand-0.4.0-publication.md) identify its source, npm archive, independent brand 1.1.1 and deployed Docs/site. That release’s documentation covered 13 component families plus Brand / Logo; the [maintained component index](../components/README.md) describes the repository API surface. Coverage describes the checked examples and dependency versions; native/manual acceptance remains open.
|
|
4
|
+
|
|
5
|
+
The [owned-service language runtime](../components/naeil-locale.md) documents `/naeil-locale`, `/client`, `/server`, `/messages`, `/checker` and `/chrome`. Owned Next services use provider-backed chrome with exact `next-intl@4.14.8`; standalone React header/footer adapters remain available. These entries have their own release and consumer receipts; the historical foundation matrix below does not certify their routing, authentication or production adoption.
|
|
4
6
|
|
|
5
7
|
## 0.4.0 publication coverage
|
|
6
8
|
|
|
@@ -2,21 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
이 안내는 `@naeil/ui`의 기본 모양과 재사용 규칙을 설명한다. 패키지 소비와 소비 사이트 배포는 별도 작업이다.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Home API는 0.8.0부터, 공통 root 예약 기본값은 0.9.0부터 제공한다. 현재 게시 버전과 설치 명령은 [README](../../README.md#use-the-ui), 릴리스·hosted Docs·서비스별 기록은 [릴리스 정책](../package-release.md#publication-and-deployment)을 확인한다.
|
|
6
|
+
|
|
7
|
+
소유한 Next 서비스는 [공통 언어 런타임](../components/naeil-locale.md)의 `/naeil-locale`, `/client`, `/server`, `/messages`, `/checker`를 사용한다. `NaeilLocaleProvider` 안에서는 헤더·계정·푸터를 `/naeil-locale/chrome`에서 가져온다. `/naeil-header`와 `/naeil-footer`는 독립 React 어댑터로 유지된다. 공유 server/client 경로에는 정확한 `next-intl@4.14.8`이 필요하다.
|
|
6
8
|
|
|
7
9
|
## 시작하기
|
|
8
10
|
|
|
9
11
|
React 19/ReactDOM 19와 Tailwind 4 앱에서 `/ui` 또는 선택적 `/naeil-header`·`/naeil-footer`를 사용한다. API 키와 Next.js는 필요 없다. 검증한 registry 버전을 고정해 설치한다.
|
|
10
12
|
|
|
11
13
|
```sh
|
|
12
|
-
pnpm add --save-exact @naeil/ui@
|
|
14
|
+
pnpm add --save-exact @naeil/ui@VERSION
|
|
15
|
+
# VERSION은 README와 registry에서 확인한 정확한 게시 버전으로 바꾼다.
|
|
13
16
|
```
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
archive에 포함된 안내는 준비 시점의 기록이므로 현재 설치에는 이 유지보수 안내를 따른다. 로컬 개발에서는 저장소에서 `pnpm build:pkg`와 `npm pack --ignore-scripts --pack-destination /tmp`를 실행하고 출력된 archive를 설치한다. 현재 소스의 개발용 pack은 동결 릴리스 archive와 다를 수 있으므로 게시 파일을 대체하지 않는다. [독립 React 예제](https://github.com/naeil-dev/naeil-ui/tree/main/examples/react)와 [검증/릴리스 정책](../package-release.md)을 참고한다.
|
|
16
19
|
|
|
17
20
|
공통 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 의존성과 코드는 공통 소비 경계에서 제외했다.
|
|
18
21
|
|
|
19
|
-
버전을 생략한 설치는 registry의 latest 태그를 따른다.
|
|
22
|
+
버전을 생략한 설치는 registry의 latest 태그를 따른다. 업그레이드 전에 `npm view @naeil/ui dist-tags`와 [변경 기록](../../CHANGELOG.md)을 확인하고 검증한 정확한 버전을 고정한다.
|
|
20
23
|
|
|
21
24
|
Tailwind 4를 사용하는 앱의 전역 CSS에서 공통 스타일을 한 번 불러온다.
|
|
22
25
|
|
|
@@ -29,7 +32,7 @@ Tailwind 4를 사용하는 앱의 전역 CSS에서 공통 스타일을 한 번
|
|
|
29
32
|
|
|
30
33
|
이미 Tailwind와 기본 스타일을 구성한 앱은 `@naeil/ui/theme.css`와 `@naeil/ui/components.css`를 함께 불러올 수 있다. 컴포넌트 CSS에는 크기·포커스·밀도·포털·reduced-motion 규칙이 있으므로 theme.css만으로 전체 v2 모양이 완성되지는 않는다.
|
|
31
34
|
|
|
32
|
-
0.9.0
|
|
35
|
+
0.9.0부터 두 CSS 경로의 `components.css`가 `html { scrollbar-gutter: stable }`과 Radix 이중 보상 제거를 제공한다. classic은 한쪽 공간을 예약하고 overlay는 0px이다. `<html data-naeil-scrollbar-gutter="auto">`를 첫 paint 전에 선언하면 root 예약과 lock 보정을 함께 끈다. theme-only/JS-only는 문서 정책을 바꾸지 않는다. 본문 바깥 여백/custom scroller/helper class는 별도 소비자 통합이나 opt-out이 필요하다. [채택된 계약](https://github.com/naeil-dev/naeil-ui/blob/434b7d07235316097ca3a55265ee02c1422b0cfd/docs/superpowers/specs/2026-10-29-page-root-scrollbar-gutter.md)과 [layout guide](../components/application-layout.md)의 비교·fallback·일본어 320px F3 wrap 규칙을 따른다.
|
|
33
36
|
|
|
34
37
|
CSS import를 `layer(ui)` 같은 named layer로 감싸지 않는다. 그러면 dependency의 unlayered `--removed-body-scroll-bar-size`가 이겨 classic에서 15px로 남을 수 있다. opt-out 후 `@layer base { html { scrollbar-gutter: stable; } }`는 패키지 attribute selector보다 약하므로, layer 밖에 `html[data-naeil-scrollbar-gutter="auto"] { scrollbar-gutter: stable; }`를 쓰거나 패키지 import 뒤의 같은 base layer에서 이 attribute selector를 쓴다. 이때 lock 보상은 소비자가 책임진다. Classic modal scrim은 예약된 gutter 띠를 덮지 않으며, 0.9.0에서 scrim 스타일을 바꾸지 않는다. 자세한 예시와 적용 범위는 [layout guide](../components/application-layout.md#width-contract)를 따른다.
|
|
35
38
|
|
|
@@ -55,7 +58,7 @@ Select는 값 선택, DropdownMenu는 행동 선택에 사용한다. Switch와 C
|
|
|
55
58
|
- 기본 컨트롤 높이 40px. 문서 루트에 `data-ui-density="compact"`를 주면 36px가 된다. 작은 화면과 거친 포인터에서는 최소 44px를 유지한다. 데스크톱에서 `className="h-8"` 같은 높이 재정의는 적용되며, 모바일의 44px 최소 터치 크기는 유지된다.
|
|
56
59
|
- `.light`/`.dark`는 OS 테마보다 우선한다. 기존 ThemeProvider를 사용할 수 있다.
|
|
57
60
|
- 공통 바깥 틀은 최대 1600px, 좌우 여백은 `clamp(16px, 2.4vw, 40px)`다. 본문의 `.ui-app-frame`과 공통 헤더·푸터 내부 프레임이 같은 토큰을 사용한다.
|
|
58
|
-
- `data-ui-layout="reading|settings|list|short-form|fluid"`로 내부 콘텐츠 폭을 적용한다. 각각 최대 640/640/1600/
|
|
61
|
+
- `data-ui-layout="reading|settings|list|short-form|workflow|fluid"`로 내부 콘텐츠 폭을 적용한다. 각각 최대 640/640/1600/480/896px 또는 가용 폭이다. `workflow`(2026-11-09 승인)는 단계형·카드 선택형 입력 화면용이며, 그 안의 개별 입력 필드는 계속 640/480px 이하로 둔다. 목록은 바깥 틀의 여백을 제외한 공간을 사용하고, 설정·읽기 영역은 그 안에서 좁게 유지한다.
|
|
59
62
|
- 레이블·도움말·오류 문구는 소비 화면이 연결한다. Input의 `aria-invalid`와 `aria-describedby`를 사용하고, 로딩 중에는 Button의 `disabled`와 `aria-busy`를 함께 지정한다.
|
|
60
63
|
- 성공·경고·오류·안내에는 Badge의 `success`, `warning`, `error`, `info` variant를 사용할 수 있다. 색만으로 의미를 전달하지 않는다.
|
|
61
64
|
|
|
@@ -189,6 +192,7 @@ components/ui/button
|
|
|
189
192
|
components/ui/card
|
|
190
193
|
components/ui/checkbox
|
|
191
194
|
components/ui/dialog
|
|
195
|
+
components/ui/sheet
|
|
192
196
|
components/ui/dropdown-menu
|
|
193
197
|
components/ui/input
|
|
194
198
|
components/ui/navigation
|
|
@@ -211,9 +215,11 @@ i18n/config
|
|
|
211
215
|
i18n/routing
|
|
212
216
|
```
|
|
213
217
|
|
|
218
|
+
**Server Components:** `@naeil/ui/ui` remains a client component barrel; do not call its `buttonVariants` or `badgeVariants` exports on the server. Use `@naeil/ui/components/ui/button` and `@naeil/ui/components/ui/badge` for those server-side helper calls. Both `@naeil/ui/utils` and `@naeil/ui/lib/utils` provide RSC-safe `cn`.
|
|
219
|
+
|
|
214
220
|
`components/index` has the same framework requirements as root. `/utils` and `lib/utils` remain aliases for `cn`. `i18n/config` preserves the compatibility locale names; products may instead own their locale list and routing. There are no open-ended component/lib/i18n export patterns. Root, `/ui`, `/utils`, `/theme.css`, `/globals.css` and `/components.css` remain public. `/naeil-header`, `/naeil-footer` and `/release` are explicit dedicated entries; they do not create open-ended component export patterns.
|
|
215
221
|
|
|
216
|
-
|
|
222
|
+
These source paths are not package entries: website-only paths belong to the brand/example website, and unused ones may be removed without a package API change. Move any local-source consumer use into the consumer application before upgrading:
|
|
217
223
|
|
|
218
224
|
| Previously declared source path | Ownership/migration |
|
|
219
225
|
| --- | --- |
|
package/docs/package-release.md
CHANGED
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
# Package verification and release policy
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Publication receipt: 0.12.0 published 2026-11-10; registry tags verified 2026-11-11.** Source/tag `e03af076b725d742c4b319aca5ebb2379e2f0258`, frozen archive SHA-256 `7f5f01407c576e3c5fa956cf76ebfb3a8ef59b58619de99da68351974aca721b`, 178 regular files. Registry bytes matched; verified tags are `latest=0.12.0`, `next=0.12.0` ([receipt](https://github.com/naeil-dev/naeil-ui/blob/main/docs/releases/0.12.0/README.md), [GitHub Release](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.12.0)). Earlier baseline 0.10.0 — 2026-11-04: source/tag `455f2f9aedb108606af2f429c18281260eafd2dd`, SHA-256 `a4a1e312f2f608358a10f9019c248af37a8172bb116d3bc506144442cb963fb4`, 175 files, tags then `latest=0.7.2`, `next=0.10.0`. See the [publication and three-service acceptance receipts](https://github.com/naeil-dev/naeil-ui/blob/main/docs/design/shared-language-2026-11-04/implementation-progress.md). Historical releases, archives and receipts remain immutable; hosted Docs require their own receipt. The retained [local runner](https://github.com/naeil-dev/naeil-ui/blob/main/docs/rollout/local-runner.md) is a **0.7.x-only, contract 1** release/recovery tool, outside release and recovery procedures for 0.8.0 and later. UI v2 names a design generation, not an npm major. Version-scoped installation is in the [README](../README.md#use-the-ui).
|
|
4
4
|
|
|
5
|
-
## 0.
|
|
5
|
+
## 0.13.0 candidate — audit fixes and owned-service headers
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Not published. PR #47 supplies the 2026-11-12 audit fixes: server-safe utility imports, locale request/protocol hardening, pressed/theme/typography/accessibility behavior, package payload cleanup and CI checks. PR #48 adds strict opt-in `service` profiles for `abstorm`, `home`, `estimate` and `jev`, canonical lowercase branding and service-only tabs, plus toolbar-only mobile sheets with desktop focus restoration. Legacy props/output and inferred `NaeilHeaderProps` remain supported through service-first/legacy-last overloads. Deprecated brand/status/toolbar escape hatches remain functional without `service`; see [header profiles](components/naeil-header.md) and [compatibility changes](../CHANGELOG.md).
|
|
8
|
+
|
|
9
|
+
Package metadata, generated `/release` and clean React/Next fixture versions are 0.13.0. Chrome contract 1 is unchanged because the service branch is opt-in and the omitted-service legacy contract is preserved; the audit's changed visual defaults and dependency/font guidance are listed in the changelog. Freeze all bundled source and guide edits in the source/version commit, then retain the exact archive, full member hashes and final local gates outside the npm payload in a separate evidence-only commit, as for 0.12.0. Rebuild from that frozen Git source and require byte-identical packing.
|
|
10
|
+
|
|
11
|
+
Registry checked 2026-11-12: `latest=0.12.0`, `next=0.12.0`; 0.13.0 is absent. The owner runs the manual publication command with OTP, publishes the reviewed archive to `next` and preserves `latest` unless separately approved. Intended tag `v0.13.0` must identify the frozen source. Preparation executes none of publication, dist-tag changes, tag/Release creation, workflow dispatch, push/merge, hosted Docs deployment or service adoption; each requires its own maintainer action and receipt. Historical release directories, archives, receipts and the 0.7.x rollout runner stay unchanged.
|
|
12
|
+
|
|
13
|
+
## 0.12.0 release — shared UI refinements and Sheet
|
|
14
|
+
|
|
15
|
+
This additive minor release includes PR #42 (`0d1cb08`): optional `closeLabel` for `DialogContent`/`DialogFooter` with unchanged defaults, error versus destructive guidance and checks, NaeilFooter starters using default `full`, compact footer link groups aligned to the top unless overridden with consumer `items-*` classes, and `ui.width-workflow` (896px) / `data-ui-layout="workflow"`. The locale service registration proposal is documentation only. PR #43 (`047de96`) adds public Sheet primitives at `@naeil/ui/ui` and `@naeil/ui/components/ui/sheet`.
|
|
16
|
+
|
|
17
|
+
Published 2026-11-10 to `next` and promoted to `latest` on 2026-11-11 with owner approval (see the receipt above). Tag `v0.12.0` identifies the frozen source. Package version, generated `/release` metadata and clean React/Next fixture versions move together. Future releases require a new frozen source/archive and their own gates; maintained guide edits do not replace this archive. Publication, registry verification, consumer adoption, GitHub Release and hosted Docs remain separate receipts.
|
|
18
|
+
|
|
19
|
+
## 0.11.0 release — AB Storm locale registry
|
|
20
|
+
|
|
21
|
+
Published 2026-11-08, this additive release registers AB Storm's five protected UI routes and error-document identity. Tag `v0.11.0` identifies its frozen source; see the [release](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.11.0). The historical 0.7.x runner transaction and chrome contract 1 remain unchanged. Package publication, consumer adoption and hosted Docs require separate receipts.
|
|
8
22
|
|
|
9
23
|
## Architecture
|
|
10
24
|
|
|
@@ -12,6 +26,8 @@ One repository contains the shared package and the separate Next.js brand/exampl
|
|
|
12
26
|
|
|
13
27
|
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). Historical 0.7.x release plans and transaction recovery use the [local rollout runner](https://github.com/naeil-dev/naeil-ui/blob/main/docs/rollout/local-runner.md); the [rollout records](https://github.com/naeil-dev/naeil-ui/tree/main/docs/rollout) preserve dated evidence and historical policies. Publishing a package, creating an update PR or merging it never establishes complete consumer rollout. Home Console is outside the selected shared-UI rollout.
|
|
14
28
|
|
|
29
|
+
The [owned-service language runtime](components/naeil-locale.md) exposes `/naeil-locale` for registered routes/locales, `/server` for request routing/configuration, `/client` for the controller/provider, `/messages` for selected dictionaries, `/checker` for message validation and `/chrome` for provider-backed header/account/footer presentation. Owned Next services under `NaeilLocaleProvider` use `/naeil-locale/chrome`; `/naeil-header` and `/naeil-footer` remain standalone React adapters. The shared server/client runtime requires exact `next-intl@4.14.8`.
|
|
30
|
+
|
|
15
31
|
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 0.7.2 default catalog contains naeil-ui and references the official `https://naeil.dev/images/whale.png` URL and require network access; no image bytes are bundled, and unresolved artwork redistribution provenance remains in [third-party notices](../THIRD_PARTY_NOTICES.md).
|
|
16
32
|
|
|
17
33
|
## Checks
|
|
@@ -127,7 +143,7 @@ The immutable npm archive's bundled guides are the release-preparation snapshot.
|
|
|
127
143
|
|
|
128
144
|
### Release procedure
|
|
129
145
|
|
|
130
|
-
|
|
146
|
+
Storybook resolves relative Markdown guide and TypeScript source links against `v${version}`, using the version from the package.json being built. Maintained repository guides use relative wrapper-source links so their API authority follows the checkout. The package tag is independent of the reviewed Docs deployment SHA; hosted verification checks links against the build’s package version. Explicit historical evidence links retain their recorded revisions. Freeze subsequent documentation changes separately from immutable release archives; a new version’s links become publicly reachable only when its source tag exists.
|
|
131
147
|
|
|
132
148
|
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.
|
|
133
149
|
|
|
@@ -160,7 +176,7 @@ Package publication, tag, GitHub Release, main merge and Home deployment each re
|
|
|
160
176
|
|
|
161
177
|
## Storybook preview artifact
|
|
162
178
|
|
|
163
|
-
`pnpm build:storybook` builds
|
|
179
|
+
`pnpm build:storybook` builds 18 actual Docs pages: 16 UI families (the 14 primitives plus Navigation and SiteFooter) and Brand / Logo and NaeilHeader. Interactive examples include the complete branded header, JapaneseApplication, canonical footer ReferenceFull/ReferenceCompact and AccountStates. Canonical footer/account examples live within existing stories, without a separate NaeilFooter Docs family. It copies generated documentation notices and approved canonical brand SVGs, bundles locally installed Pretendard/Noto Sans JP and disables Vite publicDir. The artifact check verifies real Docs/story entries, exact MIT/shadcn/font notices, brand references and absence of website public images/SVGs/HTML. It does not claim those excluded site assets have cleared rights.
|
|
164
180
|
|
|
165
181
|
CI uploads `storybook-preview` after a successful build; it is a downloadable static artifact, not a hosted deployment. Download/unzip it and serve the extracted directory (containing index.html):
|
|
166
182
|
|
|
@@ -186,16 +202,16 @@ Select **Publish reviewed UI docs (manual only)** in Actions (or use the command
|
|
|
186
202
|
gh workflow run publish-docs-manual.yml --ref main -f reviewed_sha=FULL_REVIEWED_DOCS_COMMIT_SHA -f confirmation=PUBLISH_REVIEWED_DOCS
|
|
187
203
|
```
|
|
188
204
|
|
|
189
|
-
After the reviewed Docs deployment, verify the manager and iframe under `/naeil-ui/`, all
|
|
205
|
+
After the reviewed Docs deployment, verify the manager and iframe under `/naeil-ui/`, all 16 UI and 2 Brand Docs pages, their Usage examples, NaeilHeader JapaneseApplication, canonical footer full/compact destinations, and signed-out/signed-in/menu/busy account states. Check the guide and source links against the tag matching the built package.json version, canonical artwork and official image references, local fonts and exact LICENSE/THIRD_PARTY_NOTICES/font notices over HTTP. Retain the deployment URL, Docs source SHA, workflow run and observed results separately from the package source/tag. 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.
|
|
190
206
|
|
|
191
207
|
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.
|
|
192
208
|
|
|
193
209
|
For a Storybook dependency upgrade, first build the new preview to obtain fresh manager scripts, then run `python3 scripts/refresh-storybook-notices.py` (read-only npm/source retrieval plus a local notice-file update), review its source/notice changes, and rebuild. The refresh is opt-in and needs network; the build never retrieves legal/reference material silently. Keep all generated `licenses/` JSON/text files with the preview. The standalone React consumer likewise emits exact installed code/font notices with its production output.
|
|
194
210
|
|
|
195
|
-
### 0.9.0 frame preparation gates
|
|
211
|
+
### Historical 0.9.0 frame preparation gates
|
|
196
212
|
|
|
197
213
|
The owner adopted rev 1 on 2026-10-29 for local implementation and verification, including the root opt-out and F3 wrap. Both CSS graphs, theme/JS-only controls, opt-out and false-support branch, short/long route frames, body/content/fixed anchors under nested Radix locks, capture guards, frozen 0.8.0 comparisons and clean installed React/Next production CSS must pass before freezing. The false-support fixture tests a CSS branch, not a real unsupported engine. `build-chrome-fixtures.ts` alone is not clean-consumer proof; `check-consumers.ts` independently installs/builds/exercises both paths in each framework.
|
|
198
214
|
|
|
199
215
|
Run the normal checks above serially, plus the two deterministic Chromium mode jobs using B0's process-local wrappers, `NAEIL_UI_SCROLLBAR_MODE=classic|overlay` and `NAEIL_UI_SCROLLBAR_WRAPPERS=/absolute/wrapper-directory`. Their 15/0px overflow probes and stable-root frame probes must pass; the diagnostic `--enable-automation` flag exposes actual argv through CDP without changing the mode probe. Preserve exact source/archive SHA-256/SRI/inventory and per-gate commands/exit codes outside the archive. Repeat archive-dependent checks using `NAEIL_UI_CHROME_PACKAGE=/absolute/extracted/package` and `NAEIL_UI_EXPECTED_ARCHIVE_SHA256`.
|
|
200
216
|
|
|
201
|
-
|
|
217
|
+
At the October 29 preparation checkpoint, the candidate was unpublished. The following holds describe that historical checkpoint, not current release or service status. npm/dist-tag, version tag, GitHub Release, push/main merge (= naeil.dev production), hosted Docs and Home bump/deploy remain separate approvals. Home keeps its local root rule until an approved exact-version upgrade removes it; rollback restores manifest/lock and local root rule together. Estimate/Jev remain on 0.7.2 and STOP remains in force.
|