refactor: migrate legacy wire namespace to wrn
Quality / quality (ubuntu-latest) (push) Failing after 9m49s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
2026-08-12 18:51:15 +05:30
parent ec23dd4c93
commit 2c960fc1dc
488 changed files with 27306 additions and 19063 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ Legend:
| 28 | Performance budgets | configurable route JS/CSS, HTML, image, hydration, and SSR budgets | Implemented |
| 29 | Observability | tracer/span APIs, request middleware, Server-Timing, console exporter | Implemented |
| 30 | Component architecture | Existing `@wrnexus/ui` inventory retained; syntax metadata supports typed tooling | Existing + hardened |
| 31 | Design tokens | Existing `--wire-*` system and theme resolution retained | Existing + hardened |
| 31 | Design tokens | Existing `--wrn-*` system and theme resolution retained | Existing + hardened |
| 32 | Accessibility | compile-time missing-alt diagnostic plus existing DevToolbar scanning | Implemented |
| 33 | Motion/transitions | Existing CSR/lifecycle foundation retained; strategy can be plugin/runtime extended | Foundation / experimental |
| 34 | Documentation | language, architecture, upgrade, implementation, test checklist docs | Implemented |
+32 -32
View File
@@ -29,7 +29,7 @@ single generic runtime (no percomponent bundles). The `.wrn` language compile
**Part III — Build an app, feature by feature**
- 10. A page · 11. Layouts · 12. Components & props · 13. Reactivity · 14. Wire UI · 15. Theming · 16. Styles · 17. API routes · 18. Validation (forms + API) · 19. Database · 20. Auth, sessions & CSRF · 21. Middleware · 22. i18n · 23. SEO · 24. Security headers & CORS · 25. Realtime · 26. SSR/CSR data bindings · 27. Optional packages · 28. Config profiles & env · 29. Testing · 30. Build & deploy
- 10. A page · 11. Layouts · 12. Components & props · 13. Reactivity · 14. WrNexus UI · 15. Theming · 16. Styles · 17. API routes · 18. Validation (forms + API) · 19. Database · 20. Auth, sessions & CSRF · 21. Middleware · 22. i18n · 23. SEO · 24. Security headers & CORS · 25. Realtime · 26. SSR/CSR data bindings · 27. Optional packages · 28. Config profiles & env · 29. Testing · 30. Build & deploy
**Part IV — Reference**
@@ -206,11 +206,11 @@ quoted or baretoendofline.
```
style {
.box { background: var(--wire-color-surface); border-radius: var(--wire-radius); }
.box { background: var(--wrn-color-surface); border-radius: var(--wrn-radius); }
}
```
Multiple `style` blocks accumulate. Use theme tokens (`var(--wire-*)`) so styles restyle on theme
Multiple `style` blocks accumulate. Use theme tokens (`var(--wrn-*)`) so styles restyle on theme
change.
### `functions { }` — typed helpers
@@ -339,8 +339,8 @@ view {
```
There are also framework attributes consumed by **other** runtimes (loaded only when present):
`data-wire-theme-toggle`/`data-wire-theme-set` (theme, §15), `data-schema`/`data-error`/
`data-success`/`data-redirect` (forms, §18), `data-wire-lang-set`/`data-wire-lang` (i18n, §22),
`data-wrn-theme-toggle`/`data-wrn-theme-set` (theme, §15), `data-schema`/`data-error`/
`data-success`/`data-redirect` (forms, §18), `data-wrn-lang-set`/`data-wrn-lang` (i18n, §22),
`data-room*` (realtime, §25).
Cross-platform pages can use `data-native-browser="capability"` and
@@ -489,11 +489,11 @@ component Demo {
The runtime tracks dependencies automatically and rerenders only what changed. No `new Function`,
no `eval` — CSPsafe.
## 14. Wire UI
## 14. WrNexus UI
`@wrnexus/ui` ships **24** themed components, autodiscovered like your own. Mount with
`data-component`; every component accepts a `class` prop (appended to the root) and is styled via
`--wire-*` tokens + `.wire-*` classes you can override.
`--wrn-*` tokens + `.wrn-*` classes you can override.
**Layout:** `container`, `stack` (`gap`), `hstack` (`gap`, `align`), `grid` (`cols`, `gap`),
`spacer`, `divider`, `card`.
@@ -514,14 +514,14 @@ Variants: buttons `default|primary|danger|ghost`, sizes `sm|md|lg`; badge/tag/al
<div data-component="grid" cols="3" gap="4">…</div>
```
**Override styling**, in priority order: (1) theme tokens `--wire-*`, (2) redefine `.wire-*` in your
**Override styling**, in priority order: (1) theme tokens `--wrn-*`, (2) redefine `.wrn-*` in your
CSS (loads after `ui.css`), (3) the `class` prop, (4) `wrnexus eject <name>` to copy the component's
`.wrn` source into `app/components/` (your copy shadows the library one).
## 15. Theming
Themes are flat token maps rendered as `--wire-<key>` CSS variables (server + client). Builtin
`light` and `dark`; the cookie `wire-theme` selects one.
Themes are flat token maps rendered as `--wrn-<key>` CSS variables (server + client). Builtin
`light` and `dark`; the cookie `wrn-theme` selects one.
```ts
// wrnexus.config.ts
@@ -543,11 +543,11 @@ Builtin token keys include: `color-scheme`, `color-bg`, `color-surface`, `col
Toggle from the view with zero JS:
```
<button data-wire-theme-toggle>Toggle theme</button>
<button data-wire-theme-set="light">Light</button>
<button data-wrn-theme-toggle>Toggle theme</button>
<button data-wrn-theme-set="light">Light</button>
```
The client exposes `window.wireTheme = { get, set, toggle, bind, themes }`.
The client exposes `window.wrnTheme = { get, set, toggle, bind, themes }`.
## 16. Styles
@@ -634,30 +634,30 @@ export async function POST(ctx: Context): Promise<Response> {
`parseEnv(schema, source?)` validates env vars and throws one readable multiline error.
**Client form flow** (zero JS you write). The schema's descriptor is baked into
`window.__wireSchemas` by name (filename). Wire a form up with attributes:
`window.__wrnSchemas` by name (filename). WrNexus a form up with attributes:
```
<form data-schema="login" method="post" action="/api/login" data-redirect="/dashboard">
<div data-component="input" type="email" name="email"></div>
<span class="wire-field-error" data-error="email"></span>
<span class="wrn-field-error" data-error="email"></span>
<div data-component="input" type="password" name="password"></div>
<span class="wire-field-error" data-error="password"></span>
<span class="wrn-field-error" data-error="password"></span>
<div class="wire-alert wire-alert--success" data-success="Signed in!" hidden></div>
<button type="submit" class="wire-btn wire-btn--primary">Sign in</button>
<div class="wrn-alert wrn-alert--success" data-success="Signed in!" hidden></div>
<button type="submit" class="wrn-btn wrn-btn--primary">Sign in</button>
</form>
```
- `data-schema="login"` — picks the descriptor.
- `name="…"` — matched to schema fields; validated on `blur` and `submit`.
- `data-error="field"` — receives the message; the input gets `aria-invalid` + `.wire-invalid`.
- `data-error="field"` — receives the message; the input gets `aria-invalid` + `.wrn-invalid`.
- `data-success` — shown on success when there's no redirect.
- `data-redirect="/path"` (or `redirect` in the JSON response) — navigates on success.
On submit it validates clientside, then POSTs `JSON` with `x-csrf-token` (from the `wire-csrf`
On submit it validates clientside, then POSTs `JSON` with `x-csrf-token` (from the `wrn-csrf`
cookie) and `credentials: same-origin`, and resurfaces server `errors` into the `data-error`
spans. It also dispatches `wire:success` / `wire:error` events. Scaffold: `wrnexus generate schema login`.
spans. It also dispatches `wrn:success` / `wrn:error` events. Scaffold: `wrnexus generate schema login`.
## 19. Database
@@ -860,9 +860,9 @@ export async function POST(ctx: Context): Promise<Response> {
**Guarding:** `requireAuth({ loginPath: "/login" })` as middleware — API/JSON → 401, page nav → 302
to `${loginPath}?next=<target>`. Or inline: `if (getUser(ctx) == null) …`.
**CSRF** (doublesubmit): cookie `wire-csrf` (JSreadable), header `x-csrf-token`. `csrfToken(ctx)`
**CSRF** (doublesubmit): cookie `wrn-csrf` (JSreadable), header `x-csrf-token`. `csrfToken(ctx)`
returns/creates the token; `verifyCsrf(ctx)` passes GET/HEAD/OPTIONS, else compares header to cookie.
The Wire UI form runtime sends the header automatically. Add `csrfProtection()` middleware to enforce
The WrNexus UI form runtime sends the header automatically. Add `csrfProtection()` middleware to enforce
globally.
**Sessions:** cookie `wrnexus.sid` (HttpOnly, Lax, Secure on HTTPS), 24h sliding TTL, 256bit id.
@@ -908,7 +908,7 @@ Core factories and their key options:
## 22. i18n
Optin: add dictionaries under `app/locales/<lang>.json`. Language resolves per request from the
`wire-lang` cookie → `Accept-Language` → default.
`wrn-lang` cookie → `Accept-Language` → default.
```json
// app/locales/en.json
@@ -923,7 +923,7 @@ export const GET = async (ctx: Context) =>
```
Config: `i18n: { default: "en", locales: ["en", "fr"] }` (both optional; inferred from files).
Switch language from the view with `data-wire-lang-set="fr"`. Formatting helpers (Intlbased) are
Switch language from the view with `data-wrn-lang-set="fr"`. Formatting helpers (Intlbased) are
exported from `@wrnexus/i18n`: `formatNumber`, `formatCurrency`, `formatDate`, `formatRelativeTime`,
`plural`.
@@ -1021,7 +1021,7 @@ realtime: { scale: true, redisUrl: process.env.REDIS_URL }, // defaults to redis
Now `client.room.broadcast(msg)` in one app instance is delivered to subscribers in all the
others. Connectiontargeted `send`/`to(id)` stay local (ids are perprocess). Under the hood it's
`bridgeRealtime(registry, bus)` from `@wrnexus/core` + the `@wrnexus/pubsub` Redis driver — you can
also wire it manually for custom buses.
also wrn it manually for custom buses.
## 26. SSR/CSR data bindings
@@ -1264,7 +1264,7 @@ wrnexus gateway [--port=3000] [--prod] Serve every workspace a
wrnexus generate <type> <name> (alias: g) Scaffold: page | component | api | schema
wrnexus generate routes Regenerate app/routes.gen.ts
wrnexus generate docker Scaffold Dockerfile + compose
wrnexus eject <name...> Copy a Wire UI component into app/components/
wrnexus eject <name...> Copy a WrNexus UI component into app/components/
wrnexus db new [name] [--from-models] [--db=<name>] Scaffold a migration (optionally from schema.ts)
wrnexus db generate [--db=<name>] Regenerate queries.gen.ts from queries/*.sql
wrnexus db migrate | rollback | status [--db=<name>] Apply / revert / list migrations
@@ -1299,7 +1299,7 @@ const config: AppConfig = {
theme: {
palette: "violet",
default: "dark", // theme when no wire-theme cookie
default: "dark", // theme when no wrn-theme cookie
themes: { light: { "color-primary": "#2563eb" }, dark: { "color-primary": "#6c8cff" } },
},
@@ -1354,8 +1354,8 @@ directive to `false`/`null` to remove it.
**Server/compiler:** `data-component` · `data-slot` · `<slot [name]>` · `{expr}` · `{{expr}}` ·
`{t:key}` (→ `data-t`) · `@event="stmt"` · `api="binding"`.
**Forms:** `data-schema` · `name` · `data-error` · `data-success` · `data-redirect`.
**Theme:** `data-wire-theme-toggle` · `data-wire-theme-set="name"`.
**i18n:** `data-wire-lang-set="lang"` · `data-wire-lang`.
**Theme:** `data-wrn-theme-toggle` · `data-wrn-theme-set="name"`.
**i18n:** `data-wrn-lang-set="lang"` · `data-wrn-lang`.
**Realtime:** `data-room` · `data-room-user` · `data-room-log` · `data-room-status`
(+`data-room-status-class`) · `<template data-room-item="type">` (`%field%`) · `data-room-send` ·
`data-room-reset`.
@@ -1371,7 +1371,7 @@ directive to `false`/`null` to remove it.
(`saveUpload`, `collectUploads`, `sanitizeFilename`); streaming (`streamResponse`, `sse`); realtime
(`defineRoom`, `createRealtimeRegistry`, `bridgeRealtime`); errors (`renderError`, `renderNotFound`); headers
(`withSecurityHeaders`, CORS); sessions (`setSessionBackend`, `loadSession`); JSX runtime.
- `@wrnexus/compiler` — `compileWireFile`, `compile`, `parse`, `generate`, `Lexer`, `ParseError`.
- `@wrnexus/compiler` — `compileWrnFile`, `compile`, `parse`, `generate`, `Lexer`, `ParseError`.
- `@wrnexus/router` — `buildRouter`, `matchRoute`, `generateRoutesFile`.
- `@wrnexus/ssr` — `renderDocument`.
- `@wrnexus/csr` — `getReactiveRuntime`, `getNavRuntime`, `getRealtimeRuntime`.
@@ -1388,7 +1388,7 @@ directive to `false`/`null` to remove it.
`createDb`, `paginate`, `loadRelated`, migrations, query generation; subpaths `/session`,
`/sqlite`, `/postgres`, `/mysql`, `/mongo`.
- `@wrnexus/dev-server` — `startServer`, `startGateway` (multi-app host router), prod handler.
- `@wrnexus/cli` — the `wrnexus` binary; subpath `/workspace` (`WorkspaceConfig`, `startGateway` wiring).
- `@wrnexus/cli` — the `wrnexus` binary; subpath `/workspace` (`WorkspaceConfig`, `startGateway` integration).
- `@wrnexus/validation` — `v`, `parseBody`, `parseEnv`, `invalid`, `renderSchemasScript`.
- `@wrnexus/helpers` — original gateway URL/path/method helpers and `redirectToLogin`.
- `@wrnexus/ui` — `uiComponentsDir`, `uiCssPath`, `uiCss`, `uiComponentNames`.
+1 -1
View File
@@ -131,7 +131,7 @@ duplicate version).
## Consume on another machine (needs Bun)
```bash
mkdir my-wire-app && cd my-wire-app
mkdir my-wrn-app && cd my-wrn-app
# Scaffold via the CLI
npm i @wrnexus/cli
+1 -1
View File
@@ -871,7 +871,7 @@ Official enterprise packages should eventually support:
- Export and deletion workflows
- Consent tracking
**Status:** Delivered. `@wrnexus/auth` supplies OAuth account linking, passkeys, email/SMS/TOTP/recovery-code MFA, trusted devices, revocable sessions and audited impersonation. `@wrnexus/authz` supplies RBAC, ABAC and composable policy decisions. The separate `@wrnexus/identity` package adds strict OIDC discovery and PKCE authorization, signed-SAML adapter validation with issuer/audience/recipient/expiry/replay enforcement, LDAP and Active Directory synchronization adapters, authenticated bounded SCIM provisioning, scoped API keys and service accounts, approval-gated subject exports/deletions, consent history, retention enforcement and governance audit events. SAML XML-signature and LDAP wire parsing deliberately remain adapter responsibilities so deployments can choose a maintained protocol SDK without placing vendor code in core.
**Status:** Delivered. `@wrnexus/auth` supplies OAuth account linking, passkeys, email/SMS/TOTP/recovery-code MFA, trusted devices, revocable sessions and audited impersonation. `@wrnexus/authz` supplies RBAC, ABAC and composable policy decisions. The separate `@wrnexus/identity` package adds strict OIDC discovery and PKCE authorization, signed-SAML adapter validation with issuer/audience/recipient/expiry/replay enforcement, LDAP and Active Directory synchronization adapters, authenticated bounded SCIM provisioning, scoped API keys and service accounts, approval-gated subject exports/deletions, consent history, retention enforcement and governance audit events. SAML XML-signature and LDAP wrn parsing deliberately remain adapter responsibilities so deployments can choose a maintained protocol SDK without placing vendor code in core.
## 23. AI-Native Development
+1 -1
View File
@@ -83,7 +83,7 @@ Verify before committing:
| 28 | Performance budgets | Set deliberately small HTML/JS/CSS/image budgets, then realistic budgets. | Build warns/fails according to policy, then passes with realistic limits. |
| 29 | Observability | Enable tracing and `serverTiming`; make a request containing nested spans. | Trace records include duration/status/attributes and response has `Server-Timing`. |
| 30 | Component architecture | Render primitives, behavior components, layouts, and product components in light/dark/responsive states. | Props/events/slots/accessibility remain consistent and app overrides still win. |
| 31 | Design tokens | Audit `--wire-*` usage and switch themes. | Components use semantic tokens and no required token is undefined. |
| 31 | Design tokens | Audit `--wrn-*` usage and switch themes. | Components use semantic tokens and no required token is undefined. |
| 32 | Accessibility | Compile missing-alt markup and run toolbar keyboard/focus/ARIA checks. | Compile-time and runtime accessibility findings appear without duplicates or false positives. |
| 33 | Motion/transitions | Exercise existing lifecycle/animation behavior with reduced-motion enabled and disabled. | Motion respects user preference and teardown does not leak listeners/timers. |
| 34 | Documentation | Follow the language, architecture, upgrade, and this checklist from a clean clone. | Commands/examples match actual APIs and produce the documented result. |
+1 -1
View File
@@ -1,6 +1,6 @@
# WRNexusJS — Security & Power Improvement Plan
Prepared for WorkRoot · covers `E:\WireJS` (framework v0.8.4)
Prepared for WorkRoot · covers `E:\WrNexus` (framework v0.8.4)
This plan is scoped and sequenced the way the repo's own roadmap docs are (`ROADMAP-V1.md`,
`IMPLEMENTATION-ROADMAP-0.8.md`): version-gated phases, one package/file set per item, with
+19 -19
View File
@@ -9,7 +9,7 @@ definition, and local styles on every component. The core reactive runtime is
The §4.1 ownership migration is complete: `ui.css` contains global and
cross-cutting primitives only. Shared component foundations are carried by
three internal style-only components and render on demand; the former global
component families and standalone `wire-next` generation class are absent.
component families and standalone `wrn-next` generation class are absent.
Final validation passed the production, package, example, service, editor,
showcase-generation, typecheck, lint, formatting, public-API, visual-contract,
@@ -60,7 +60,7 @@ Practical rules:
- CSS comments in a `style {}` block are `/* */` only. `//` is not a CSS comment
and silently swallows the rule that follows it.
- Style the component's own BEM classes (`wire-thing`, `wire-thing__part`).
- Style the component's own BEM classes (`wrn-thing`, `wrn-thing__part`).
Variants are data attributes: `[data-variant="soft"]`, not a class explosion.
- No Tailwind utility classes in component markup. See §4.3.
@@ -141,7 +141,7 @@ positives because most tokens are generated per palette, so any such check must
read the **rendered** CSS; and the semantic spread must sit _before_ the
primary/secondary palette entries or it overrides them.
**How to test.** Load a page, then in the console collect every `var(--wire-*)`
**How to test.** Load a page, then in the console collect every `var(--wrn-*)`
referenced by stylesheet rules and check each against
`getComputedStyle(document.documentElement)`. Expect 38 referenced, 0 undefined.
@@ -197,7 +197,7 @@ builds. It should warn on at least:
the event — include the registry keys actually present, which is exactly what
would have made §1.1 a five-minute bug.
2. A `@binding` naming a function that does not exist in scope.
3. A `var(--wire-*)` referenced by a component but absent from the rendered
3. A `var(--wrn-*)` referenced by a component but absent from the rendered
theme.
4. A state write discarded because it happened after the client function
returned (see §2.2).
@@ -331,9 +331,9 @@ done, what is left, and which disposition each remaining component takes.
#### 3.1.1 Already done in 0.8.6 — do not redo
Fifteen components were fixed. Ten had outputs that were **declared but
miswired** — they dispatched a hand-built `CustomEvent` instead of calling
incorrectly connected** — they dispatched a hand-built `CustomEvent` instead of calling
`output.*`, so the declaration was right and only the emit was wrong. Nothing
was added to these; they were rewired:
was added to these; they were reconnected:
> Card, Footer, Breadcrumb, Accordion, alert, Badge, AnnouncementBar,
> AvatarGroup, ToggleCount, InputNumber
@@ -351,13 +351,13 @@ through `output.*`:
| `Timeline` | `select` | item pressed |
Verified firing in a browser: `SearchBox`, `Marquee`, `List`, `Timeline`, plus
all ten rewired components. **`Map` was not verified** — its three outputs were
all ten reconnected components. **`Map` was not verified** — its three outputs were
converted by the same mechanical change and the build passes, but no Map was on
the probe page. Put one on a page and confirm before treating it as done.
#### 3.1.2 Original remaining work — resolved
**Original issue.** These were not miswired. All nine were **pure scaffolds**: roughly 25
**Original issue.** These were not incorrectly connected. All nine were **pure scaffolds**: roughly 25
lines each, zero state, zero functions, no style block, no event handlers. They
are markup shells that declare outputs. "Add an emitter" is not the work — there
is nothing to emit from.
@@ -447,9 +447,9 @@ AdvancedRangeSlider, Chart, Confetti, CopyMarkup, FileUpload, Toast,
ToastNotifications, TreeView. Do §3.1 first and this list drops to 19 without
any extra work. Do not plan the two items separately.
Separately, 58 components carried the standalone `wire-next` scaffold class in
Separately, 58 components carried the standalone `wrn-next` scaffold class in
the original audit; **zero retain it now**. Component-specific BEM identifiers
such as `wire-next--alert` remain locally owned implementation details, but no
such as `wrn-next--alert` remain locally owned implementation details, but no
component is bound to a global stylesheet through the generation artefact.
**Change.** Rebuild them under §0.1, or remove them. Note that several are
@@ -474,10 +474,10 @@ bun run build && gzip -c examples/basic-app/dist/ui.css | wc -c
`TextLink` (14), `Map` (12), `SearchBox` (8), `Timeline` (8) still style
themselves with utility classes in markup.
All seven now use local `wire-*` BEM styles. `InputNumber` styles are emitted as
All seven now use local `wrn-*` BEM styles. `InputNumber` styles are emitted as
component-scoped CSS and therefore do not appear in the global `ui.css` file.
**Change.** Migrate to `wire-*` BEM classes in the component's own `style {}`
**Change.** Migrate to `wrn-*` BEM classes in the component's own `style {}`
block, per §0.1. Note this changes the rendered class list, so application CSS
selecting on those utilities stops matching — it needs a migration note, exactly
as the layout group did in 0.8.6.
@@ -512,14 +512,14 @@ whichever behaviour was chosen.
every page. Only **42 of 108** components had a local `style {}` block.
**Result.** The maintained library now has **102 of 102** components with local
styles. Built `ui.css` is **15,927 bytes / 3,762 gzipped**. The `.wire-next`,
`.wire-btn`, `.wire-dropdown`, `.wire-alert`, `.wire-card`, `.wire-footer`,
`.wire-metric-card`, and `.wire-segmented-group` global families are gone.
styles. Built `ui.css` is **15,927 bytes / 3,762 gzipped**. The `.wrn-next`,
`.wrn-btn`, `.wrn-dropdown`, `.wrn-alert`, `.wrn-card`, `.wrn-footer`,
`.wrn-metric-card`, and `.wrn-segmented-group` global families are gone.
Reusable field, select, color, and size foundations live in three internal
style-only components; the renderer emits and deduplicates them only when a
component that needs them renders. An example-app SSR guard verifies that
on-demand path, while the UI suite prevents the global families or standalone
`wire-next` class from returning.
`wrn-next` class from returning.
**Change.** Done in groups with the visual contract regenerated after each
migration.
@@ -542,7 +542,7 @@ cannot silently regress.
change this session needed a full server restart, which is the single biggest
drag on the edit loop.
**Evidence, and what is _not_ yet proven.** The watcher is wired correctly:
**Evidence, and what is _not_ yet proven.** The watcher is connected correctly:
`componentDirs` includes `uiComponentsDir()` and is passed as `extraDirs`
(`packages/dev-server/src/index.ts:706-723`), external paths arrive absolute
(`packages/dev-server/src/watch.ts:104`), and `hotUpdate` calls
@@ -706,7 +706,7 @@ context.state.topLinks; ...` — the full state-restore prologue.
After hoisting and closure deduplication, the page is **101,253 decoded bytes**;
the largest module is **51,946 bytes** with **2.4% duplicated lines**.
Gzip hides this on the wire, but **parse and compile cost scales with decoded
Gzip hides this on the wrn, but **parse and compile cost scales with decoded
bytes, not transferred bytes**. Half a megabyte of JavaScript is parsed to run
one page.
@@ -792,7 +792,7 @@ a case-sensitive filesystem the same script produces duplicate files instead.
**Change.** Pick one:
- **Delete it.** `generate-ui-component-reference.mjs` is the maintained
generator, it is wired into `release:prepare`, and it works. If this script is
generator, it is connected into `release:prepare`, and it works. If this script is
redundant, it is a loaded gun in the repo for no benefit.
- **Or fix and gate it**: make it write to a temp directory and swap atomically
only on success, so a mid-run crash cannot leave a partial library. Then add
@@ -71,7 +71,7 @@ Versioned, timestamped files with `up`/`down`. Two authoring modes:
last applied state and emits the SQL for you to review.
`wrnexus db migrate` applies pending migrations inside a transaction and records
them in a `_wire_migrations` table; `rollback` runs `down`; `status` lists state.
them in a `_wrn_migrations` table; `rollback` runs `down`; `status` lists state.
Dialect-aware SQL generation for create/alter/index.
## 5. sqlc-like typed queries (`app/db/queries/*.sql` → generated TS)
@@ -130,7 +130,7 @@ A local Artifact/web UI to browse tables + run read-only queries in dev.
1. **Core + SQLite adapter**`@wrnexus/db`, `table()`/`v` model layer, `Driver`
interface, `bun:sqlite` adapter, `db.one/all/exec/tx`, result→schema mapping.
(SQLite first = zero external service to test against.)
2. **Migrations** ✅ done — runner + `_wire_migrations`, `wrnexus db migrate/rollback/status/new`,
2. **Migrations** ✅ done — runner + `_wrn_migrations`, `wrnexus db migrate/rollback/status/new`,
`.sql` (`-- +up`/`-- +down`) + `--from-models` DDL generation. (Model-diffing beyond the
initial CREATE TABLE is a later enhancement; needs topological ordering by FK refs.)
3. **sqlc-like generator** ✅ done — `.sql` parsing (`-- name: X :one/:many/:exec`),
@@ -144,7 +144,7 @@ A local Artifact/web UI to browse tables + run read-only queries in dev.
5. **MongoDB adapter** ✅ built (unverified) — `@wrnexus/db/mongo`: a document
collection API (`find/findOne/insert/update/delete/count`) keyed by models, reads
coerced through `model.parse`, `_id``id`. Lazily imports `mongodb` (optional dep).
Not wired into the SQL singleton/migrations/generator (Mongo isn't SQL). Needs
Not connected into the SQL singleton/migrations/generator (Mongo isn't SQL). Needs
`mongodb` + a server to test.
6. **Polish** — ✅ FK-topological ordering in `--from-models` (referenced tables
first). Deferred: `db studio` (web UI), richer relations/joins helpers.
@@ -6,7 +6,7 @@ validation. Built **foundation-first** so each subsystem lands solid and tested.
Order (one subsystem per turn):
1. **Theme system** ✅ done — design tokens, SSR + client, no-flash, overridable.
2. **Wire UI** (`@wrnexus/ui`) ✅ done — 17 components + layout primitives as `.wrn`,
2. **WrNexus UI** (`@wrnexus/ui`) ✅ done — 17 components + layout primitives as `.wrn`,
consuming theme tokens, overridable 4 ways; auto-discovered + `wrnexus eject`.
3. **Layout system** ✅ done (folded into turn 2) — layout primitives (Container,
Stack, HStack, Grid, Divider, Spacer) + page layouts (`app/layout.wrn` + `<slot>`).
@@ -16,13 +16,13 @@ Order (one subsystem per turn):
## 4. i18n (done)
- `@wrnexus/i18n`: locales in `app/locales/<lang>.json` (nested/flat keys, `{param}`
interpolation). Per request the lang resolves from the `wire-lang` cookie →
interpolation). Per request the lang resolves from the `wrn-lang` cookie →
Accept-Language → config default (`wrnexus.config.ts` `i18n.default`).
- **Server:** `ctx.lang` + `ctx.t(key, params)` on every request (pages + API).
- **Views:** `{t:key}` text sugar compiles to a `<span data-t="key">` marker;
`t:<attr>="key"` translates an attribute. `translateHtml` resolves both on the
final HTML (after components + layout), and `<html lang>` is set (no flash).
- **Switch:** `[data-wire-lang-set="es"]` (or `<select data-wire-lang>`) → the tiny
- **Switch:** `[data-wrn-lang-set="es"]` (or `<select data-wrn-lang>`) → the tiny
`/__wrnexus/i18n.js` sets the cookie + reloads; injected only when present.
- Fallback chain: current lang → default lang → the key itself.
@@ -37,28 +37,28 @@ password: v.string().min(8) })`). `.parse(data)` runs server-side (coerce + erro
parseBody(login, ctx.req)` → 400 `{errors}` or `{value}`. **Form:** `<form
data-schema="login">` with `[data-error="field"]` spans.
- The framework bakes all descriptors into `/__wrnexus/schemas.js`
(`window.__wireSchemas`) and ships an eval-free `/__wrnexus/validate.js` that validates
(`window.__wrnSchemas`) and ships an eval-free `/__wrnexus/validate.js` that validates
`form[data-schema]` on submit/blur — injected only when a page has `data-schema`.
## 2 + 5. Wire UI + layout (done)
## 2 + 5. WrNexus UI + layout (done)
- **Distribution:** `@wrnexus/ui` ships `.wrn` components under `components/`; the
framework auto-discovers them (router `componentDirs`), app/components shadow by
name, and `wrnexus eject <name>` copies one into the app to own it.
- **Codegen:** components now bake prop-driven text/attributes server-side
(`__wireHtml`/`__wireAttr`) so static components ship zero JS; state-referencing
(`__wrnHtml`/`__wrnAttr`) so static components ship zero JS; state-referencing
text stays a reactive mustache. Reserved-word props (`class`) get `__p_` refs;
attribute `{expr}` enables `variant`/`size`/`class` composition.
- **Slots:** `renderComponents` is nesting-aware and fills `<slot>` with mount
children — this also powers page layouts (`app/layout.wrn` wraps every page).
- **Styles:** one themed stylesheet `/__wrnexus/ui.css` (all `.wire-*` classes use
`var(--wire-*)`), linked theme → ui → app so app CSS overrides win.
- **Styles:** one themed stylesheet `/__wrnexus/ui.css` (all `.wrn-*` classes use
`var(--wrn-*)`), linked theme → ui → app so app CSS overrides win.
---
## 1. Theme system (this turn)
**Tokens.** Kebab-case token keys become `--wire-<key>` CSS custom properties.
**Tokens.** Kebab-case token keys become `--wrn-<key>` CSS custom properties.
Framework ships default `light` + `dark` token sets (colors, radius, etc.); user
config deep-merges over them and may add new themes.
@@ -79,23 +79,23 @@ and component styles can read/override it:
```css
:root{ /* default theme tokens */ }
[data-theme="light"]{ --wire-color-primary:#2563eb; color-scheme:light; ... }
[data-theme="dark"]{ --wire-color-primary:#6c8cff; color-scheme:dark; ... }
[data-theme="light"]{ --wrn-color-primary:#2563eb; color-scheme:light; ... }
[data-theme="dark"]{ --wrn-color-primary:#6c8cff; color-scheme:dark; ... }
```
**SSR (no flash).** Server reads the `wire-theme` cookie (falls back to config
**SSR (no flash).** Server reads the `wrn-theme` cookie (falls back to config
default) and renders `<html data-theme="…">`, so the correct theme paints on the
first byte. The theme name is validated against configured names.
**Client** (`/__wrnexus/theme.js`, injected only when a page has a toggle):
`window.wireTheme.{get,set,toggle}` — sets `data-theme` on `<html>`, persists the
`wire-theme` cookie, and binds `[data-wire-theme-toggle]` /
`[data-wire-theme-set="name"]` elements so a `.wrn` component can switch themes
`window.wrnTheme.{get,set,toggle}` — sets `data-theme` on `<html>`, persists the
`wrn-theme` cookie, and binds `[data-wrn-theme-toggle]` /
`[data-wrn-theme-set="name"]` elements so a `.wrn` component can switch themes
without writing JS.
**Override.** Users change tokens in config, or redefine any `--wire-*` variable
in their own CSS (loaded after theme.css → wins). Wire UI components consume
`var(--wire-*)`, so overriding a token restyles every component at once.
**Override.** Users change tokens in config, or redefine any `--wrn-*` variable
in their own CSS (loaded after theme.css → wins). WrNexus UI components consume
`var(--wrn-*)`, so overriding a token restyles every component at once.
**Integration points:** `@wrnexus/styles` (theme module), `@wrnexus/ssr`
(`renderDocument` html attrs), dev runtime/assets, prod server, `wrnexus build`
@@ -270,7 +270,7 @@ disclosing policy structure to unauthenticated callers. This becomes opt-in via
## Build order
1. `registry.ts`, `catalog.ts`, `store.ts` (memory), `engine.ts`, extended `guards.ts`.
2. Resource-level policies wired to `filterAuthorized`; `audit.ts`.
2. Resource-level policies connected to `filterAuthorized`; `audit.ts`.
3. `db.ts` adapter, migrations, `wrnexus authz init`, codegen, `wrnexus authz list`.
4. `.wrn` view integration (`can()` inside `{#if}`).
5. Admin UI components.
@@ -3227,7 +3227,7 @@ export async function runAuthzCommand(
}
```
- [ ] **Step 4: Wire it into the CLI**
- [ ] **Step 4: WrNexus it into the CLI**
In `packages/cli/src/index.ts`, add immediately after the `case "db"` block:
@@ -3257,7 +3257,7 @@ git commit -m "feat(cli): add wrnexus authz list/generate/init"
---
## Task 14: Wire the catalog into dev and prod boot
## Task 14: WrNexus the catalog into dev and prod boot
**Files:**
@@ -3375,7 +3375,7 @@ git commit -m "feat(dev-server): load the authz catalog at boot"
---
## Task 15: Example app wiring and documentation
## Task 15: Example app integration and documentation
**Files:**
@@ -418,7 +418,7 @@ export class ServiceError extends Error {
}
/**
* Convert to a wire result. The message is replaced unless explicitly
* Convert to a wrn result. The message is replaced unless explicitly
* exposed: a handler's error text routinely names tables, hosts, or
* credentials, and this value crosses an app boundary.
*/
@@ -1296,7 +1296,7 @@ describe("implement", () => {
expect(result).toEqual({ ok: true, value: { sum: 3 } });
});
test("coerces through the schema rather than trusting the wire", async () => {
test("coerces through the schema rather than trusting the wrn", async () => {
// "3" arrives as a string over JSON from a sloppy caller; the schema coerces.
const result = await impl().invoke("add", { a: 1, b: "3" });
expect(result).toEqual({ ok: true, value: { sum: 4 } });
@@ -1360,7 +1360,7 @@ describe("implement", () => {
test("a guarded procedure with NO permission checker configured denies", async () => {
// Fail closed: a contract that declares a permission must not run
// unguarded just because the app forgot to wire a checker.
// unguarded just because the app forgot to wrn a checker.
const result = await impl(undefined).invoke("guarded", {});
expect(result.ok).toBe(false);
if (!result.ok) expect(result.code).toBe(RPC_ERROR_CODES.denied);
@@ -1439,7 +1439,7 @@ export interface ImplementOptions {
/** This app's name, used as the identity token's expected audience. */
selfApp: string;
/**
* Resolve whether the subject holds a permission. Wire this to
* Resolve whether the subject holds a permission. WrNexus this to
* `@wrnexus/authz`. A procedure that DECLARES a permission but finds no
* checker configured is denied — never run unguarded.
*/
@@ -2345,7 +2345,7 @@ export async function handleRpcRequest(
Run: `bun test packages/dev-server/test/rpc-endpoint.test.ts`
Expected: PASS, 9 tests
- [ ] **Step 5: Wire the dispatcher into the request pipeline**
- [ ] **Step 5: WrNexus the dispatcher into the request pipeline**
In `packages/dev-server/src/runtime.ts`, inside the main `fetch` handler, call `handleRpcRequest` BEFORE normal page/API routing and return its result when non-null. Build the `Map<string, ServiceImplementation>` from `router.services` at boot, importing each module's default export. Follow the pattern `loadAppAuthzCatalog` uses for importing discovered modules, including routing hot-reload re-imports through `loadModule`.
@@ -2411,7 +2411,7 @@ const billing = defineService({
},
});
function wire(allowed: boolean) {
function wrn(allowed: boolean) {
const service = implement(
billing,
{
@@ -2434,7 +2434,7 @@ describe("end to end", () => {
const client = serviceClient(billing, {
app: "billing",
as: { user: { id: "u1" }, tenant: { id: "acme" }, locals: {} } as unknown as Context,
transport: wire(true),
transport: wrn(true),
});
expect(await client.createInvoice({ amountCents: 250 })).toEqual({
invoiceId: "inv_250",
@@ -2448,7 +2448,7 @@ describe("end to end", () => {
const client = serviceClient(billing, {
app: "billing",
as: { user: { id: "u1" }, locals: {} } as unknown as Context,
transport: wire(false),
transport: wrn(false),
});
try {
await client.createInvoice({ amountCents: 1 });
@@ -2459,7 +2459,7 @@ describe("end to end", () => {
});
test("invalid input never reaches the handler", async () => {
const client = serviceClient(billing, { app: "billing", transport: wire(true) });
const client = serviceClient(billing, { app: "billing", transport: wrn(true) });
try {
await client.createInvoice({ amountCents: "abc" } as never);
throw new Error("should not reach here");
+3 -3
View File
@@ -1002,8 +1002,8 @@
"assertValidAst",
"compilationKey",
"compile",
"compileNativeWireFile",
"compileWireFile",
"compileNativeWrnFile",
"compileWrnFile",
"createCompilationCache",
"createComponentContract",
"createWrnSourceMap",
@@ -2620,7 +2620,7 @@
"ThemeTokens",
"activeThemeCssHref",
"auditCssPerformance",
"auditWireTokens",
"auditWrnTokens",
"bundleCss",
"contrast",
"defineConfig",
@@ -4,7 +4,7 @@
**Goal:** Ship runtime-owned roving arrow-key focus, then build Nav, Pagination and Stepper as real components on that foundation.
**Architecture:** One declarative attribute pair (`data-wrn-roving` on a container, `data-wrn-roving-item` on children) implements ARIA roving focus once in the reactive runtime, the same way modal dialog focus already lives there. The three components then declare intent with a single attribute instead of carrying five near-identical `@keydown` handlers. Each component uses a local `style {}` block with `wire-*` classes, declares its `outputs`, and takes props in / reports outputs out with no global state.
**Architecture:** One declarative attribute pair (`data-wrn-roving` on a container, `data-wrn-roving-item` on children) implements ARIA roving focus once in the reactive runtime, the same way modal dialog focus already lives there. The three components then declare intent with a single attribute instead of carrying five near-identical `@keydown` handlers. Each component uses a local `style {}` block with `wrn-*` classes, declares its `outputs`, and takes props in / reports outputs out with no global state.
**Tech Stack:** Bun, TypeScript, `.wrn` components, happy-dom for runtime tests, `@wrnexus/test` (`renderComponent`, `mountHtml`) for component tests.
@@ -456,10 +456,10 @@ test("pagination renders windowed page numbers and emits change", async () => {
siblingCount: 1,
});
const dom = mountHtml(html);
const root = dom.querySelector(".wire-pagination") as HTMLElement;
const root = dom.querySelector(".wrn-pagination") as HTMLElement;
expect(root.getAttribute("role")).toBe("navigation");
const current = dom.querySelector('.wire-pagination__page[aria-current="page"]');
const current = dom.querySelector('.wrn-pagination__page[aria-current="page"]');
expect(current!.textContent!.trim()).toBe("5");
expect(root.textContent).toContain("41");
expect(root.textContent).toContain("50");
@@ -478,7 +478,7 @@ test("pagination survives a non-array or empty dataset", async () => {
const source = readFileSync(uiComponentPath("Pagination"), "utf8");
const html = await renderComponent(source, { page: 1, pageSize: 10, total: 0 });
const dom = mountHtml(html);
expect(dom.querySelector(".wire-pagination")).not.toBeNull();
expect(dom.querySelector(".wrn-pagination")).not.toBeNull();
});
```
@@ -488,7 +488,7 @@ test("pagination survives a non-array or empty dataset", async () => {
bun test packages/ui -t "pagination"
```
Expected: FAIL — the scaffold has no `.wire-pagination` class and no page numbers.
Expected: FAIL — the scaffold has no `.wrn-pagination` class and no page numbers.
- [ ] **Step 3: Replace `packages/ui/components/Pagination.wrn`**
@@ -594,33 +594,33 @@ component Pagination {
<nav
{...attrs}
data-ui-component="Pagination"
class='wire-pagination {class}'
class='wrn-pagination {class}'
data-variant='{variant}'
role="navigation"
aria-label='{label}'
>
<p class="wire-pagination__summary" data-show="showSummary">
<p class="wrn-pagination__summary" data-show="showSummary">
{firstShown()} to {lastShown()} of {total}
</p>
<div class="wire-pagination__controls">
<div class="wrn-pagination__controls">
<button
type="button"
class="wire-pagination__step"
class="wrn-pagination__step"
aria-label='{previousLabel}'
@click='goPrevious()'
>
<span class="wire-pagination__step-icon" aria-hidden="true">&#8249;</span>
<span class="wire-pagination__step-label">{previousLabel}</span>
<span class="wrn-pagination__step-icon" aria-hidden="true">&#8249;</span>
<span class="wrn-pagination__step-label">{previousLabel}</span>
</button>
<ol class="wire-pagination__pages" data-show="variant === 'numbered'">
<ol class="wrn-pagination__pages" data-show="variant === 'numbered'">
{#each pageNumbers() as entry}
<li>
<span class="wire-pagination__gap" data-show="entry.gap">{entry.label}</span>
<span class="wrn-pagination__gap" data-show="entry.gap">{entry.label}</span>
<button
type="button"
class="wire-pagination__page"
class="wrn-pagination__page"
data-show="!entry.gap"
data-active='{entry.value === currentPage()}'
aria-current='{entry.value === currentPage() ? "page" : "false"}'
@@ -632,18 +632,18 @@ component Pagination {
{/each}
</ol>
<p class="wire-pagination__compact" data-show="variant !== 'numbered'">
<p class="wrn-pagination__compact" data-show="variant !== 'numbered'">
{currentPage()} / {lastPage()}
</p>
<button
type="button"
class="wire-pagination__step"
class="wrn-pagination__step"
aria-label='{nextLabel}'
@click='goNext()'
>
<span class="wire-pagination__step-label">{nextLabel}</span>
<span class="wire-pagination__step-icon" aria-hidden="true">&#8250;</span>
<span class="wrn-pagination__step-label">{nextLabel}</span>
<span class="wrn-pagination__step-icon" aria-hidden="true">&#8250;</span>
</button>
</div>
@@ -652,7 +652,7 @@ component Pagination {
}
style {
.wire-pagination {
.wrn-pagination {
display: flex;
flex-wrap: wrap;
align-items: center;
@@ -661,20 +661,20 @@ component Pagination {
max-width: 100%;
}
.wire-pagination__summary {
.wrn-pagination__summary {
margin: 0;
color: var(--wire-color-text-muted);
color: var(--wrn-color-text-muted);
font-size: 0.82rem;
}
.wire-pagination__controls {
.wrn-pagination__controls {
display: flex;
align-items: center;
gap: 0.35rem;
flex-wrap: wrap;
}
.wire-pagination__pages {
.wrn-pagination__pages {
display: flex;
align-items: center;
gap: 0.25rem;
@@ -683,8 +683,8 @@ component Pagination {
list-style: none;
}
.wire-pagination__page,
.wire-pagination__step {
.wrn-pagination__page,
.wrn-pagination__step {
appearance: none;
display: inline-flex;
align-items: center;
@@ -692,50 +692,50 @@ component Pagination {
min-width: 2.25rem;
justify-content: center;
padding: 0.4rem 0.6rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-sm);
background: var(--wire-color-surface);
color: var(--wire-color-text);
border: 1px solid var(--wrn-color-border);
border-radius: var(--wrn-radius-sm);
background: var(--wrn-color-surface);
color: var(--wrn-color-text);
font: inherit;
font-size: 0.85rem;
cursor: pointer;
}
.wire-pagination__page:hover,
.wire-pagination__step:hover {
background: var(--wire-color-surface-soft);
.wrn-pagination__page:hover,
.wrn-pagination__step:hover {
background: var(--wrn-color-surface-soft);
}
.wire-pagination__page[data-active="true"] {
border-color: var(--wire-color-primary);
background: var(--wire-color-primary);
color: var(--wire-color-primary-contrast);
.wrn-pagination__page[data-active="true"] {
border-color: var(--wrn-color-primary);
background: var(--wrn-color-primary);
color: var(--wrn-color-primary-contrast);
font-weight: 700;
}
.wire-pagination__gap {
.wrn-pagination__gap {
padding: 0 0.35rem;
color: var(--wire-color-text-muted);
color: var(--wrn-color-text-muted);
}
.wire-pagination__compact {
.wrn-pagination__compact {
margin: 0;
padding: 0 0.5rem;
color: var(--wire-color-text-muted);
color: var(--wrn-color-text-muted);
font-size: 0.85rem;
}
/* Below the small breakpoint the word labels crowd the arrows out. */
@media (max-width: 639px) {
.wire-pagination {
.wrn-pagination {
justify-content: center;
}
.wire-pagination__step-label {
.wrn-pagination__step-label {
display: none;
}
.wire-pagination__summary {
.wrn-pagination__summary {
width: 100%;
text-align: center;
}
@@ -816,14 +816,14 @@ test("stepper marks complete, current and upcoming steps", async () => {
active: 1,
});
const dom = mountHtml(html);
const items = [...dom.querySelectorAll(".wire-stepper__step")];
const items = [...dom.querySelectorAll(".wrn-stepper__step")];
expect(items).toHaveLength(3);
expect(items[0].getAttribute("data-status")).toBe("complete");
expect(items[1].getAttribute("data-status")).toBe("current");
expect(items[2].getAttribute("data-status")).toBe("upcoming");
expect(items[1].getAttribute("aria-current")).toBe("step");
expect(dom.querySelector(".wire-stepper")!.tagName.toLowerCase()).toBe("ol");
expect(dom.querySelector(".wrn-stepper")!.tagName.toLowerCase()).toBe("ol");
});
test("stepper renders vertically and clamps an out-of-range active index", async () => {
@@ -834,9 +834,9 @@ test("stepper renders vertically and clamps an out-of-range active index", async
orientation: "vertical",
});
const dom = mountHtml(html);
const root = dom.querySelector(".wire-stepper") as HTMLElement;
const root = dom.querySelector(".wrn-stepper") as HTMLElement;
expect(root.getAttribute("data-orientation")).toBe("vertical");
const items = [...dom.querySelectorAll(".wire-stepper__step")];
const items = [...dom.querySelectorAll(".wrn-stepper__step")];
expect(items[1].getAttribute("data-status")).toBe("current");
});
@@ -859,7 +859,7 @@ test("clickable stepper opts into roving focus", async () => {
bun test packages/ui -t "stepper"
```
Expected: FAIL — the scaffold renders a `<nav>` of anchors with no `.wire-stepper__step`.
Expected: FAIL — the scaffold renders a `<nav>` of anchors with no `.wrn-stepper__step`.
- [ ] **Step 3: Replace `packages/ui/components/Stepper.wrn`**
@@ -927,7 +927,7 @@ component Stepper {
<ol
{...attrs}
data-ui-component="Stepper"
class='wire-stepper {class}'
class='wrn-stepper {class}'
data-orientation='{orientation}'
data-clickable='{clickable}'
data-wrn-roving='{clickable ? (orientation === "vertical" ? "vertical" : "horizontal") : ""}'
@@ -935,28 +935,28 @@ component Stepper {
>
{#each stepList() as step, index}
<li
class="wire-stepper__step"
class="wrn-stepper__step"
data-status='{statusFor(index)}'
aria-current='{statusFor(index) === "current" ? "step" : "false"}'
>
<button
type="button"
class="wire-stepper__button"
class="wrn-stepper__button"
data-wrn-roving-item='{clickable}'
@click='selectStep(index, step)'
>
<span class="wire-stepper__marker" aria-hidden="true">
<span class='wire-stepper__icon {step.icon}' data-show="step.icon"></span>
<span class="wire-stepper__number" data-show="!step.icon">{index + 1}</span>
<span class="wrn-stepper__marker" aria-hidden="true">
<span class='wrn-stepper__icon {step.icon}' data-show="step.icon"></span>
<span class="wrn-stepper__number" data-show="!step.icon">{index + 1}</span>
</span>
<span class="wire-stepper__body">
<span class="wire-stepper__label">{step.label}</span>
<span class="wire-stepper__description" data-show="step.description">
<span class="wrn-stepper__body">
<span class="wrn-stepper__label">{step.label}</span>
<span class="wrn-stepper__description" data-show="step.description">
{step.description}
</span>
</span>
</button>
<span class="wire-stepper__custom">
<span class="wrn-stepper__custom">
<slot name="step-{index}"></slot>
</span>
</li>
@@ -966,7 +966,7 @@ component Stepper {
}
style {
.wire-stepper {
.wrn-stepper {
display: flex;
gap: 0.5rem;
margin: 0;
@@ -975,11 +975,11 @@ component Stepper {
max-width: 100%;
}
.wire-stepper[data-orientation="vertical"] {
.wrn-stepper[data-orientation="vertical"] {
flex-direction: column;
}
.wire-stepper__step {
.wrn-stepper__step {
display: flex;
flex-direction: column;
flex: 1 1 0;
@@ -987,7 +987,7 @@ component Stepper {
gap: 0.35rem;
}
.wire-stepper__button {
.wrn-stepper__button {
appearance: none;
display: flex;
align-items: center;
@@ -995,7 +995,7 @@ component Stepper {
width: 100%;
padding: 0.5rem;
border: 0;
border-radius: var(--wire-radius-sm);
border-radius: var(--wrn-radius-sm);
background: transparent;
color: inherit;
font: inherit;
@@ -1003,67 +1003,67 @@ component Stepper {
cursor: default;
}
.wire-stepper[data-clickable="true"] .wire-stepper__button {
.wrn-stepper[data-clickable="true"] .wrn-stepper__button {
cursor: pointer;
}
.wire-stepper[data-clickable="true"] .wire-stepper__button:hover {
background: var(--wire-color-surface-soft);
.wrn-stepper[data-clickable="true"] .wrn-stepper__button:hover {
background: var(--wrn-color-surface-soft);
}
.wire-stepper__marker {
.wrn-stepper__marker {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
width: 2rem;
height: 2rem;
border: 1px solid var(--wire-color-border);
border: 1px solid var(--wrn-color-border);
border-radius: 999px;
background: var(--wire-color-surface);
background: var(--wrn-color-surface);
font-size: 0.85rem;
font-weight: 700;
}
.wire-stepper__step[data-status="complete"] .wire-stepper__marker {
border-color: var(--wire-color-primary);
background: var(--wire-color-primary);
color: var(--wire-color-primary-contrast);
.wrn-stepper__step[data-status="complete"] .wrn-stepper__marker {
border-color: var(--wrn-color-primary);
background: var(--wrn-color-primary);
color: var(--wrn-color-primary-contrast);
}
.wire-stepper__step[data-status="current"] .wire-stepper__marker {
border-color: var(--wire-color-primary);
color: var(--wire-color-primary);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--wire-color-primary) 22%, transparent);
.wrn-stepper__step[data-status="current"] .wrn-stepper__marker {
border-color: var(--wrn-color-primary);
color: var(--wrn-color-primary);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--wrn-color-primary) 22%, transparent);
}
.wire-stepper__step[data-status="upcoming"] .wire-stepper__marker {
color: var(--wire-color-text-muted);
.wrn-stepper__step[data-status="upcoming"] .wrn-stepper__marker {
color: var(--wrn-color-text-muted);
}
.wire-stepper__body {
.wrn-stepper__body {
display: flex;
flex-direction: column;
min-width: 0;
}
.wire-stepper__label {
.wrn-stepper__label {
font-size: 0.9rem;
font-weight: 600;
}
.wire-stepper__description {
color: var(--wire-color-text-muted);
.wrn-stepper__description {
color: var(--wrn-color-text-muted);
font-size: 0.78rem;
}
.wire-stepper__step[data-status="upcoming"] .wire-stepper__label {
color: var(--wire-color-text-muted);
.wrn-stepper__step[data-status="upcoming"] .wrn-stepper__label {
color: var(--wrn-color-text-muted);
}
/* A horizontal stepper cannot stay side by side on a phone. */
@media (max-width: 639px) {
.wire-stepper {
.wrn-stepper {
flex-direction: column;
}
}
@@ -1163,11 +1163,11 @@ test("nav renders links, marks the active one, and shows icons and badges", asyn
});
const dom = mountHtml(html);
expect(dom.querySelector(".wire-nav")!.getAttribute("role")).toBe("navigation");
expect(dom.querySelector(".wrn-nav")!.getAttribute("role")).toBe("navigation");
const current = dom.querySelector('[aria-current="page"]');
expect(current!.textContent).toContain("Inbox");
expect(dom.querySelector(".wire-nav__badge")!.textContent!.trim()).toBe("9");
expect(dom.querySelector(".wire-nav__icon")).not.toBeNull();
expect(dom.querySelector(".wrn-nav__badge")!.textContent!.trim()).toBe("9");
expect(dom.querySelector(".wrn-nav__icon")).not.toBeNull();
expect(dom.querySelector('[aria-disabled="true"]')).not.toBeNull();
});
@@ -1194,10 +1194,10 @@ test("nav renders a submenu with a disclosure arrow and opts into roving focus",
expect(dom.querySelector("[data-wrn-roving]")).not.toBeNull();
expect(dom.querySelectorAll("[data-wrn-roving-item]").length).toBeGreaterThan(0);
expect(dom.querySelector(".wire-nav__arrow")).not.toBeNull();
expect(dom.querySelector(".wire-nav__submenu")).not.toBeNull();
expect(dom.querySelector(".wrn-nav__arrow")).not.toBeNull();
expect(dom.querySelector(".wrn-nav__submenu")).not.toBeNull();
// Third level is rendered, and nothing deeper is attempted.
expect(dom.querySelector(".wire-nav__submenu--level3")).not.toBeNull();
expect(dom.querySelector(".wrn-nav__submenu--level3")).not.toBeNull();
expect(dom.body.innerHTML).toContain("Deep");
});
@@ -1205,8 +1205,8 @@ test("nav renders empty rather than throwing when items is not an array", async
const source = readFileSync(uiComponentPath("Nav"), "utf8");
const html = await renderComponent(source, { items: "not-an-array", active: "" });
const dom = mountHtml(html);
expect(dom.querySelector(".wire-nav")).not.toBeNull();
expect(dom.querySelectorAll(".wire-nav__link").length).toBe(0);
expect(dom.querySelector(".wrn-nav")).not.toBeNull();
expect(dom.querySelectorAll(".wrn-nav__link").length).toBe(0);
});
```
@@ -1216,7 +1216,7 @@ test("nav renders empty rather than throwing when items is not an array", async
bun test packages/ui -t "nav "
```
Expected: FAIL — the scaffold renders bare anchors with no `.wire-nav__link`, no submenu and no roving attributes.
Expected: FAIL — the scaffold renders bare anchors with no `.wrn-nav__link`, no submenu and no roving attributes.
- [ ] **Step 3: Replace `packages/ui/components/Nav.wrn`**
@@ -1274,7 +1274,7 @@ component Nav {
<nav
{...attrs}
data-ui-component="Nav"
class='wire-nav {class}'
class='wrn-nav {class}'
data-orientation='{orientation}'
data-expanded='{expanded}'
role="navigation"
@@ -1282,24 +1282,24 @@ component Nav {
>
<button
type="button"
class="wire-nav__toggle"
class="wrn-nav__toggle"
data-show="collapsible"
aria-expanded='{expanded}'
aria-label='{toggleLabel}'
@click='toggleMenu()'
>
<span class="wire-nav__toggle-bar" aria-hidden="true"></span>
<span class="wire-nav__toggle-text">{toggleLabel}</span>
<span class="wrn-nav__toggle-bar" aria-hidden="true"></span>
<span class="wrn-nav__toggle-text">{toggleLabel}</span>
</button>
<ul
class="wire-nav__list"
class="wrn-nav__list"
data-wrn-roving='{orientation === "vertical" ? "vertical" : "horizontal"}'
>
{#each itemList() as item}
<li class="wire-nav__item" data-has-children='{childrenOf(item).length > 0}'>
<li class="wrn-nav__item" data-has-children='{childrenOf(item).length > 0}'>
<a
class="wire-nav__link"
class="wrn-nav__link"
href='{item.href || "#"}'
data-wrn-roving-item="true"
data-active='{isActive(item)}'
@@ -1307,53 +1307,53 @@ component Nav {
aria-disabled='{item.disabled ? "true" : "false"}'
@click='choose(item)'
>
<span class='wire-nav__icon {item.icon}' data-show="item.icon" aria-hidden="true"></span>
<span class="wire-nav__label">{item.label}</span>
<span class="wire-nav__badge" data-show="item.badge">{item.badge}</span>
<span class='wrn-nav__icon {item.icon}' data-show="item.icon" aria-hidden="true"></span>
<span class="wrn-nav__label">{item.label}</span>
<span class="wrn-nav__badge" data-show="item.badge">{item.badge}</span>
<span
class="wire-nav__arrow"
class="wrn-nav__arrow"
data-show="childrenOf(item).length > 0"
aria-hidden="true"
>&#8250;</span>
</a>
<ul class="wire-nav__submenu" data-show="childrenOf(item).length > 0">
<ul class="wrn-nav__submenu" data-show="childrenOf(item).length > 0">
{#each childrenOf(item) as child}
<li class="wire-nav__item" data-has-children='{childrenOf(child).length > 0}'>
<li class="wrn-nav__item" data-has-children='{childrenOf(child).length > 0}'>
<a
class="wire-nav__link"
class="wrn-nav__link"
href='{child.href || "#"}'
data-active='{isActive(child)}'
aria-current='{isActive(child) ? "page" : "false"}'
aria-disabled='{child.disabled ? "true" : "false"}'
@click='choose(child)'
>
<span class='wire-nav__icon {child.icon}' data-show="child.icon" aria-hidden="true"></span>
<span class="wire-nav__label">{child.label}</span>
<span class="wire-nav__badge" data-show="child.badge">{child.badge}</span>
<span class='wrn-nav__icon {child.icon}' data-show="child.icon" aria-hidden="true"></span>
<span class="wrn-nav__label">{child.label}</span>
<span class="wrn-nav__badge" data-show="child.badge">{child.badge}</span>
<span
class="wire-nav__arrow"
class="wrn-nav__arrow"
data-show="childrenOf(child).length > 0"
aria-hidden="true"
>&#8250;</span>
</a>
<ul
class="wire-nav__submenu wire-nav__submenu--level3"
class="wrn-nav__submenu wrn-nav__submenu--level3"
data-show="childrenOf(child).length > 0"
>
{#each childrenOf(child) as leaf}
<li class="wire-nav__item">
<li class="wrn-nav__item">
<a
class="wire-nav__link"
class="wrn-nav__link"
href='{leaf.href || "#"}'
data-active='{isActive(leaf)}'
aria-current='{isActive(leaf) ? "page" : "false"}'
aria-disabled='{leaf.disabled ? "true" : "false"}'
@click='choose(leaf)'
>
<span class='wire-nav__icon {leaf.icon}' data-show="leaf.icon" aria-hidden="true"></span>
<span class="wire-nav__label">{leaf.label}</span>
<span class='wrn-nav__icon {leaf.icon}' data-show="leaf.icon" aria-hidden="true"></span>
<span class="wrn-nav__label">{leaf.label}</span>
</a>
</li>
{/each}
@@ -1370,11 +1370,11 @@ component Nav {
}
style {
.wire-nav {
.wrn-nav {
max-width: 100%;
}
.wire-nav__list {
.wrn-nav__list {
display: flex;
align-items: center;
gap: 0.25rem;
@@ -1383,61 +1383,61 @@ component Nav {
list-style: none;
}
.wire-nav[data-orientation="vertical"] .wire-nav__list {
.wrn-nav[data-orientation="vertical"] .wrn-nav__list {
flex-direction: column;
align-items: stretch;
}
.wire-nav__item {
.wrn-nav__item {
position: relative;
}
.wire-nav__link {
.wrn-nav__link {
display: flex;
align-items: center;
gap: 0.45rem;
padding: 0.45rem 0.7rem;
border-radius: var(--wire-radius-sm);
color: var(--wire-color-text-muted);
border-radius: var(--wrn-radius-sm);
color: var(--wrn-color-text-muted);
font-size: 0.9rem;
font-weight: 600;
text-decoration: none;
}
.wire-nav__link:hover {
background: var(--wire-color-surface-soft);
color: var(--wire-color-text);
.wrn-nav__link:hover {
background: var(--wrn-color-surface-soft);
color: var(--wrn-color-text);
}
.wire-nav__link[data-active="true"] {
background: var(--wire-color-primary-soft);
color: var(--wire-color-primary);
.wrn-nav__link[data-active="true"] {
background: var(--wrn-color-primary-soft);
color: var(--wrn-color-primary);
}
.wire-nav__link[aria-disabled="true"] {
.wrn-nav__link[aria-disabled="true"] {
opacity: 0.5;
pointer-events: none;
}
.wire-nav__badge {
.wrn-nav__badge {
padding: 0.05rem 0.4rem;
border-radius: 999px;
background: var(--wire-color-primary-soft);
color: var(--wire-color-primary);
background: var(--wrn-color-primary-soft);
color: var(--wrn-color-primary);
font-size: 0.72rem;
}
.wire-nav__arrow {
.wrn-nav__arrow {
display: inline-block;
transition: transform 160ms ease;
}
.wire-nav__item:hover > .wire-nav__link > .wire-nav__arrow,
.wire-nav__item:focus-within > .wire-nav__link > .wire-nav__arrow {
.wrn-nav__item:hover > .wrn-nav__link > .wrn-nav__arrow,
.wrn-nav__item:focus-within > .wrn-nav__link > .wrn-nav__arrow {
transform: rotate(90deg);
}
.wire-nav__submenu {
.wrn-nav__submenu {
position: absolute;
z-index: 30;
top: 100%;
@@ -1445,42 +1445,42 @@ component Nav {
min-width: 12rem;
margin: 0;
padding: 0.35rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-md);
background: var(--wire-color-surface);
box-shadow: var(--wire-shadow-1);
border: 1px solid var(--wrn-color-border);
border-radius: var(--wrn-radius-md);
background: var(--wrn-color-surface);
box-shadow: var(--wrn-shadow-1);
list-style: none;
opacity: 0;
visibility: hidden;
transition: opacity 160ms ease;
}
.wire-nav__item:hover > .wire-nav__submenu,
.wire-nav__item:focus-within > .wire-nav__submenu {
.wrn-nav__item:hover > .wrn-nav__submenu,
.wrn-nav__item:focus-within > .wrn-nav__submenu {
opacity: 1;
visibility: visible;
}
.wire-nav__submenu--level3 {
.wrn-nav__submenu--level3 {
top: 0;
left: 100%;
}
.wire-nav__toggle {
.wrn-nav__toggle {
display: none;
align-items: center;
gap: 0.5rem;
padding: 0.45rem 0.7rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-sm);
background: var(--wire-color-surface);
color: var(--wire-color-text);
border: 1px solid var(--wrn-color-border);
border-radius: var(--wrn-radius-sm);
background: var(--wrn-color-surface);
color: var(--wrn-color-text);
font: inherit;
font-size: 0.9rem;
cursor: pointer;
}
.wire-nav__toggle-bar {
.wrn-nav__toggle-bar {
width: 1rem;
height: 2px;
background: currentColor;
@@ -1493,21 +1493,21 @@ component Nav {
* unreachable on touch.
*/
@media (max-width: 767px) {
.wire-nav__toggle {
.wrn-nav__toggle {
display: inline-flex;
}
.wire-nav__list {
.wrn-nav__list {
flex-direction: column;
align-items: stretch;
}
.wire-nav[data-expanded="false"] .wire-nav__list {
.wrn-nav[data-expanded="false"] .wrn-nav__list {
display: none;
}
.wire-nav__submenu,
.wire-nav__submenu--level3 {
.wrn-nav__submenu,
.wrn-nav__submenu--level3 {
position: static;
opacity: 1;
visibility: visible;
@@ -1656,7 +1656,7 @@ git push
## Self-Review
**Spec coverage for phase 1.** Roving focus in the runtime — Task 1. Nav multi-level to depth 3, icons, badges, animated arrows, responsive collapse, `aria-current` — Task 5. Pagination standalone with compact and numbered variants and windowed numbers — Task 3. Stepper horizontal/vertical with indexed named slots and `aria-current="step"` — Task 4. Local `style {}` blocks with `wire-*` classes — Tasks 3, 4, 5. Error handling for non-array `items` and out-of-range `active`/`page` — covered by a test in each of Tasks 3, 4, 5. Showcase profiles and regeneration — Tasks 36. Runtime budget check — Tasks 1 and 6.
**Spec coverage for phase 1.** Roving focus in the runtime — Task 1. Nav multi-level to depth 3, icons, badges, animated arrows, responsive collapse, `aria-current` — Task 5. Pagination standalone with compact and numbered variants and windowed numbers — Task 3. Stepper horizontal/vertical with indexed named slots and `aria-current="step"` — Task 4. Local `style {}` blocks with `wrn-*` classes — Tasks 3, 4, 5. Error handling for non-array `items` and out-of-range `active`/`page` — covered by a test in each of Tasks 3, 4, 5. Showcase profiles and regeneration — Tasks 36. Runtime budget check — Tasks 1 and 6.
Out of phase 1 by design, carried to later plans: Tabs, Sidebar, MegaMenu (phase 2); Navbar, Breadcrumb, Scrollspy, responsive sweep (phase 3).
@@ -14,7 +14,7 @@ Stepper has no steps or progress, Pagination has no pages.
Of the remaining four, Breadcrumb is genuinely built (323 lines, own style
block). Navbar and Sidebar render but have no keyboard handling and keep their
styles in `ui.css`. Tabs works but is off-pattern in three ways: it is the only
component in the library using Tailwind utility classes rather than `wire-*` +
component in the library using Tailwind utility classes rather than `wrn-*` +
a local style block, it has no `outputs` block and fires raw `CustomEvent`s via
`dispatchEvent`, and it sets a roving `tabindex` with no `@keydown` handler at
all — which is worse than having no keyboard support, because the roving
@@ -28,7 +28,7 @@ All nine components, delivered in three phases.
### Styling
Every navigation component gets a local `style {}` block using `wire-*`
Every navigation component gets a local `style {}` block using `wrn-*`
classes. This matches DataTable, Toaster, Modal, Drawer, ContextMenu and
Breadcrumb — the 22 of 108 components that carry local styles are exactly the
recently built ones. Navbar and Sidebar styles move out of `ui.css` as part of
@@ -116,7 +116,7 @@ scroll lock rather than duplicating them.
| Component | Work |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Nav | Build. Flat or multi-level (3 deep), horizontal/vertical, `items[{label,href,value,icon,badge,disabled,items}]`, `aria-current="page"`, roving focus, animated arrows, collapses on mobile. `outputs: select` |
| Tabs | Rewrite off Tailwind onto `wire-*` + local styles. Real `outputs {change, select}` replacing raw `dispatchEvent`. Roving + Home/End. `mode="client"\|"url"`. Panel transition. Fix the `<slot>` that renders regardless of active tab |
| Tabs | Rewrite off Tailwind onto `wrn-*` + local styles. Real `outputs {change, select}` replacing raw `dispatchEvent`. Roving + Home/End. `mode="client"\|"url"`. Panel transition. Fix the `<slot>` that renders regardless of active tab |
| Pagination | Build standalone. `page`/`pageSize`/`total`, compact + numbered styles, windowed page numbers. `outputs: change, previous, next` |
| Stepper | Build. `<ol>`/`<li>`, status derived from `active` index, horizontal/vertical, optionally clickable, `aria-current="step"`. Indexed named slots (`data-slot="step-0"`, `step-1`, …) for custom per-step content, falling back to built-in rendering |
| MegaMenu | Build. Trigger plus a single-level panel of link columns. Panel marked `data-wrn-anchored` so the existing clamp handles viewport containment. Hover and focus open, Escape closes, click-outside closes |
@@ -10,7 +10,7 @@ Two problems, in different proportions to the navigation group.
**Three components advertise behaviour they do not have.**
`LayoutSplitter` is the worst component in the library. It declares
`resizeStart`, `resize` and `resizeEnd`, so a caller reasonably wires up
`resizeStart`, `resize` and `resizeEnd`, so a caller reasonably connects up
`@resize` and receives nothing, forever, with no error. It has no pointer
handling at all, and its props are `columns`, `gap` and `maxWidth`, copied
wholesale from a grid scaffold. `CustomScrollbar` is the same shape: a
@@ -22,9 +22,9 @@ genuinely does not need more. It is thin, not dishonest.
**Most of the group is built on Tailwind utilities.**
Seven of the ten use utility classes and `class:` conditionals rather than
`wire-*` classes and a local style block. They are theme-aware, because the
`wrn-*` classes and a local style block. They are theme-aware, because the
utilities carry arbitrary values bound to tokens
(`bg-[var(--wire-color-surface-soft)]`), but they depend on Tailwind being
(`bg-[var(--wrn-color-surface-soft)]`), but they depend on Tailwind being
present and produce a class explosion. `SectionHeader` has 38 such lines.
A correction that shaped this survey: when Tabs was rewritten it was described
@@ -50,7 +50,7 @@ audit rather than a rewrite.
### Styling
Every component in scope moves to `wire-*` classes with a local `style {}`
Every component in scope moves to `wrn-*` classes with a local `style {}`
block and `data-*` attributes for variants, matching PageHeader, DataTable,
Toaster and the navigation group.
@@ -95,7 +95,7 @@ something: `axis`, `thickness`, `thumb`, `track`, `maxHeight`.
### Kbd
Left as it is, beyond the `wire-*` migration. It is thin because a `<kbd>`
Left as it is, beyond the `wrn-*` migration. It is thin because a `<kbd>`
is thin.
### Runtime budget
+8 -8
View File
@@ -9,14 +9,14 @@ rebuilt. Numbers come from the source and from a browser, not from estimates.
property does not warn — it resolves to nothing — so the styles that used them
silently did nothing:
| Token | Effect while undefined |
| ----------------------------- | --------------------------------------------------------- |
| `--wire-color-focus` | Focus rings drew with no colour, in 14 components |
| `--wire-color-surface-soft` | Every soft surface rendered transparent, in 27 components |
| `--wire-color-on-danger` | Text on danger fills had no colour |
| `--wire-color-surface-subtle` | Subtle panels rendered transparent |
| `--wire-color-input-*` (6) | Input backgrounds, borders and placeholders unstyled |
| `*-hover`, `*-contrast` | Missing for info, success, warning and danger |
| Token | Effect while undefined |
| ---------------------------- | --------------------------------------------------------- |
| `--wrn-color-focus` | Focus rings drew with no colour, in 14 components |
| `--wrn-color-surface-soft` | Every soft surface rendered transparent, in 27 components |
| `--wrn-color-on-danger` | Text on danger fills had no colour |
| `--wrn-color-surface-subtle` | Subtle panels rendered transparent |
| `--wrn-color-input-*` (6) | Input backgrounds, borders and placeholders unstyled |
| `*-hover`, `*-contrast` | Missing for info, success, warning and danger |
They are derived in the theme now, so they follow the palette and the accent.
Verified in a browser: 38 tokens referenced, **0 undefined** (was 10).
+104 -104
View File
@@ -2,109 +2,109 @@
"schemaVersion": 1,
"releaseLine": "0.8",
"artifacts": {
"packages/ui/components/Accordion.wrn": "6532417153592cf60ab437a3b4e500176b14394dd66756d47df087d8c4f863ef",
"packages/ui/components/AdvancedSelect.wrn": "c3779c89ce309de8c1e2fbc02a39472fffd6fb10c2b83db0104c6d1135b87082",
"packages/ui/components/AnnouncementBar.wrn": "903bfd9421a7350c923ace3315cedc5763fe3e6b7b54b660a0f26281d46a8754",
"packages/ui/components/AuthForm.wrn": "bb5ac1ac8d981d490652eba5d4edf3612980470aa8b94bf4995cec1aa2db4bfc",
"packages/ui/components/AuthSplitLayout.wrn": "2a04cabb8bf2bda8739e2aba6dcfd29713efa7b51777f99b03dad1645b6ddae1",
"packages/ui/components/AvatarGroup.wrn": "737cd929e3bcd9f9b2fe1b602ae17c1fbf584bd8a1949ce36b65427931e27abc",
"packages/ui/components/BackToTop.wrn": "b12c56ec8b7aabad68cbdc47f4b3237e2c21a61398f0aa51f9add6229b7357cd",
"packages/ui/components/Blockquote.wrn": "70bb7f0da2743a44d38d38daebe09637c2653ccb8454d78a226c034cfece31d6",
"packages/ui/components/Breadcrumb.wrn": "5ab85d273ce72e4d5b87907975bb33f0249a34f2f87f01dc0812e827f775eed9",
"packages/ui/components/ButtonGroup.wrn": "be6675ae06b9f3285187e04d8d3312cf14cf4d24fe9bc0f78b2f796b6819ff69",
"packages/ui/components/CTASection.wrn": "2d2241d4f1018cfd2f8ea1ddd5fa8c8fcb8d1bbb2d4e4498cb9f39ff47a3801c",
"packages/ui/components/Card.wrn": "db5f313be0d057dac8c2d693574d15a146296c0aec6e41ec58b96966e45186d5",
"packages/ui/components/Carousel.wrn": "72e216882e3d1d744edd0d7697ce5810353a7cc0c386022452546bd959ff351d",
"packages/ui/components/Chart.wrn": "d2cedd0e02818d0908708c2d07a495c629fad13fa021a2e035d5023dc5c367de",
"packages/ui/components/ChatBubble.wrn": "c7c0ffcf732161330cc7fba79775ac829264b16731c980d3ec0820fc3ac8f9a7",
"packages/ui/components/Clipboard.wrn": "03fcfb9786008fd7fb0a7719c3279711253afc5bbb9b0262b805dd553c44da8a",
"packages/ui/components/Collapse.wrn": "90220ce36529d2b44bc45b1b265373462b5871a4e492be127f52743fa0619b0b",
"packages/ui/components/ColorPicker.wrn": "602752f2ad7f6b092987ccae9c35a0a413a6261d63d6e88f279ee939d0ec4049",
"packages/ui/components/Columns.wrn": "e01496aa53025444cc51671efcce40d6d24d86775b2cbb1ee0def1862bb6315d",
"packages/ui/components/Combobox.wrn": "78c97205f42f015d22dd58018641bbd6b0d9cba55b1138af5c9d1da8d1095202",
"packages/ui/components/Confetti.wrn": "b9aece64735c721c24356122e52ca84602d9f646c7d8be1e0b80d9de3163a501",
"packages/ui/components/Container.wrn": "4a0acbb896f4c11714e3925d912b10ef9aeedfa904b4ad8561aa2cbd9a0fdca0",
"packages/ui/components/ContextMenu.wrn": "33fb0f60268b12411d66e3031dc0557cb231149e7a8d83340b4b453a6e37cb09",
"packages/ui/components/CustomScrollbar.wrn": "fedb2ab06cc2cf9499c130590945ca6971a3edfb60407b6658ef7756e4be9823",
"packages/ui/components/DataMap.wrn": "553677298a28cced00c419fe35dff3d989a8b6d829cadad6e563d4a63a02581e",
"packages/ui/components/DataTable.wrn": "cfc3bb9110ccd1aa38b85fd74995180b6b82c177d0bbd6dcce99d56c99cc6e5b",
"packages/ui/components/DatePicker.wrn": "0c63bc72951961105529c4ebdc1064c22f44d0ce5fc8b813df7554280c7b1ad0",
"packages/ui/components/DeviceFrame.wrn": "b76a0c820278ac7df5c07702b5d95e764ce0ebfcf7d4f89a8b629df8ecafee11",
"packages/ui/components/Divider.wrn": "f5cc449611022b3d3eedf982ae48f6b1a289db7855cc9b6ea0248dcda807ffb3",
"packages/ui/components/DragAndDrop.wrn": "4c01e56b5f7734b50dbff57157e0fbf163667b8e8a8fc50e1907e77a87f69c51",
"packages/ui/components/Drawer.wrn": "e6e2778e515361a3475439ab91b6efec3895efab2a4dfdcfb535713f656cc7ed",
"packages/ui/components/Dropdown.wrn": "627319de0f555f0f07f80e19a59f9fd52e7f74af7cf2cf9ff09e114678ad9eb8",
"packages/ui/components/FeatureCard.wrn": "2a1bfb01cec8a9892d3ff066e48c276fa7c548cb59c15bcd9b4bbf85450a07a2",
"packages/ui/components/FeatureGrid.wrn": "3b4539ad3a5f93deb1ff29a98118dd8fa53cce1dd8433f7662d907019c04df37",
"packages/ui/components/FeatureIconCard.wrn": "620f66a36ca5c8ad8f2ea09e94dc4471e4146189c42149e9d31db58501281639",
"packages/ui/components/FileInput.wrn": "2cc422b2dc9d28b1c7ec8d83aa76ba8ddc2a83eb1d57f940fe320f6c4581c4b8",
"packages/ui/components/FileUploadProgress.wrn": "185715b5c9cf6a285cdae2c17b54d4136faf7779c7841ad89e346397f61dad73",
"packages/ui/components/Footer.wrn": "71790c99e4b15a62fdaf4b7a65d7016ca427408b62a2b1c7695ef1b39ba29440",
"packages/ui/components/Grid.wrn": "d089d8657298b4d33993ba4bf7b581f816c65db513d8e48cf1fdd18da19e05a8",
"packages/ui/components/Hero.wrn": "e4e39dcd59c273192c7e4136f6583279e20b0956bcba4cfbc3f6e01a1fade152",
"packages/ui/components/HeroActions.wrn": "77f69085db73b946c00aa684d50fb5ae474684e440e81edbccfd8ef5dc357e33",
"packages/ui/components/Image.wrn": "8113441bf90ab0d1d8618d477125ad339021f39e853db89d656c72c492e7a20b",
"packages/ui/components/InputGroup.wrn": "dc8d9bf4ed4fa7eb1b81c2d7dc443fc4a2cef1f7cd4acceee06618c8d1faa61b",
"packages/ui/components/InputNumber.wrn": "0ec020084f3e556d438f8264d61f836cfab4951c52d4df60e4944fb734fb38a9",
"packages/ui/components/Kbd.wrn": "5afaabbb15902bd8fb82cb4155cf6cbfff55600927b54d564d27e2dd8b752386",
"packages/ui/components/LayoutSplitter.wrn": "6bd6812e364420ed5d3439862116c58d0b011b298679005795bdccdbb7455066",
"packages/ui/components/LegendIndicator.wrn": "830a79bcda542b372c8e5164651d2e6f6192beeca73a64fb2e31adb25cb0ee16",
"packages/ui/components/Link.wrn": "b986abcc66bc0b1c6296f3ff4e560812e35d89cc680d5251d7a3883e68c1d053",
"packages/ui/components/List.wrn": "9bfa9613f388e5b126fc27d505e8165d7aa4a058e72132b755585464e116490e",
"packages/ui/components/ListGroup.wrn": "94d1887e74992e0ad8fc204c9b37c2888ed19ee796c62ab04aae34eef1e6c6d0",
"packages/ui/components/Map.wrn": "9023a7a188480b24222a3910d26f6926918470369a1ab610f841c31a6120b9aa",
"packages/ui/components/MarketingSectionHeader.wrn": "6f89a3b298ea299db686ddf903f92c4fe5d321719213943b16be82ba36c23302",
"packages/ui/components/Marquee.wrn": "2a88c8bd8378469add26b0d937adccac4aa9f2c2005393010298e8e4fa89693e",
"packages/ui/components/MegaMenu.wrn": "8a9a9b348ca1c5e182914ff55d981a91f47a49c52ef5e5efd8e4cb6e56361a43",
"packages/ui/components/MetricCard.wrn": "6451182739298691908f68258c0250cce2a78b0dc27c97115579ece30d7d9f92",
"packages/ui/components/MetricGrid.wrn": "6018a98c10628ed240ed236ed916c0ff60994d192c3aadafd10bc876be0f9364",
"packages/ui/components/Modal.wrn": "59d4ae9d6dd2700692d9edecfe53ee868e9f864363a4885961d1813cb2bee51f",
"packages/ui/components/Nav.wrn": "7dc456b879e9248bde267b986cdcb138b8f3127d98b51e27bc9708129953f5e2",
"packages/ui/components/Navbar.wrn": "4f55470827c7a36062db82c495bf646f6bb428b75ba331e5a932e21f940476ea",
"packages/ui/components/PageHeader.wrn": "59264dfb26a132fd3eb265c4374f9fcae781f30dd94a087c57e6e8256717cf14",
"packages/ui/components/Pagination.wrn": "9ceb74745b159150b015bbbb1974c68e14a7d4b92bd03491cb23b8855aa07983",
"packages/ui/components/PinInput.wrn": "dff3c69e2b5b2ee39f97a2c54ec6e36becd46bdc9b636a9ec249201b7d606d5a",
"packages/ui/components/Popover.wrn": "f2996f00fad3e35fba2d48e70af17f592854eb73b9e8c6a83526aa78c4e41293",
"packages/ui/components/PortalDashboard.wrn": "ed1713879ab6911920d641111885254e747081c54eb64e9305eda23272318e44",
"packages/ui/components/PreferenceSwitcher.wrn": "5daf957dd91ab3acd5f2e16d8c717cc7938ef6fa41ea0b60e0561cf06aa146d2",
"packages/ui/components/PublicPageShell.wrn": "369b74f65e27227311a2ed73e9ca56c8b60908100d6840a798e8ba5f2c8b1040",
"packages/ui/components/RangeSlider.wrn": "97e77a1ba628d43b8585bc27d14167d5743ae8f435398fb7bcead50fe07dfc9b",
"packages/ui/components/Rating.wrn": "959063a3a912d5f9247f851ceb882d7df986f8cd6e1893304224a59be6f88481",
"packages/ui/components/Scrollspy.wrn": "76d1c17580c8d460f1222ce97585bdcac9779141f2f30d5460c84ff9f75413d8",
"packages/ui/components/SearchBox.wrn": "717f7647fabd762f8ed60a7c3306eac3ddb83c0da292a53c76d91886c2b8f94f",
"packages/ui/components/Section.wrn": "33eb8a82a2102229c2b1f64cec497e9e8e70b67adab8dbe396be860fccbb699c",
"packages/ui/components/SectionHeader.wrn": "8eecf2ea7a93139512260e3d46ca2a1afeb341b8bd46b7c30baa6e2c75e25d10",
"packages/ui/components/Sidebar.wrn": "03f1bbce75ca6d50ed940e62df39c539610e89eadd2064fe24abc7d5470f98bf",
"packages/ui/components/SplitHero.wrn": "70e843565ff869bcf413b11b6d9830b2e2bd229863a00904596f71e2dff0e76d",
"packages/ui/components/StatsBar.wrn": "c7d1df3895f25b6d3a2e1012a18b97592c7f33e65418b880d486f20c2d490686",
"packages/ui/components/Stepper.wrn": "df9093e4222ef3250963a8c6fbfec74477242735d23eabe896c29731c54fc14d",
"packages/ui/components/StrongPassword.wrn": "a89d82649983e4b251babe69ff85f3f9623ad7c230c7ef74883749e646f43cf4",
"packages/ui/components/StyledIcon.wrn": "ef3406d097cc9967f0f7d8d5f66108de4c78b453b47cc0c6627630d455acc9fa",
"packages/ui/components/Tabs.wrn": "e38336d28876caa4e97da32a569749e3803b030284a85ce9f35fa788e51cc5b0",
"packages/ui/components/TextLink.wrn": "6e18906337cd3d30c2a0122593d249bde8f7cedc697b90ae388e2bd0e8eff3e1",
"packages/ui/components/TimePicker.wrn": "3b5bc1c380bb4d3569863ed783a8d8f94f7a5fa8948f4bda54f48b828a15ab52",
"packages/ui/components/Timeline.wrn": "686a37ebc62732842846d004491336970db94945bca942f226097d863e159d1c",
"packages/ui/components/Toaster.wrn": "288b2b370f65bf823e8d2a6f8c8cf66972332b8174303d33ebe8546d5e1d52c4",
"packages/ui/components/ToggleCount.wrn": "a17440af5d52be0ce59655bb61565a89832fe41f950f115da1da0abfaa86dea3",
"packages/ui/components/TogglePassword.wrn": "a4546b6825533efc6b010a095583da1664f8b63a28718bfab71609c4136aeeb5",
"packages/ui/components/TreeView.wrn": "c354fce9c5e81fed6eec4089dfd2a7f6bb84eb189c94efc88e00251efdc12c0b",
"packages/ui/components/Typography.wrn": "1b4d1b91dee0ff522d27c566becc3bc49bd9ec979ae6334e6a15fca5d88eccac",
"packages/ui/components/WysiwygEditor.wrn": "5535de685d70514651da061698eafc954c5dfea6de944e0c852c456c2d489df1",
"packages/ui/components/alert.wrn": "490a6f5b311b22ca5d630639c831b325b6918b2dd5440a242749f90af59f8b13",
"packages/ui/components/avatar.wrn": "78f602b031eb1de2db588dbcb83bbbbb9c52bef2c1c6a4a905276c3ec3e78119",
"packages/ui/components/badge.wrn": "7049be83eab9c909f2efc39cbbb5dae4aba3a6be2051b9271b92892a6438ad93",
"packages/ui/components/button.wrn": "da1660c671daf2feffe1024203ac1a8bc947beb07691bef595c1552c664b9cde",
"packages/ui/components/checkbox.wrn": "6e055207275294fd2390671dfa6c16db2bae692422f38689adad282601d04539",
"packages/ui/components/input.wrn": "5c7c2a8e2334e8c2c966a70ec4c4140ddd99a9084b9f7e2de630152bb3f2d8a4",
"packages/ui/components/progress.wrn": "61b01ba575d35691e3dfebfcb03ccd1c6b79f1df1c0d41857ec3b01944081a5d",
"packages/ui/components/radio.wrn": "f5ec1cab84c0d1b5e75133c44ce2220cd3ae5ad16a72d04c6b92b2482b9bf8b8",
"packages/ui/components/select.wrn": "0a15a19f17e3f9565d8370eab1b97f1ec7299c4e248d80d64e63897fe6ff1c0e",
"packages/ui/components/skeleton.wrn": "dda95a2c59c6060ab2b9f916eb046fbe74a68b398a051afc0bde41808e059c3a",
"packages/ui/components/spinner.wrn": "ffbd28ec6fc017fc94c67778f8966eab2eefa3b47f3f27f064c77dbeb65d84c1",
"packages/ui/components/switch.wrn": "9d3892f7a800e0fd98f39c3205eeb96a416f8a1d6834d11678a4c8abf9ee5d71",
"packages/ui/components/textarea.wrn": "dc6f079201c06caaa0ca01b65c5efe80ec4a0b50fecac9726ac3e5a8256c4f16",
"packages/ui/components/tooltip.wrn": "40028dfbb17f6725c76c2e091af9c30ea4db6aa4dea919d38f53874ea70315d1",
"packages/ui/styles/SelectStyles.wrn": "2c45e9c04678aaff76632e908b3c061410be0d6999a54a9203a39a3817d698f2",
"packages/ui/ui.css": "b7e2ae796ffbb738451364f63fce13022a81d81207f7e49c7f6220d24c36acd9"
"packages/ui/components/Accordion.wrn": "09251f76a2f9385e97eb67e06c0cf868e1771ac5f420647221bec5160287034b",
"packages/ui/components/AdvancedSelect.wrn": "b952b894a5b35050fc2f6e43c4182101eeee05c75662e2aca4abfe61512b305b",
"packages/ui/components/AnnouncementBar.wrn": "cb66b8d0619ee798a115b43f0ad93fda93dfb46571589e7a9f0a8d65ec3c84c9",
"packages/ui/components/AuthForm.wrn": "46a3e1db1c9e69efc52473cbf2fababdcbfe7144e7571469638d2c3addd4d7f0",
"packages/ui/components/AuthSplitLayout.wrn": "724938921bc38cc5a0422de69c237b630f099f2df94c66977362b048e4a420a5",
"packages/ui/components/AvatarGroup.wrn": "30b702e06a1adff8b9bae32820206020e086a69560cbdcbadb19f04f25951f97",
"packages/ui/components/BackToTop.wrn": "5b760ec7941ffd8e58c5dedae1b322ee46e072e927533d7ec077b511a816e436",
"packages/ui/components/Blockquote.wrn": "3761bf13babb6eb07ce7392258ee439ef5478064cf589eff63f945b950e00d2e",
"packages/ui/components/Breadcrumb.wrn": "9f6c23550ebfc635c36ca8660953775170b4a471c0cd0206b9a7ba760994980a",
"packages/ui/components/ButtonGroup.wrn": "fc23565ad56bd8483fcb777d9e02ccba2f9ea476c085754d42503bb83b718f72",
"packages/ui/components/CTASection.wrn": "d0665f2aa33eea95e6f84120f739b3dd9c8723c882138bcb1a7f80dcd7909904",
"packages/ui/components/Card.wrn": "255912df0668ebcf45b6cc3ffe99a4a3e0bf87376a5d199e3adcdf3610ea79e3",
"packages/ui/components/Carousel.wrn": "7ab122bc0ce772346c665b43d62e73c9865a13b97c02ccf5b03d1e3eaea757d6",
"packages/ui/components/Chart.wrn": "07bc01247b5a1c2b82c2ba8386b7fcdbf480efead75d52b7da04d471072c7ee4",
"packages/ui/components/ChatBubble.wrn": "d71f7d6567d76ac0eb3ecc8e2e567fec12bb3236ea05f4d0a72286abc0b7cbb1",
"packages/ui/components/Clipboard.wrn": "5a93f2bae337d7ce364229b796bac673f60dde6dc135f0969f4e106e04854d30",
"packages/ui/components/Collapse.wrn": "26df087a61c82f1aa1749785f4c9be654c4f934859c1a47acfcb8cc67eecc75d",
"packages/ui/components/ColorPicker.wrn": "557e36adbdee66d8ba9dcdc2446c13f3385a243f2766777feef8504908006c99",
"packages/ui/components/Columns.wrn": "8ccd9e53f6799b09f8b996740d12e4e73ee782f6fd3e57595c6c16f788b9b812",
"packages/ui/components/Combobox.wrn": "58488dbb60e41dacbf223afdb4a05abdbec53b7f54cd79a0db659add7057b1c1",
"packages/ui/components/Confetti.wrn": "0e81426a3ee8aff672385a5466cf96085c25ba17677a2fef432bcddf13f4d58e",
"packages/ui/components/Container.wrn": "61c895a9cc0e02d314392e94226bddfae2b8fad074e30a68ba935e6ec9549ea6",
"packages/ui/components/ContextMenu.wrn": "1b078b9ac20ce2561167b0e14cec1fc26704c251d7a25021b45e51e1b980946e",
"packages/ui/components/CustomScrollbar.wrn": "2a3a2719580c21823d079c92ebb000c7a5a7d9d16e3fa9275b8fb7d4449cb437",
"packages/ui/components/DataMap.wrn": "338f0d0a3307289dd0387b7fe7ba631fa0b65b6be8c7b9ee3feb2203306f76a3",
"packages/ui/components/DataTable.wrn": "e929fdb4e59613878a03fb6a11e09c42f773c06ca7b20e43ae16a266835f2af4",
"packages/ui/components/DatePicker.wrn": "91bcfd3832d3bccc4de5402c0c06209947bde593bad4f869b4c29ee14a5c0bef",
"packages/ui/components/DeviceFrame.wrn": "c38d25419ee44b05d7c443cc4e854aeeb7a53a9289e374d71834de2dd2e4d979",
"packages/ui/components/Divider.wrn": "bfa36cf16ccd48c996bb0b08a438f1b281ea1811049ed69fc7680925b1eba019",
"packages/ui/components/DragAndDrop.wrn": "84305f07d43cdb9eff1f63c19458d88b0aec013424d05a49a2cafbecedc60513",
"packages/ui/components/Drawer.wrn": "5692db9a627587951898c2392789ef9dcae1662f19663607171a17d8f4ddb023",
"packages/ui/components/Dropdown.wrn": "978367a9dde22448cc664d686e4dd9c579fe8ba0b2cf02d610d95a3501f8dbb0",
"packages/ui/components/FeatureCard.wrn": "1bc548c115f924a0c7ade4c557852757083755c60ca0ee747b150a7cca3ebced",
"packages/ui/components/FeatureGrid.wrn": "15b5d6f9ddb7e3697682e7247fdf3c2dd080b770335f84ba9fab2692166fe897",
"packages/ui/components/FeatureIconCard.wrn": "3b4f3fa62c6729e686886a5b848e26c255766684829cec2b715967b4e73d6f07",
"packages/ui/components/FileInput.wrn": "866a292a3280527bf429893469e7c50f7cf38965d8adb37b45a35ede1606d5b8",
"packages/ui/components/FileUploadProgress.wrn": "e5da29c562a521cdd6bb50b8f4d217aa1ab981d7b2a2432af47391472f0a8034",
"packages/ui/components/Footer.wrn": "6694302f63f44dda3527d97b1bcc3031d51362601835dbe842cb04ba70088758",
"packages/ui/components/Grid.wrn": "83d4f5f2656d539538723f5791ba3c238901432e9d8c55c74f068d3eb5a74517",
"packages/ui/components/Hero.wrn": "345478b212701817ff57060f87982a987baf01a7179c979768e1cd4218b50900",
"packages/ui/components/HeroActions.wrn": "67cd31400ccb6abdbbf16219267dee946b44b064b79f25276d20ceb7d6e8a790",
"packages/ui/components/Image.wrn": "361179c478d7674c3b998891a366d73de9514fc6cc8786440c6c50b9ef065357",
"packages/ui/components/InputGroup.wrn": "30e9f2e4364542179180b6d6e796002d0ffe1e30305146749874697cde6629ea",
"packages/ui/components/InputNumber.wrn": "069195cc483f3f7d6f305d03fbe5a821906a030376fafb6f0d969e4c95b68fd0",
"packages/ui/components/Kbd.wrn": "6b402cb93f0fa76bb978d1ba483215f70ec7214b1c5e84b568fa3e26e87ed9d9",
"packages/ui/components/LayoutSplitter.wrn": "41d070e801a271552023e4392e4c0f67327c61e2e8eaee5f8b87af254b1d79c1",
"packages/ui/components/LegendIndicator.wrn": "b2b75a2a5edc20a326c2047d4c81b9cd3f319292a1eec5f4abd5cbafc0677d71",
"packages/ui/components/Link.wrn": "13f9d6b403440f4b3c3a9ce4dbefa0d5570eb30ff93f498e49f18baab3e08c1d",
"packages/ui/components/List.wrn": "5bd7d0b12b2f7dbf730db4030c6e20c6617b0933c1341428bbd6bcdab9ab6073",
"packages/ui/components/ListGroup.wrn": "eb7eca762101ea873fd6fa2f12f427580130fba3b21c0448a551b0452997dc92",
"packages/ui/components/Map.wrn": "3e6d5de5a21dd050c5c65950d6fb2f89af4024e1856a48f055b65b88fcd7b890",
"packages/ui/components/MarketingSectionHeader.wrn": "39b79499b77dc1c7d34e4e5ecb45a9ddc6182f78c2a2586671c4fa07f44679ad",
"packages/ui/components/Marquee.wrn": "81cd80732be34c8d7e4bf28b00347e1a9273166afdf66589d9f5d5774b69403b",
"packages/ui/components/MegaMenu.wrn": "6a6db166259f8f2bd7ac8fbb21dba6d915c4b936d87b19805caa78189f54730a",
"packages/ui/components/MetricCard.wrn": "513a6e99be3d9db46d96af9942b51331a0a048b184603e77e814506f0a52bdc5",
"packages/ui/components/MetricGrid.wrn": "c71e53249835908833055b553e64a8ee55fdf11ac4605436a9581ebb87a0608b",
"packages/ui/components/Modal.wrn": "7fa4b877772736f29f690e24d8742922b310397ef3083f0b78acb67a9f0d14b2",
"packages/ui/components/Nav.wrn": "c45b0ecb42250f4b3ede33c8932a025f789dda9ef48dbf332459ae458163e69a",
"packages/ui/components/Navbar.wrn": "ed3bb1974b93d52c480af468bdb1c0b253cb9196f3a00602614d3ce1e271a669",
"packages/ui/components/PageHeader.wrn": "321cde36ce8d521a57901033d46e8b437f42e558cca27f49ca26f7172aff1d54",
"packages/ui/components/Pagination.wrn": "4c7ac4bbda38c791af503f7923a511a958adc01637d286bcaaaa0f00ae8bb0fd",
"packages/ui/components/PinInput.wrn": "4dc398456f6392d7925db941debb484c7cb0358ecef527f696fe5ec4800a7602",
"packages/ui/components/Popover.wrn": "1246b99b4236bc7109a5d1427d013bb07bbea7a2da4f821517d2545ee0b5c019",
"packages/ui/components/PortalDashboard.wrn": "f04171eb1f8cabef06de3c20e4694b766def3407e1e20d2c9aaebc9bb7da03ee",
"packages/ui/components/PreferenceSwitcher.wrn": "71fc4b2fd8897dbd2e0795a6a824d76a57a4ce8756a889662f26df28b73c411a",
"packages/ui/components/PublicPageShell.wrn": "3d3f25c03d48f3d3d7e3c567e79cb137c7fce1867e054fd6d440fa1d2e961077",
"packages/ui/components/RangeSlider.wrn": "bbf646c5d5a89a62986290db811d77b8f635ebcaea9ca2d334b569aa5edc785b",
"packages/ui/components/Rating.wrn": "902b55c64e3798f3097f09b1558d1a2372f66d4f760662de085783108ee04587",
"packages/ui/components/Scrollspy.wrn": "b9c6400ee92a7c228362610a2051f37bff1d3baba1dbacd66d58397dfda5d856",
"packages/ui/components/SearchBox.wrn": "3f88340e0b69c0cd552023c72bd22dc511bc00422d46060097bcf0777e683675",
"packages/ui/components/Section.wrn": "45b7a1977c25a6020d5cc8bab2ce9c80730e7ec2d51ad53e8c9f64cd9b5b64cd",
"packages/ui/components/SectionHeader.wrn": "aca2df8eb35806096f5b9af466b018e5c22a19422e8665f488380da577a0ceb5",
"packages/ui/components/Sidebar.wrn": "e0250a973aea589a4d7dcc8b30dd01f22592bf22ba012e54a672b2a2288d8af6",
"packages/ui/components/SplitHero.wrn": "843387dc7b920b3cf6a1b2b785b8653c281982e524479edc2638a89381ff3577",
"packages/ui/components/StatsBar.wrn": "c273bd6ca417a0a20e5e6f1214414f678741b73bedd885fea1037575fa8c5b95",
"packages/ui/components/Stepper.wrn": "7ec0902acd7cb74b44d490215b6421dae9a41731735ad1e9aec17e8bfc3fa142",
"packages/ui/components/StrongPassword.wrn": "d5ea906fafe268b070a26ab551a252c0575d899c9d2b03b337bd047688b85dc5",
"packages/ui/components/StyledIcon.wrn": "0874f9a234b053a7c8b9c6983be5d664453a64c4576dff1a049101e249a2866d",
"packages/ui/components/Tabs.wrn": "f85214960e62da2fac41228deba511a50c57fd94f2830a8233b75048f6a542e9",
"packages/ui/components/TextLink.wrn": "9d561631c5f65a2bcdc59f5c0b166a5dd794a396f42093f2cd26388386f6f954",
"packages/ui/components/TimePicker.wrn": "ec0860a4a82a042a65acf9aa81519a5c815b61e0b8080cf6f1c986d26ce7f0e8",
"packages/ui/components/Timeline.wrn": "fb553f69763840532eef1c0aafa79013f57411dc5335e7cb7e7c20c5a3753008",
"packages/ui/components/Toaster.wrn": "5e4c9b2c1bfd5675a81a32e57684b99393ac7fe45d8420c7409a4e95d47d080c",
"packages/ui/components/ToggleCount.wrn": "e577195ee05ddb43cceec47145f6b90c0149f2f17055733d58911fcd02de2c7f",
"packages/ui/components/TogglePassword.wrn": "b6176453cb2c586fe88c3db6bdd734ae2b4c95db46d57e0de298dfba3d0dd0c2",
"packages/ui/components/TreeView.wrn": "f54d8495730203b923629bcfb167d5ca41236af0101ea2723d33354413555b4b",
"packages/ui/components/Typography.wrn": "a3de0febe0ba8640660e7f22babe8ca0e75e1b2882ba7be42f0728add7e05740",
"packages/ui/components/WysiwygEditor.wrn": "3f9d1765184581e3c1f335769a9f19969917450258bc95ba076980d99f5610b5",
"packages/ui/components/alert.wrn": "d42287e41b918b1e19962e9462ef203002eb5480acac984f115b711e9dbe663d",
"packages/ui/components/avatar.wrn": "8bc705e459b13c7f063c57e1506ce540e50fa8ef9020ae85b6e8b6a3579fc5dc",
"packages/ui/components/badge.wrn": "e44e33633fb34e897696cd9290f210108e35a3e2dc3b2a4a367411f45c69a1e1",
"packages/ui/components/button.wrn": "cba4ccbbd23bb75b3836ec7a53673e40f1e043d18bfcee3d613db96c318f4ba8",
"packages/ui/components/checkbox.wrn": "18046396b75d0b9c6bb2bdb09dbff1846c84fb07490f390a25ca7b5367fd2ef4",
"packages/ui/components/input.wrn": "a576e5ee2c6d0da963ebb14e8809ddf3ec7333b1eae095d5a4b7fce3ceb1fb55",
"packages/ui/components/progress.wrn": "6307a90585197d7aab19a8710b2430f5d4ed27ce77e9b90b1414ea0eed876492",
"packages/ui/components/radio.wrn": "09425a78358de5bbd2f47482f313e80065135335b969ce5ccdd5c7cc3ea5232c",
"packages/ui/components/select.wrn": "b107b259d228201e9071701370ad1c912ac9a8131f9e0a55834bcc84ef0dd417",
"packages/ui/components/skeleton.wrn": "4fc5e0846eeefd7830c038e1789be995c4f9d833aa913ff079eb4863baa65648",
"packages/ui/components/spinner.wrn": "2322645da7ef53f7c06035ff071d9a2f6ffe2901ff9338daed84037369367105",
"packages/ui/components/switch.wrn": "874504e4828e9db6a570d78984c4d3a76d0ceb39d70baa877649cb3798c82c85",
"packages/ui/components/textarea.wrn": "76d432179f2b7790ab9cdd644752928c259e1f496ad89c4db79981b74bbd226f",
"packages/ui/components/tooltip.wrn": "f3dfdfa5cd9661fe5e95ef3580eef4c7437c069726421370c2d7328fbe7d840d",
"packages/ui/styles/SelectStyles.wrn": "074fe0d67de4ef5e9f9cfe879beb72fd5c83352888687d3a1a4b7722c87af3ca",
"packages/ui/ui.css": "9ea591404e9cf675bbf1003e15e9fad00327094ff217dc20733f0fc87c0f4a62"
}
}