Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc98bccd6c |
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"version": "0.0.1",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "component-showcase",
|
||||
"runtimeExecutable": "bun",
|
||||
"runtimeArgs": ["run", "--cwd", "examples/component-showcase", "dev"],
|
||||
"port": 3000
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ai",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -149,156 +149,3 @@ app.put(
|
||||
- **Bun-only** — like the rest of WrNexus, this package targets the Bun runtime; Node is not supported.
|
||||
- Works with [`@wrnexus/core`](../core) — the guards return `Middleware` and read the subject from `ctx.user` on the request `Context`. Both types are imported from `@wrnexus/core`.
|
||||
- Policy combinators (`any`, `all`) and `authorize` are async-aware, so policies may return a `Promise<boolean>` (e.g. for a database ownership check).
|
||||
|
||||
## Declaring permissions
|
||||
|
||||
The RBAC/PBAC/ABAC surface above is the low-level toolkit. On top of it sits a
|
||||
declarative **registry + catalog + store + engine**: permissions, roles, and
|
||||
policies are declared once in code, merged into a frozen catalog at boot, and
|
||||
resolved per-request against a pluggable `PermissionStore` that holds who has
|
||||
what.
|
||||
|
||||
Put declarations in `app/authz/<name>.ts`; they are discovered automatically
|
||||
and merged (conflicting declarations of the same permission/role/policy across
|
||||
files fail the boot loudly, naming both source files).
|
||||
|
||||
```ts
|
||||
import { defineAuthz, owner } from "@wrnexus/authz";
|
||||
|
||||
export default defineAuthz({
|
||||
permissions: {
|
||||
"post:read": { title: "View posts", public: true },
|
||||
"post:delete": { title: "Delete posts", risk: "high" },
|
||||
},
|
||||
// "post:*" is a namespace wildcard grant, valid inside a role's list — it is
|
||||
// not itself a registered permission, so it can only ever grant permissions
|
||||
// that ARE declared above (e.g. "post:read", "post:delete").
|
||||
roles: { editor: ["post:*"], admin: ["role:editor"] },
|
||||
policies: { ownsPost: owner("id", "authorId") },
|
||||
bindings: { "post:delete": ["ownsPost"] },
|
||||
});
|
||||
```
|
||||
|
||||
`public: true` means anonymous callers may hold the permission — but any
|
||||
policy bound to it still runs, and can still veto the anonymous caller (e.g. a
|
||||
`notBanned` policy on a public `post:preview` permission).
|
||||
|
||||
## Checking permissions
|
||||
|
||||
Register `authzMiddleware` once, in `app/middleware/`, with the merged
|
||||
catalog and a `PermissionStore`. Like every other `app/middleware/*.ts` file,
|
||||
the registration is an eager, module-scope call — the same shape as
|
||||
`authzMiddleware({ catalog, store })` requires — so it must run after the
|
||||
catalog has been populated. Both the dev server and `wrnexus build`'s
|
||||
generated production entry guarantee `getAuthzCatalog()` is populated before
|
||||
any app middleware module evaluates. Name the file so it sorts after whatever
|
||||
middleware sets `ctx.user` (middleware runs in alphabetical filename order —
|
||||
`authz.ts` after `auth.ts`, for instance).
|
||||
|
||||
```ts
|
||||
// app/middleware/authz.ts
|
||||
import { authzMiddleware, getAuthzCatalog } from "@wrnexus/authz";
|
||||
import { dbPermissionStore } from "@wrnexus/authz/db";
|
||||
import { getDb } from "@wrnexus/db";
|
||||
|
||||
export default authzMiddleware({ catalog: getAuthzCatalog(), store: dbPermissionStore(getDb()) });
|
||||
```
|
||||
|
||||
> **`subject.id` must be a non-empty string.** The engine denies (and logs to
|
||||
> stderr) whenever `ctx.user.id` is present but not a non-empty string — this
|
||||
> includes the common case of an integer primary key. Coerce it before it
|
||||
> reaches `ctx.user`, e.g. `user.id = String(row.id)`, or every request for
|
||||
> that user denies with "Invalid subject" instead of resolving normally.
|
||||
> `owner()` (the built-in ownership policy) compares subject and resource ids
|
||||
> with `Object.is`, so both sides must be the same type too — `owner()` on a
|
||||
> numeric `resource.authorId` against a stringified `subject.id` never
|
||||
> matches even when they represent "the same" id.
|
||||
|
||||
There is no per-route `middleware` export — `app/middleware/*.ts` is the only
|
||||
place middleware is registered. To gate part of the app, branch on the
|
||||
request the same way any other conditional middleware does (compare
|
||||
`app/middleware/captcha-login.ts` in the auth showcase, which branches on
|
||||
method + path the same way):
|
||||
|
||||
```ts
|
||||
// app/middleware/protect-posts.ts
|
||||
import type { Context, Next } from "@wrnexus/core";
|
||||
import { guardPermission } from "@wrnexus/authz";
|
||||
|
||||
const guardPostWrite = guardPermission("post:write");
|
||||
|
||||
export default function protectPosts(ctx: Context, next: Next) {
|
||||
return ctx.url.pathname.startsWith("/api/posts") && ctx.req.method !== "GET"
|
||||
? guardPostWrite(ctx, next)
|
||||
: next();
|
||||
}
|
||||
```
|
||||
|
||||
Or check inline inside a route handler with the free function `can()`:
|
||||
|
||||
```ts
|
||||
// app/api/posts/[id].ts
|
||||
import type { Context } from "@wrnexus/core";
|
||||
import { can } from "@wrnexus/authz";
|
||||
|
||||
export const DELETE = async (ctx: Context) => {
|
||||
const post = { id: "1", authorId: "alice" }; // load your own resource here
|
||||
if (!(await can(ctx, "post:delete", post))) {
|
||||
return Response.json({ ok: false, error: "Forbidden" }, { status: 403 });
|
||||
}
|
||||
return Response.json({ ok: true });
|
||||
};
|
||||
```
|
||||
|
||||
`can()` is a free function taking `ctx`, not `ctx.can` — `@wrnexus/core` must
|
||||
not depend on `@wrnexus/authz`, so the per-request resolver lives in
|
||||
`ctx.locals` instead, reached through `can()` / `decideFor()` /
|
||||
`guardPermission()` / `filterCan()`. Calling any of them before
|
||||
`authzMiddleware` has run for that request throws a `WRN-AUTHZ-SETUP` error
|
||||
naming the missing registration, rather than silently denying.
|
||||
|
||||
See `examples/auth-showcase/app/authz/showcase.ts` and
|
||||
`examples/auth-showcase/app/middleware/authz.ts` for a complete, runnable
|
||||
version of this wiring.
|
||||
|
||||
## Precedence
|
||||
|
||||
1. An explicit deny wins over everything, including `*` — and honours the
|
||||
same namespace-wildcard matching as grants (denying `post:*` blocks
|
||||
`post:comment:delete`, not just `post:*` itself).
|
||||
2. A bound policy can veto a permission a role grants, and runs even for a
|
||||
`public: true` permission — including for an anonymous caller.
|
||||
3. Otherwise the permission must be held via a role or an explicit grant.
|
||||
4. Default deny.
|
||||
|
||||
Every failure — an unknown permission (outside strict/dev mode), a store
|
||||
outage, a thrown policy — denies rather than throwing through to the caller.
|
||||
|
||||
`permissionsFor()` (on the resolver returned by `createAuthzResolver`) is a
|
||||
coarse hint for hiding UI (e.g. a menu section), **never authoritative**. A
|
||||
`Set<string>` cannot represent "granted `post:*` except `post:delete`", so a
|
||||
narrow deny beneath a broad grant is invisible to it — the set still contains
|
||||
`post:*` while `can()` / `decide()` correctly refuse `post:delete`. Gate real
|
||||
actions with `can()`, `decideFor()`, or `filterCan()`; never by matching
|
||||
against `permissionsFor()`'s result.
|
||||
|
||||
## CLI
|
||||
|
||||
```bash
|
||||
wrnexus authz list # every registered permission, role, and policy
|
||||
wrnexus authz generate # app/authz/permissions.gen.ts type unions
|
||||
wrnexus authz init # scaffold the assignment-table migration
|
||||
```
|
||||
|
||||
`wrnexus authz generate`'s output is a plain `Permission | Role` string-literal
|
||||
union — `can()`, `guardPermission()`, and `decideFor()` all take a bare
|
||||
`string` and nothing reads this file automatically, so import it to type your
|
||||
own helpers/constants against the registered catalog, e.g.:
|
||||
|
||||
```ts
|
||||
import type { Permission } from "app/authz/permissions.gen.ts";
|
||||
|
||||
function guard(permission: Permission) {
|
||||
return guardPermission(permission);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/authz",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/authz — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -34,16 +34,8 @@
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
},
|
||||
"./db": {
|
||||
"types": "./dist/db.d.ts",
|
||||
"import": "./dist/db.js"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.8.5",
|
||||
"@wrnexus/db": "^0.8.5"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
|
||||
+17
-18
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/cli",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/cli — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -44,23 +44,22 @@
|
||||
"wrnexus": "./dist/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.8.5",
|
||||
"@wrnexus/router": "^0.8.5",
|
||||
"@wrnexus/csr": "^0.8.5",
|
||||
"@wrnexus/compiler": "^0.8.5",
|
||||
"@wrnexus/styles": "^0.8.5",
|
||||
"@wrnexus/dev-server": "^0.8.5",
|
||||
"@wrnexus/ui": "^0.8.5",
|
||||
"@wrnexus/validation": "^0.8.5",
|
||||
"@wrnexus/i18n": "^0.8.5",
|
||||
"@wrnexus/mcp": "^0.8.5",
|
||||
"@wrnexus/playground": "^0.8.5",
|
||||
"@wrnexus/db": "^0.8.5",
|
||||
"@wrnexus/authz": "^0.8.5",
|
||||
"@wrnexus/plugin": "^0.8.5",
|
||||
"@wrnexus/syntax": "^0.8.5",
|
||||
"@wrnexus/typecheck": "^0.8.5",
|
||||
"@wrnexus/security": "^0.8.5",
|
||||
"@wrnexus/core": "^0.8.4",
|
||||
"@wrnexus/router": "^0.8.4",
|
||||
"@wrnexus/csr": "^0.8.4",
|
||||
"@wrnexus/compiler": "^0.8.4",
|
||||
"@wrnexus/styles": "^0.8.4",
|
||||
"@wrnexus/dev-server": "^0.8.4",
|
||||
"@wrnexus/ui": "^0.8.4",
|
||||
"@wrnexus/validation": "^0.8.4",
|
||||
"@wrnexus/i18n": "^0.8.4",
|
||||
"@wrnexus/mcp": "^0.8.4",
|
||||
"@wrnexus/playground": "^0.8.4",
|
||||
"@wrnexus/db": "^0.8.4",
|
||||
"@wrnexus/plugin": "^0.8.4",
|
||||
"@wrnexus/syntax": "^0.8.4",
|
||||
"@wrnexus/typecheck": "^0.8.4",
|
||||
"@wrnexus/security": "^0.8.4",
|
||||
"selfsigned": "^5.5.0"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/compiler",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/compiler — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -37,10 +37,10 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/csr": "^0.8.5",
|
||||
"@wrnexus/syntax": "^0.8.5",
|
||||
"@wrnexus/store": "^0.8.5",
|
||||
"@wrnexus/validation": "^0.8.5"
|
||||
"@wrnexus/csr": "^0.8.4",
|
||||
"@wrnexus/syntax": "^0.8.4",
|
||||
"@wrnexus/store": "^0.8.4",
|
||||
"@wrnexus/validation": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/core",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/core — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/csr",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/csr — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -37,7 +37,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.8.5"
|
||||
"@wrnexus/core": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/db",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Typed database drivers, migrations, instrumentation, repositories, pagination, and transaction helpers.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/dev-server",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/dev-server — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -41,27 +41,25 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/authz": "^0.8.5",
|
||||
"@wrnexus/rpc": "^0.8.5",
|
||||
"@wrnexus/core": "^0.8.5",
|
||||
"@wrnexus/dev-toolbar": "^0.8.5",
|
||||
"@wrnexus/router": "^0.8.5",
|
||||
"@wrnexus/ssr": "^0.8.5",
|
||||
"@wrnexus/csr": "^0.8.5",
|
||||
"@wrnexus/compiler": "^0.8.5",
|
||||
"@wrnexus/styles": "^0.8.5",
|
||||
"@wrnexus/ui": "^0.8.5",
|
||||
"@wrnexus/validation": "^0.8.5",
|
||||
"@wrnexus/i18n": "^0.8.5",
|
||||
"@wrnexus/db": "^0.8.5",
|
||||
"@wrnexus/pubsub": "^0.8.5",
|
||||
"@wrnexus/uploader": "^0.8.5",
|
||||
"@wrnexus/plugin": "^0.8.5",
|
||||
"@wrnexus/store": "^0.8.5",
|
||||
"@wrnexus/security": "^0.8.5",
|
||||
"@wrnexus/observability": "^0.8.5",
|
||||
"@wrnexus/cache": "^0.8.5",
|
||||
"@wrnexus/pwa": "^0.8.5"
|
||||
"@wrnexus/core": "^0.8.4",
|
||||
"@wrnexus/dev-toolbar": "^0.8.4",
|
||||
"@wrnexus/router": "^0.8.4",
|
||||
"@wrnexus/ssr": "^0.8.4",
|
||||
"@wrnexus/csr": "^0.8.4",
|
||||
"@wrnexus/compiler": "^0.8.4",
|
||||
"@wrnexus/styles": "^0.8.4",
|
||||
"@wrnexus/ui": "^0.8.4",
|
||||
"@wrnexus/validation": "^0.8.4",
|
||||
"@wrnexus/i18n": "^0.8.4",
|
||||
"@wrnexus/db": "^0.8.4",
|
||||
"@wrnexus/pubsub": "^0.8.4",
|
||||
"@wrnexus/uploader": "^0.8.4",
|
||||
"@wrnexus/plugin": "^0.8.4",
|
||||
"@wrnexus/store": "^0.8.4",
|
||||
"@wrnexus/security": "^0.8.4",
|
||||
"@wrnexus/observability": "^0.8.4",
|
||||
"@wrnexus/cache": "^0.8.4",
|
||||
"@wrnexus/pwa": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/dev-toolbar",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/dev-toolbar — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/encryption",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Authenticated encryption, key rotation, hashing, and optional application-layer encrypted HTTP envelopes.",
|
||||
"license": "MIT",
|
||||
@@ -37,7 +37,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.8.5"
|
||||
"@wrnexus/core": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/helpers",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
|
||||
"license": "MIT",
|
||||
@@ -37,7 +37,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.8.5"
|
||||
"@wrnexus/core": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/i18n",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Locale loading, fallback resolution, SSR/browser translations, formatters, and WRNexusJS language components.",
|
||||
"license": "MIT",
|
||||
@@ -42,9 +42,9 @@
|
||||
"./components/*": "./components/*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.8.5",
|
||||
"@wrnexus/plugin": "^0.8.5",
|
||||
"@wrnexus/ui": "^0.8.5"
|
||||
"@wrnexus/core": "^0.8.4",
|
||||
"@wrnexus/plugin": "^0.8.4",
|
||||
"@wrnexus/ui": "^0.8.4"
|
||||
},
|
||||
"wrnexus": {
|
||||
"plugin": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/jwt",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "HS256 JSON Web Tokens, key rotation, access/refresh helpers, scopes, cookies, and auth middleware.",
|
||||
"license": "MIT",
|
||||
@@ -37,7 +37,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.8.5"
|
||||
"@wrnexus/core": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/mobile",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/mobile — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -37,7 +37,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/native": "^0.8.5"
|
||||
"@wrnexus/native": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/native",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/native — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/oauth",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/oauth — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -37,7 +37,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/jwt": "^0.8.5"
|
||||
"@wrnexus/jwt": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/plugin",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/plugin — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -49,7 +49,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/syntax": "^0.8.5"
|
||||
"@wrnexus/syntax": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/pubsub",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/pubsub — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/queue",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/queue — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -37,7 +37,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.8.5"
|
||||
"@wrnexus/core": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/reactive",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/reactive — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/router",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/router — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -37,8 +37,8 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/compiler": "^0.8.5",
|
||||
"@wrnexus/core": "^0.8.5"
|
||||
"@wrnexus/compiler": "^0.8.4",
|
||||
"@wrnexus/core": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ssr",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/ssr — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -45,9 +45,9 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.8.5",
|
||||
"@wrnexus/store": "^0.8.5",
|
||||
"@wrnexus/security": "^0.8.5"
|
||||
"@wrnexus/core": "^0.8.4",
|
||||
"@wrnexus/store": "^0.8.4",
|
||||
"@wrnexus/security": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/styles",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/styles — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -37,9 +37,9 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/uploader": "^0.8.5",
|
||||
"@wrnexus/core": "^0.8.5",
|
||||
"@wrnexus/plugin": "^0.8.5"
|
||||
"@wrnexus/uploader": "^0.8.4",
|
||||
"@wrnexus/core": "^0.8.4",
|
||||
"@wrnexus/plugin": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/syntax",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/syntax — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/test",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/test — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/tracking",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/tracking — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
+16
-16
@@ -359,15 +359,6 @@ Reusable preference switcher component.
|
||||
- Slots: None
|
||||
- Outputs: `theme({ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])`, `color({ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])`, `language({ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])`
|
||||
|
||||
### Toaster
|
||||
|
||||
Reusable toaster component.
|
||||
|
||||
- Mount: `data-component="Toaster"`
|
||||
- Props: `color: string = "info"`, `size: string = "default"`, `position: string = "bottom-right"`, `duration: number = 4500`, `max: number = 4`, `pauseOnHover: boolean = true`, `showIcon: boolean = true`, `successIcon: string = ""`, `dangerIcon: string = ""`, `warningIcon: string = ""`, `infoIcon: string = ""`, `closable: boolean = true`, `showProgress: boolean = true`, `closeLabel: string = "Dismiss notification"`, `class: string = ""`
|
||||
- Slots: None
|
||||
- Outputs: `show({ id: number; message: string; tone: string })`, `dismiss({ id: number; reason: string })`, `action({ id: number; sourceEvent: Event })`
|
||||
|
||||
## Data
|
||||
|
||||
### MetricCard
|
||||
@@ -563,6 +554,15 @@ Theme-aware, responsive data map component.
|
||||
- Slots: `default`
|
||||
- Outputs: `select({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `change({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`
|
||||
|
||||
### DataTable
|
||||
|
||||
Theme-aware, responsive data table component.
|
||||
|
||||
- Mount: `data-component="DataTable"`
|
||||
- Props: `size: string = "default"`, `color: string = "primary"`, `caption: string = "Data Table"`, `columns: unknown[] = []`, `rows: unknown[] = []`, `striped: boolean = true`, `class: string = ""`
|
||||
- Slots: `default`
|
||||
- Outputs: `sort({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `select({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `change({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `rowClick({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `pageChange({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`
|
||||
|
||||
### DragAndDrop
|
||||
|
||||
Theme-aware, responsive drag and drop component.
|
||||
@@ -945,7 +945,7 @@ Open an accessible keyboard-aware action menu from pointer or keyboard context i
|
||||
Present responsive modal side or bottom content with focus management, backdrop behavior, slots, and close events.
|
||||
|
||||
- Mount: `data-component="Drawer"`
|
||||
- Props: `open: boolean = false`, `defaultOpen: boolean = false`, `placement: string = "right"`, `size: string = "md"`, `color: string = "primary"`, `variant: string = "default"`, `title: string = "Drawer"`, `description: string = ""`, `icon: string = ""`, `label: string = "Drawer"`, `closeLabel: string = "Close drawer"`, `showClose: boolean = true`, `closeOnBackdrop: boolean = true`, `closeOnEscape: boolean = true`, `duration: number = 260`, `overlay: boolean = true`, `scrollable: boolean = true`, `triggerLabel: string = ""`, `triggerIcon: string = ""`, `class: string = ""`
|
||||
- Props: `open: boolean = false`, `defaultOpen: boolean = false`, `placement: string = "right"`, `size: string = "md"`, `color: string = "primary"`, `variant: string = "default"`, `title: string = "Drawer"`, `description: string = ""`, `icon: string = ""`, `label: string = "Drawer"`, `closeLabel: string = "Close drawer"`, `showClose: boolean = true`, `closeOnBackdrop: boolean = true`, `closeOnEscape: boolean = true`, `overlay: boolean = true`, `scrollable: boolean = true`, `triggerLabel: string = ""`, `triggerIcon: string = ""`, `class: string = ""`
|
||||
- Slots: `trigger`, `header`, `default`, `footer`
|
||||
- Outputs: `open({ placement: string; sourceEvent: Event })`, `close({ reason: string; placement: string; sourceEvent: Event })`, `cancel({ placement: string; sourceEvent: Event })`
|
||||
|
||||
@@ -963,7 +963,7 @@ Open an accessible anchored menu with keyboard navigation, item selection, actio
|
||||
Present an accessible modal dialog with focus management, confirmation, cancellation, slots, and responsive sizing.
|
||||
|
||||
- Mount: `data-component="Modal"`
|
||||
- Props: `open: boolean = false`, `defaultOpen: boolean = false`, `title: string = "Modal"`, `description: string = ""`, `icon: string = ""`, `label: string = "Modal dialog"`, `size: string = "md"`, `placement: string = "center"`, `color: string = "primary"`, `variant: string = "default"`, `showClose: boolean = true`, `closeLabel: string = "Close modal"`, `closeOnBackdrop: boolean = true`, `closeOnEscape: boolean = true`, `closeOnCancel: boolean = true`, `closeOnConfirm: boolean = false`, `showFooter: boolean = true`, `cancelLabel: string = "Cancel"`, `cancelIcon: string = ""`, `confirmLabel: string = "Confirm"`, `confirmIcon: string = ""`, `confirmDisabled: boolean = false`, `confirmLoading: boolean = false`, `destructive: boolean = false`, `triggerLabel: string = ""`, `triggerIcon: string = ""`, `scrollable: boolean = true`, `scrollBehavior: string = "inside"`, `class: string = ""`
|
||||
- Props: `open: boolean = false`, `defaultOpen: boolean = false`, `title: string = "Modal"`, `description: string = ""`, `icon: string = ""`, `label: string = "Modal dialog"`, `size: string = "md"`, `placement: string = "center"`, `color: string = "primary"`, `variant: string = "default"`, `showClose: boolean = true`, `closeLabel: string = "Close modal"`, `closeOnBackdrop: boolean = true`, `closeOnEscape: boolean = true`, `closeOnCancel: boolean = true`, `closeOnConfirm: boolean = false`, `showFooter: boolean = true`, `cancelLabel: string = "Cancel"`, `cancelIcon: string = ""`, `confirmLabel: string = "Confirm"`, `confirmIcon: string = ""`, `confirmDisabled: boolean = false`, `confirmLoading: boolean = false`, `destructive: boolean = false`, `triggerLabel: string = ""`, `triggerIcon: string = ""`, `scrollable: boolean = true`, `class: string = ""`
|
||||
- Slots: `trigger`, `header`, `default`, `footer`
|
||||
- Outputs: `open({ sourceEvent: Event })`, `close({ reason: string; sourceEvent: Event })`, `cancel({ sourceEvent: Event })`, `confirm({ sourceEvent: Event })`
|
||||
|
||||
@@ -987,11 +987,11 @@ Show concise accessible contextual help on hover, focus, click, or controlled op
|
||||
|
||||
## Tables
|
||||
|
||||
### DataTable
|
||||
### Table
|
||||
|
||||
Sortable, filterable, paginated data table with row selection.
|
||||
Theme-aware, responsive table component.
|
||||
|
||||
- Mount: `data-component="DataTable"`
|
||||
- Props: `color: string = "primary"`, `size: string = "default"`, `columns: unknown[] = []`, `rows: unknown[] = []`, `rowKey: string = "id"`, `remote: boolean = false`, `loadingLabel: string = "Loading"`, `errorLabel: string = "Could not load this data"`, `retryLabel: string = "Try again"`, `caption: string = ""`, `description: string = ""`, `searchable: boolean = true`, `searchPlaceholder: string = "Search"`, `paginated: boolean = true`, `pageSize: number = 10`, `paginationStyle: string = "compact"`, `pageSizes: number[] = [10, 25, 50]`, `selectable: boolean = false`, `actions: unknown[] = []`, `striped: boolean = true`, `bordered: boolean = true`, `gridlines: string = "rows"`, `density: string = "default"`, `emptyLabel: string = "No records to show"`, `noResultsLabel: string = "No records match your search"`, `clearSearchLabel: string = "Clear search"`, `stickyFirstColumn: boolean = false`, `layout: string = "rows"`, `class: string = ""`
|
||||
- Mount: `data-component="Table"`
|
||||
- Props: `size: string = "default"`, `color: string = "primary"`, `caption: string = "Table"`, `columns: unknown[] = []`, `rows: unknown[] = []`, `striped: boolean = true`, `class: string = ""`
|
||||
- Slots: `default`
|
||||
- Outputs: `sort({ key: string; direction: string })`, `search({ query: string })`, `pageChange({ page: number; pageSize: number })`, `select({ selected: Array<string | number>; all: boolean })`, `change({ page: number; pageSize: number; total: number; query: string; sortKey: string; sortDirection: string })`, `rowClick({ row: object; sourceEvent: Event })`, `action({ id: string; selected: Array<string | number>; rows: object[]; sourceEvent: Event })`, `request({ instanceId: number; page: number; pageSize: number; sortKey: string; sortDirection: string; query: string })`
|
||||
- Outputs: `sort({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `select({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `rowClick({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`
|
||||
|
||||
@@ -168,8 +168,8 @@
|
||||
},
|
||||
{
|
||||
"name": "DataTable",
|
||||
"category": "tables",
|
||||
"purpose": "Sortable, filterable, paginated data table with row selection."
|
||||
"category": "integrations",
|
||||
"purpose": "Theme-aware, responsive data table component."
|
||||
},
|
||||
{
|
||||
"name": "DatePicker",
|
||||
@@ -471,6 +471,11 @@
|
||||
"category": "forms",
|
||||
"purpose": "Theme-aware, responsive switch component."
|
||||
},
|
||||
{
|
||||
"name": "Table",
|
||||
"category": "tables",
|
||||
"purpose": "Theme-aware, responsive table component."
|
||||
},
|
||||
{
|
||||
"name": "Tabs",
|
||||
"category": "navigation",
|
||||
@@ -506,11 +511,6 @@
|
||||
"category": "integrations",
|
||||
"purpose": "Theme-aware, responsive toast notifications component."
|
||||
},
|
||||
{
|
||||
"name": "Toaster",
|
||||
"category": "core",
|
||||
"purpose": "Reusable toaster component."
|
||||
},
|
||||
{
|
||||
"name": "ToggleCount",
|
||||
"category": "advanced-forms",
|
||||
|
||||
@@ -4569,9 +4569,16 @@
|
||||
{
|
||||
"name": "DataTable",
|
||||
"mount": "DataTable",
|
||||
"category": "tables",
|
||||
"purpose": "Sortable, filterable, paginated data table with row selection.",
|
||||
"category": "integrations",
|
||||
"purpose": "Theme-aware, responsive data table component.",
|
||||
"props": [
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
@@ -4580,10 +4587,10 @@
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"name": "caption",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"default": "\"Data Table\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
@@ -4600,111 +4607,6 @@
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "rowKey",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"id\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "remote",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "loadingLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Loading\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "errorLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Could not load this data\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "retryLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Try again\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "caption",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "searchable",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "searchPlaceholder",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Search\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "paginated",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "pageSize",
|
||||
"type": "number",
|
||||
"required": false,
|
||||
"default": "10",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "paginationStyle",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"compact\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "pageSizes",
|
||||
"type": "number[]",
|
||||
"required": false,
|
||||
"default": "[10, 25, 50]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "selectable",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "actions",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "striped",
|
||||
"type": "boolean",
|
||||
@@ -4712,62 +4614,6 @@
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "bordered",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "gridlines",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"rows\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "density",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "emptyLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"No records to show\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "noResultsLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"No records match your search\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "clearSearchLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Clear search\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "stickyFirstColumn",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "layout",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"rows\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
@@ -4780,47 +4626,26 @@
|
||||
"outputs": [
|
||||
{
|
||||
"name": "sort",
|
||||
"payloadType": "{ key: string; direction: string }"
|
||||
},
|
||||
{
|
||||
"name": "search",
|
||||
"payloadType": "{ query: string }"
|
||||
},
|
||||
{
|
||||
"name": "pageChange",
|
||||
"payloadType": "{ page: number; pageSize: number }"
|
||||
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
|
||||
},
|
||||
{
|
||||
"name": "select",
|
||||
"payloadType": "{ selected: Array<string | number>; all: boolean }"
|
||||
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
|
||||
},
|
||||
{
|
||||
"name": "change",
|
||||
"payloadType": "{ page: number; pageSize: number; total: number; query: string; sortKey: string; sortDirection: string }"
|
||||
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
|
||||
},
|
||||
{
|
||||
"name": "rowClick",
|
||||
"payloadType": "{ row: object; sourceEvent: Event }"
|
||||
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
|
||||
},
|
||||
{
|
||||
"name": "action",
|
||||
"payloadType": "{ id: string; selected: Array<string | number>; rows: object[]; sourceEvent: Event }"
|
||||
},
|
||||
{
|
||||
"name": "request",
|
||||
"payloadType": "{ instanceId: number; page: number; pageSize: number; sortKey: string; sortDirection: string; query: string }"
|
||||
"name": "pageChange",
|
||||
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
"sort",
|
||||
"search",
|
||||
"pageChange",
|
||||
"select",
|
||||
"change",
|
||||
"rowClick",
|
||||
"action",
|
||||
"request"
|
||||
],
|
||||
"events": ["sort", "select", "change", "rowClick", "pageChange"],
|
||||
"source": "components/DataTable.wrn"
|
||||
},
|
||||
{
|
||||
@@ -5395,13 +5220,6 @@
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "duration",
|
||||
"type": "number",
|
||||
"required": false,
|
||||
"default": "260",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "overlay",
|
||||
"type": "boolean",
|
||||
@@ -8918,13 +8736,6 @@
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "scrollBehavior",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"inside\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
@@ -12198,6 +12009,80 @@
|
||||
"events": ["input", "change", "focus", "blur"],
|
||||
"source": "components/Switch.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Table",
|
||||
"mount": "Table",
|
||||
"category": "tables",
|
||||
"purpose": "Theme-aware, responsive table component.",
|
||||
"props": [
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "caption",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Table\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "columns",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "rows",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "striped",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": ["default"],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "sort",
|
||||
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
|
||||
},
|
||||
{
|
||||
"name": "select",
|
||||
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
|
||||
},
|
||||
{
|
||||
"name": "rowClick",
|
||||
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
|
||||
}
|
||||
],
|
||||
"events": ["sort", "select", "rowClick"],
|
||||
"source": "components/table.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Tabs",
|
||||
"mount": "Tabs",
|
||||
@@ -13008,136 +12893,6 @@
|
||||
"events": ["add", "dismiss", "clear", "action"],
|
||||
"source": "components/ToastNotifications.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Toaster",
|
||||
"mount": "Toaster",
|
||||
"category": "core",
|
||||
"purpose": "Reusable toaster component.",
|
||||
"props": [
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"info\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "position",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"bottom-right\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "duration",
|
||||
"type": "number",
|
||||
"required": false,
|
||||
"default": "4500",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "max",
|
||||
"type": "number",
|
||||
"required": false,
|
||||
"default": "4",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "pauseOnHover",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "showIcon",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "successIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "dangerIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "warningIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "infoIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "closable",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "showProgress",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "closeLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Dismiss notification\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "show",
|
||||
"payloadType": "{ id: number; message: string; tone: string }"
|
||||
},
|
||||
{
|
||||
"name": "dismiss",
|
||||
"payloadType": "{ id: number; reason: string }"
|
||||
},
|
||||
{
|
||||
"name": "action",
|
||||
"payloadType": "{ id: number; sourceEvent: Event }"
|
||||
}
|
||||
],
|
||||
"events": ["show", "dismiss", "action"],
|
||||
"source": "components/Toaster.wrn"
|
||||
},
|
||||
{
|
||||
"name": "ToggleCount",
|
||||
"mount": "ToggleCount",
|
||||
|
||||
@@ -45,12 +45,8 @@ component ContextMenu {
|
||||
sourceEvent.preventDefault()
|
||||
}
|
||||
if (placement === "pointer" && sourceEvent) {
|
||||
// Place the menu at the pointer and let the anchored clamp in the
|
||||
// runtime pull it back on screen once it has been laid out and can
|
||||
// actually be measured. Subtracting a guessed 340x420 here instead
|
||||
// pushed every menu that was not that size away from the pointer.
|
||||
positionX = Math.max(12, sourceEvent.clientX || 12)
|
||||
positionY = Math.max(12, sourceEvent.clientY || 12)
|
||||
positionX = Math.max(12, Math.min(sourceEvent.clientX || 12, window.innerWidth - 340))
|
||||
positionY = Math.max(12, Math.min(sourceEvent.clientY || 12, window.innerHeight - 420))
|
||||
}
|
||||
visible = true
|
||||
output.open({
|
||||
@@ -165,7 +161,6 @@ component ContextMenu {
|
||||
|
||||
<div
|
||||
class="wire-context-menu__panel"
|
||||
data-wrn-anchored="true"
|
||||
data-show='{open || visible}'
|
||||
role="menu"
|
||||
aria-label='{label}'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,8 +20,6 @@ open: boolean = false
|
||||
showClose: boolean = true
|
||||
closeOnBackdrop: boolean = true
|
||||
closeOnEscape: boolean = true
|
||||
// Open/close animation length in ms. 0 disables the animation entirely.
|
||||
duration: number = 260
|
||||
overlay: boolean = true
|
||||
scrollable: boolean = true
|
||||
triggerLabel: string = ""
|
||||
@@ -81,9 +79,7 @@ open: boolean = false
|
||||
data-overlay='{overlay ? "true" : "false"}'
|
||||
data-scrollable='{scrollable ? "true" : "false"}'
|
||||
class='wire-drawer {class}'
|
||||
style='--drawer-duration: {duration}ms'
|
||||
>
|
||||
|
||||
{#if triggerLabel}
|
||||
<button
|
||||
type="button"
|
||||
@@ -105,6 +101,7 @@ open: boolean = false
|
||||
|
||||
<div
|
||||
class="wire-drawer__layer"
|
||||
data-show='{open || visible}'
|
||||
role="presentation"
|
||||
@keydown='handleKeydown(event)'
|
||||
>
|
||||
@@ -221,32 +218,12 @@ open: boolean = false
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
* The layer stays in the layout and is revealed by [data-open]; it used to
|
||||
* be toggled with data-show, which sets display:none, and display cannot
|
||||
* be transitioned -- the drawer simply snapped in and out. visibility is
|
||||
* delayed by the duration on the way out so the panel can finish sliding
|
||||
* before the layer is taken out of the hit-testing tree.
|
||||
*/
|
||||
.wire-drawer__layer {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1200;
|
||||
display: flex;
|
||||
pointer-events: none;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition:
|
||||
opacity var(--drawer-duration, 260ms) ease,
|
||||
visibility 0s linear var(--drawer-duration, 260ms);
|
||||
}
|
||||
|
||||
.wire-drawer[data-open="true"] .wire-drawer__layer {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition:
|
||||
opacity var(--drawer-duration, 260ms) ease,
|
||||
visibility 0s linear 0s;
|
||||
}
|
||||
|
||||
.wire-drawer__backdrop {
|
||||
@@ -285,38 +262,6 @@ open: boolean = false
|
||||
box-shadow: -28px 0 80px color-mix(in srgb, black 28%, transparent);
|
||||
pointer-events: auto;
|
||||
overflow: hidden;
|
||||
/* Slides in from whichever edge the placement puts it on. */
|
||||
transform: translateX(100%);
|
||||
transition: transform var(--drawer-duration, 260ms) cubic-bezier(0.32, 0.72, 0, 1);
|
||||
}
|
||||
|
||||
.wire-drawer[data-open="true"] .wire-drawer__panel {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.wire-drawer[data-placement="left"] .wire-drawer__panel {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.wire-drawer[data-placement="top"] .wire-drawer__panel {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.wire-drawer[data-placement="bottom"] .wire-drawer__panel {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
.wire-drawer[data-open="true"][data-placement="left"] .wire-drawer__panel,
|
||||
.wire-drawer[data-open="true"][data-placement="top"] .wire-drawer__panel,
|
||||
.wire-drawer[data-open="true"][data-placement="bottom"] .wire-drawer__panel {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.wire-drawer__layer,
|
||||
.wire-drawer__panel {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
.wire-drawer[data-size="sm"] .wire-drawer__panel {
|
||||
@@ -450,19 +395,12 @@ open: boolean = false
|
||||
color: color-mix(in srgb, currentColor 76%, transparent);
|
||||
}
|
||||
|
||||
/*
|
||||
* padding is reset explicitly: an app-level `button { padding: ... }` rule
|
||||
* outranks the browser default and leaves this fixed-size button with a
|
||||
* content box of a couple of pixels, which squeezes the icon to a sliver
|
||||
* and reads as "the close button has no icon". Same trap as Modal.
|
||||
*/
|
||||
.wire-drawer__close {
|
||||
appearance: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 0 0 auto;
|
||||
padding: 0;
|
||||
width: 2.35rem;
|
||||
height: 2.35rem;
|
||||
color: var(--wire-color-text-muted);
|
||||
@@ -479,30 +417,10 @@ open: boolean = false
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Never let the glyph be shrunk by the flex container. */
|
||||
.wire-drawer__close svg {
|
||||
flex: 0 0 auto;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Slot content is authored by the host app, so the app global stylesheet
|
||||
* styles it too. A bare element selector there (p { color: ... }) beats
|
||||
* anything the panel merely *inherits*, which is how modal body copy ended
|
||||
* up muted grey on a saturated background. State the colour explicitly;
|
||||
* :where() keeps the specificity low enough that any class the app puts on
|
||||
* its own slot content still wins.
|
||||
*/
|
||||
.wire-drawer__body {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
padding: 1.35rem;
|
||||
color: var(--wire-color-text);
|
||||
}
|
||||
|
||||
.wire-drawer__body :where(p, li, dd, dt, h1, h2, h3, h4, h5, h6, span, label, code) {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.wire-drawer[data-scrollable="true"] .wire-drawer__body {
|
||||
|
||||
@@ -171,7 +171,6 @@ items: unknown[] = []
|
||||
|
||||
<div
|
||||
class="wire-dropdown__panel"
|
||||
data-wrn-anchored="true"
|
||||
data-show='{open || visible}'
|
||||
role="menu"
|
||||
aria-label='{menuLabel}'
|
||||
|
||||
@@ -35,7 +35,6 @@ component Modal {
|
||||
triggerLabel: string = ""
|
||||
triggerIcon: string = ""
|
||||
scrollable: boolean = true
|
||||
scrollBehavior: string = "inside"
|
||||
class: string = ""
|
||||
}
|
||||
|
||||
@@ -51,16 +50,6 @@ component Modal {
|
||||
output.open({ sourceEvent: sourceEvent })
|
||||
}
|
||||
|
||||
// Slot content can close the modal it sits in by dispatching a bubbling
|
||||
// wrnexus:modal:close event, e.g. from a form success handler:
|
||||
//
|
||||
// event.target.dispatchEvent(
|
||||
// new CustomEvent("wrnexus:modal:close", { bubbles: true })
|
||||
// )
|
||||
//
|
||||
// The listener is on the modal root, so the event only ever closes the
|
||||
// modal the dispatching element is actually inside -- no ids to wire up
|
||||
// and no way to close somebody else's modal by accident.
|
||||
client function hideModal(reason, sourceEvent) {
|
||||
visible = false
|
||||
output.close({
|
||||
@@ -98,23 +87,21 @@ component Modal {
|
||||
<div
|
||||
{...attrs}
|
||||
data-ui-component="Modal"
|
||||
data-open='{isOpen() ? "true" : "false"}'
|
||||
data-open='{open || visible ? "true" : "false"}'
|
||||
data-size='{size}'
|
||||
data-placement='{placement}'
|
||||
data-color='{color}'
|
||||
data-variant='{variant}'
|
||||
data-scrollable='{scrollable ? "true" : "false"}'
|
||||
data-scroll='{scrollBehavior}'
|
||||
data-destructive='{destructive ? "true" : "false"}'
|
||||
class='wire-modal {class}'
|
||||
@wrnexus:modal:close='hideModal("api", event)'
|
||||
>
|
||||
{#if triggerLabel}
|
||||
<button
|
||||
type="button"
|
||||
class="wire-modal__trigger"
|
||||
aria-haspopup="dialog"
|
||||
aria-expanded='{isOpen() ? "true" : "false"}'
|
||||
aria-expanded='{open || visible ? "true" : "false"}'
|
||||
@click='showModal(event)'
|
||||
>
|
||||
{#if triggerIcon}
|
||||
@@ -140,7 +127,7 @@ component Modal {
|
||||
|
||||
<div
|
||||
class="wire-modal__layer"
|
||||
data-show="isOpen()"
|
||||
data-show='{open || visible}'
|
||||
role="presentation"
|
||||
@keydown='handleKeydown(event)'
|
||||
>
|
||||
@@ -196,20 +183,11 @@ component Modal {
|
||||
aria-label='{closeLabel}'
|
||||
@click='hideModal("close-button", event)'
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
<span
|
||||
class="icon-[lucide--x]"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M18 6 6 18" />
|
||||
<path d="M6 6 18 18" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
{/if}
|
||||
</header>
|
||||
@@ -299,26 +277,16 @@ component Modal {
|
||||
--modal-contrast: var(--wire-color-secondary-contrast);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fallbacks below (the second var() argument): the theme token generator
|
||||
* (packages/styles/src/theme.ts) only emits a real -contrast token for
|
||||
* primary and secondary. info, success, and danger have no contrast
|
||||
* token defined at all, so var(--wire-color-info-contrast) with no
|
||||
* fallback resolves to nothing, and --modal-contrast becomes invalid --
|
||||
* which made confirm-button and solid-panel text unreadable. White is a
|
||||
* safe default against these saturated colors until the theme package
|
||||
* defines real tokens for them.
|
||||
*/
|
||||
.wire-modal[data-color="info"] {
|
||||
--modal-accent: var(--wire-color-info);
|
||||
--modal-soft: var(--wire-color-info-soft);
|
||||
--modal-contrast: var(--wire-color-info-contrast, white);
|
||||
--modal-contrast: var(--wire-color-info-contrast);
|
||||
}
|
||||
|
||||
.wire-modal[data-color="success"] {
|
||||
--modal-accent: var(--wire-color-success);
|
||||
--modal-soft: var(--wire-color-success-soft);
|
||||
--modal-contrast: var(--wire-color-success-contrast, white);
|
||||
--modal-contrast: var(--wire-color-success-contrast);
|
||||
}
|
||||
|
||||
.wire-modal[data-color="warning"] {
|
||||
@@ -331,7 +299,7 @@ component Modal {
|
||||
.wire-modal[data-destructive="true"] {
|
||||
--modal-accent: var(--wire-color-danger);
|
||||
--modal-soft: var(--wire-color-danger-soft);
|
||||
--modal-contrast: var(--wire-color-on-danger, white);
|
||||
--modal-contrast: var(--wire-color-on-danger);
|
||||
}
|
||||
|
||||
.wire-modal__trigger,
|
||||
@@ -353,35 +321,8 @@ component Modal {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 650;
|
||||
cursor: pointer;
|
||||
transition: opacity 150ms ease, transform 150ms ease, box-shadow 150ms ease;
|
||||
}
|
||||
|
||||
.wire-modal__trigger:hover {
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
.wire-modal__trigger:active {
|
||||
transform: scale(0.97);
|
||||
}
|
||||
|
||||
.wire-modal__trigger:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--modal-accent) 40%, transparent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hidden by default so the SSR-rendered HTML never paints the layer before
|
||||
* hydration runs. data-open on the wire-modal root is evaluated and
|
||||
* serialized to a real true or false string at render time -- a plain
|
||||
* bind, not the raw-expression data-show directive -- so this selector
|
||||
* is correct on first paint with zero flash, with no dependency on
|
||||
* client JS having run yet. The data-show attribute and client directive
|
||||
* still run after hydration to keep things in sync for state changes,
|
||||
* but visibility itself is driven by CSS here. visibility (rather than
|
||||
* display) is used so the open and close transitions below can actually
|
||||
* animate -- a box that starts at display: none has no prior frame to
|
||||
* transition from.
|
||||
*/
|
||||
.wire-modal__layer {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
@@ -390,15 +331,6 @@ component Modal {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1rem;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 180ms ease, visibility 0s linear 180ms;
|
||||
}
|
||||
|
||||
.wire-modal[data-open="true"] .wire-modal__layer {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity 180ms ease, visibility 0s linear 0s;
|
||||
}
|
||||
|
||||
.wire-modal[data-placement="top"] .wire-modal__layer {
|
||||
@@ -406,12 +338,6 @@ component Modal {
|
||||
padding-top: clamp(1rem, 8vh, 5rem);
|
||||
}
|
||||
|
||||
.wire-modal[data-scroll="page"] .wire-modal__layer {
|
||||
align-items: flex-start;
|
||||
overflow-y: auto;
|
||||
padding: 2.5rem 1rem;
|
||||
}
|
||||
|
||||
.wire-modal__backdrop {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
@@ -444,18 +370,6 @@ component Modal {
|
||||
0 1px 0 color-mix(in srgb, white 5%, transparent) inset,
|
||||
0 40px 110px color-mix(in srgb, black 38%, transparent);
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
transform: scale(0.96) translateY(10px);
|
||||
transition: opacity 180ms ease, transform 220ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
.wire-modal[data-open="true"] .wire-modal__panel {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.wire-modal[data-size="xs"] .wire-modal__panel {
|
||||
width: min(19rem, calc(100vw - 2rem));
|
||||
}
|
||||
|
||||
.wire-modal[data-size="sm"] .wire-modal__panel {
|
||||
@@ -476,10 +390,6 @@ component Modal {
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.wire-modal[data-scroll="page"] .wire-modal__panel {
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.wire-modal[data-variant="soft"] .wire-modal__panel {
|
||||
background:
|
||||
linear-gradient(145deg, var(--modal-soft), transparent 68%),
|
||||
@@ -537,7 +447,6 @@ component Modal {
|
||||
}
|
||||
|
||||
.wire-modal__heading-copy h2 {
|
||||
color: inherit;
|
||||
font-size: 1.08rem;
|
||||
font-weight: 650;
|
||||
line-height: 1.3;
|
||||
@@ -553,100 +462,32 @@ component Modal {
|
||||
color: color-mix(in srgb, currentColor 76%, transparent);
|
||||
}
|
||||
|
||||
/*
|
||||
* padding is reset explicitly: an app-level `button { padding: … }` rule
|
||||
* outranks the browser default, and 1rem of horizontal padding left this
|
||||
* 2.15rem button with a ~2px content box -- which squeezed the icon to
|
||||
* 0.4px wide and read as "the close button has no icon".
|
||||
*/
|
||||
.wire-modal__close {
|
||||
appearance: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 0 0 auto;
|
||||
padding: 0;
|
||||
width: 2.15rem;
|
||||
height: 2.15rem;
|
||||
width: 2.35rem;
|
||||
height: 2.35rem;
|
||||
color: var(--wire-color-text-muted);
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 9999px;
|
||||
cursor: pointer;
|
||||
transition: background 150ms ease, color 150ms ease, border-color 150ms ease, transform 150ms ease;
|
||||
}
|
||||
|
||||
/*
|
||||
* On a solid panel the background is the accent color, so the muted-grey
|
||||
* default is close to invisible -- the dismiss affordance reads as
|
||||
* missing rather than subtle. Derive it from the panel contrast color
|
||||
* instead, and give it a faint ring so it is unmistakably a control.
|
||||
*/
|
||||
.wire-modal[data-variant="solid"] .wire-modal__close {
|
||||
color: color-mix(in srgb, currentColor 82%, transparent);
|
||||
border-color: color-mix(in srgb, currentColor 35%, transparent);
|
||||
}
|
||||
|
||||
.wire-modal[data-variant="solid"] .wire-modal__close:hover {
|
||||
color: currentColor;
|
||||
background: color-mix(in srgb, black 18%, transparent);
|
||||
border-color: color-mix(in srgb, currentColor 55%, transparent);
|
||||
}
|
||||
|
||||
.wire-modal__close:hover {
|
||||
color: var(--wire-color-text);
|
||||
background: var(--wire-color-surface-soft);
|
||||
border: 1px solid var(--wire-color-border);
|
||||
border-radius: 0.75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wire-modal__close:hover,
|
||||
.wire-modal__close:focus-visible {
|
||||
color: var(--modal-accent);
|
||||
border-color: color-mix(in srgb, var(--modal-accent) 45%, transparent);
|
||||
border-color: color-mix(in srgb, var(--modal-accent) 34%, var(--wire-color-border));
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.wire-modal__close:active {
|
||||
transform: scale(0.92);
|
||||
}
|
||||
|
||||
/* Never let the glyph be shrunk by the flex container. */
|
||||
.wire-modal__close svg {
|
||||
flex: 0 0 auto;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Slot content is authored by the host app, so the app global stylesheet
|
||||
* styles it too. A bare element selector there (p { color: ... }) beats
|
||||
* anything the panel merely *inherits*, which is how solid-variant modals
|
||||
* ended up with muted grey body copy on a saturated accent background --
|
||||
* unreadable, and worst exactly where contrast matters most (the
|
||||
* destructive confirm). Setting the color on the body makes the panel
|
||||
* choice explicit instead of leaving it to inheritance.
|
||||
*
|
||||
* NOTE: apostrophes are avoided in .wrn style comments on purpose -- the
|
||||
* block scanner treats a quote as a string delimiter while it counts
|
||||
* braces, so a stray one breaks parsing of the whole component.
|
||||
*/
|
||||
.wire-modal__body {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
padding: 1.4rem;
|
||||
color: var(--wire-color-text);
|
||||
}
|
||||
|
||||
/*
|
||||
* :where() keeps this at the specificity of .wire-modal__body alone, so it
|
||||
* outranks a global element selector but still yields to any class the app
|
||||
* puts on its own slot content (an error message, a muted caption). A
|
||||
* plain .wire-modal__body p list would have quietly overridden those.
|
||||
*/
|
||||
.wire-modal__body :where(p, li, dd, dt, h1, h2, h3, h4, h5, h6, span, label, code) {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.wire-modal[data-variant="solid"] .wire-modal__body {
|
||||
color: var(--modal-contrast);
|
||||
}
|
||||
|
||||
.wire-modal[data-scrollable="true"] .wire-modal__body {
|
||||
@@ -707,18 +548,6 @@ component Modal {
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
/*
|
||||
* On a solid-variant panel the panel background is also --modal-accent,
|
||||
* so a plain primary button (same color) has no visible edge against it.
|
||||
* Darken the fill slightly and add a light border so the button still
|
||||
* reads as a distinct, clickable pill instead of blending into the panel.
|
||||
*/
|
||||
.wire-modal[data-variant="solid"] .wire-modal__button--primary {
|
||||
background: color-mix(in srgb, black 18%, var(--modal-accent));
|
||||
border-color: color-mix(in srgb, white 32%, transparent);
|
||||
box-shadow: 0 1px 0 color-mix(in srgb, white 12%, transparent) inset;
|
||||
}
|
||||
|
||||
.wire-modal__button:disabled {
|
||||
opacity: 0.55;
|
||||
cursor: not-allowed;
|
||||
@@ -746,7 +575,6 @@ component Modal {
|
||||
}
|
||||
|
||||
.wire-modal__panel,
|
||||
.wire-modal[data-size="xs"] .wire-modal__panel,
|
||||
.wire-modal[data-size="sm"] .wire-modal__panel,
|
||||
.wire-modal[data-size="lg"] .wire-modal__panel,
|
||||
.wire-modal[data-size="xl"] .wire-modal__panel {
|
||||
@@ -771,17 +599,10 @@ component Modal {
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.wire-modal__button,
|
||||
.wire-modal__spinner,
|
||||
.wire-modal__layer,
|
||||
.wire-modal__panel,
|
||||
.wire-modal__close {
|
||||
.wire-modal__spinner {
|
||||
animation: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.wire-modal__panel {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,13 +123,12 @@ component Popover {
|
||||
|
||||
<section
|
||||
class="wire-popover__panel"
|
||||
data-wrn-anchored="true"
|
||||
data-show='{open || visible}'
|
||||
role="dialog"
|
||||
aria-label='{title || triggerLabel}'
|
||||
>
|
||||
{#if showArrow}
|
||||
<span class="wire-popover__arrow" data-wrn-anchor-arrow="true" aria-hidden="true"></span>
|
||||
<span class="wire-popover__arrow" aria-hidden="true"></span>
|
||||
{/if}
|
||||
|
||||
{#if title || description || icon || showClose}
|
||||
@@ -472,13 +471,7 @@ component Popover {
|
||||
color: color-mix(in srgb, currentColor 76%, transparent);
|
||||
}
|
||||
|
||||
/*
|
||||
* padding is reset explicitly: an app-level `button { padding: ... }` rule
|
||||
* outranks the browser default and crushes the icon inside this
|
||||
* fixed-size button. Same trap as Modal and Drawer.
|
||||
*/
|
||||
.wire-popover__close {
|
||||
padding: 0;
|
||||
appearance: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
component Table {
|
||||
outputs {
|
||||
sort(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
|
||||
select(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
|
||||
rowClick(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
|
||||
}
|
||||
|
||||
props {
|
||||
size: string = "default"
|
||||
color: string = "primary"
|
||||
caption: string = "Table"
|
||||
columns: unknown[] = []
|
||||
rows: unknown[] = []
|
||||
striped: boolean = true
|
||||
class: string = ""
|
||||
}
|
||||
view {
|
||||
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--table {class}"><table><caption>{caption}</caption><thead><tr>{#each columns as column}<th>{column.label}</th>{/each}</tr></thead><tbody>{#each rows as row}<tr>{#each columns as column}<td>{row[column.key]}</td>{/each}</tr>{/each}</tbody></table><slot /></div>
|
||||
}
|
||||
}
|
||||
@@ -97,12 +97,11 @@ id: string = ""
|
||||
<span
|
||||
id='{id}'
|
||||
class="wire-tooltip__content"
|
||||
data-wrn-anchored="true"
|
||||
data-show='{open || visible}'
|
||||
role="tooltip"
|
||||
>
|
||||
{#if showArrow}
|
||||
<span class="wire-tooltip__arrow" data-wrn-anchor-arrow="true" aria-hidden="true"></span>
|
||||
<span class="wire-tooltip__arrow" aria-hidden="true"></span>
|
||||
{/if}
|
||||
|
||||
{#if title}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ui",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/ui — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -35,10 +35,6 @@
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
},
|
||||
"./registry": {
|
||||
"types": "./dist/registry.d.ts",
|
||||
"import": "./dist/registry.js"
|
||||
},
|
||||
"./components/*": "./components/*",
|
||||
"./component-catalog.json": "./component-catalog.json",
|
||||
"./component-migrations.json": "./component-migrations.json",
|
||||
@@ -46,7 +42,7 @@
|
||||
"./ui.css": "./ui.css"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.8.5"
|
||||
"@wrnexus/core": "^0.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -8037,6 +8037,28 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wire-next--table {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
border: 1px solid var(--wire-color-border);
|
||||
border-radius: var(--wire-radius-md);
|
||||
}
|
||||
.wire-next--table table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.wire-next--table caption,
|
||||
.wire-next--table th,
|
||||
.wire-next--table td {
|
||||
padding: 0.75rem;
|
||||
border-bottom: 1px solid var(--wire-color-border);
|
||||
text-align: left;
|
||||
}
|
||||
.wire-next--table caption,
|
||||
.wire-next--table th {
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
@keyframes wire-shimmer {
|
||||
to {
|
||||
background-position: -200% 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/uploader",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Secure upload drivers, policies, client runtime, helper functions, and reusable upload components.",
|
||||
"license": "MIT",
|
||||
@@ -42,9 +42,9 @@
|
||||
"./components/*": "./components/*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.8.5",
|
||||
"@wrnexus/plugin": "^0.8.5",
|
||||
"@wrnexus/ui": "^0.8.5"
|
||||
"@wrnexus/core": "^0.8.4",
|
||||
"@wrnexus/plugin": "^0.8.4",
|
||||
"@wrnexus/ui": "^0.8.4"
|
||||
},
|
||||
"wrnexus": {
|
||||
"plugin": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/validation",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Shared server/browser schemas, validation helpers, form runtime, and reusable error components.",
|
||||
"license": "MIT",
|
||||
@@ -42,9 +42,9 @@
|
||||
"./components/*": "./components/*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.8.5",
|
||||
"@wrnexus/plugin": "^0.8.5",
|
||||
"@wrnexus/ui": "^0.8.5"
|
||||
"@wrnexus/core": "^0.8.4",
|
||||
"@wrnexus/plugin": "^0.8.4",
|
||||
"@wrnexus/ui": "^0.8.4"
|
||||
},
|
||||
"wrnexus": {
|
||||
"plugin": {
|
||||
|
||||
@@ -107,11 +107,11 @@
|
||||
},
|
||||
"packages/ai": {
|
||||
"name": "@wrnexus/ai",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
},
|
||||
"packages/auth": {
|
||||
"name": "@wrnexus/auth",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/authz": "workspace:*",
|
||||
"@wrnexus/captcha": "workspace:*",
|
||||
@@ -133,7 +133,7 @@
|
||||
},
|
||||
"packages/authz": {
|
||||
"name": "@wrnexus/authz",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
"@wrnexus/db": "workspace:*",
|
||||
@@ -141,18 +141,18 @@
|
||||
},
|
||||
"packages/benchmark": {
|
||||
"name": "@wrnexus/benchmark",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
},
|
||||
"packages/cache": {
|
||||
"name": "@wrnexus/cache",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
},
|
||||
},
|
||||
"packages/captcha": {
|
||||
"name": "@wrnexus/captcha",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
"@wrnexus/plugin": "workspace:*",
|
||||
@@ -167,7 +167,7 @@
|
||||
},
|
||||
"packages/cli": {
|
||||
"name": "@wrnexus/cli",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"bin": {
|
||||
"wrnexus": "src/index.ts",
|
||||
},
|
||||
@@ -194,7 +194,7 @@
|
||||
},
|
||||
"packages/compiler": {
|
||||
"name": "@wrnexus/compiler",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/csr": "workspace:*",
|
||||
"@wrnexus/store": "workspace:*",
|
||||
@@ -204,7 +204,7 @@
|
||||
},
|
||||
"packages/content": {
|
||||
"name": "@wrnexus/content",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.14",
|
||||
"typescript": "^5.9.2",
|
||||
@@ -212,18 +212,18 @@
|
||||
},
|
||||
"packages/core": {
|
||||
"name": "@wrnexus/core",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
},
|
||||
"packages/csr": {
|
||||
"name": "@wrnexus/csr",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
},
|
||||
},
|
||||
"packages/db": {
|
||||
"name": "@wrnexus/db",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.14",
|
||||
"typescript": "^5.9.2",
|
||||
@@ -231,7 +231,7 @@
|
||||
},
|
||||
"packages/dev-server": {
|
||||
"name": "@wrnexus/dev-server",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/authz": "workspace:*",
|
||||
"@wrnexus/cache": "workspace:*",
|
||||
@@ -258,7 +258,7 @@
|
||||
},
|
||||
"packages/dev-toolbar": {
|
||||
"name": "@wrnexus/dev-toolbar",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.14",
|
||||
"typescript": "^5.9.2",
|
||||
@@ -266,7 +266,7 @@
|
||||
},
|
||||
"packages/encryption": {
|
||||
"name": "@wrnexus/encryption",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
},
|
||||
@@ -277,21 +277,21 @@
|
||||
},
|
||||
"packages/graphql": {
|
||||
"name": "@wrnexus/graphql",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/plugin": "workspace:*",
|
||||
},
|
||||
},
|
||||
"packages/helpers": {
|
||||
"name": "@wrnexus/helpers",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
},
|
||||
},
|
||||
"packages/i18n": {
|
||||
"name": "@wrnexus/i18n",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
"@wrnexus/plugin": "workspace:*",
|
||||
@@ -305,7 +305,7 @@
|
||||
},
|
||||
"packages/identity": {
|
||||
"name": "@wrnexus/identity",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/auth": "workspace:*",
|
||||
"@wrnexus/authz": "workspace:*",
|
||||
@@ -314,7 +314,7 @@
|
||||
},
|
||||
"packages/image": {
|
||||
"name": "@wrnexus/image",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/plugin": "workspace:*",
|
||||
"@wrnexus/security": "workspace:*",
|
||||
@@ -334,7 +334,7 @@
|
||||
},
|
||||
"packages/jwt": {
|
||||
"name": "@wrnexus/jwt",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
},
|
||||
@@ -345,7 +345,7 @@
|
||||
},
|
||||
"packages/language-server": {
|
||||
"name": "@wrnexus/language-server",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"bin": {
|
||||
"wrnexus-language-server": "src/server.ts",
|
||||
},
|
||||
@@ -356,39 +356,39 @@
|
||||
},
|
||||
"packages/mcp": {
|
||||
"name": "@wrnexus/mcp",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"bin": {
|
||||
"wrnexus-mcp": "src/stdio.ts",
|
||||
},
|
||||
},
|
||||
"packages/mobile": {
|
||||
"name": "@wrnexus/mobile",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/native": "workspace:*",
|
||||
},
|
||||
},
|
||||
"packages/native": {
|
||||
"name": "@wrnexus/native",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
},
|
||||
"packages/oauth": {
|
||||
"name": "@wrnexus/oauth",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/jwt": "workspace:*",
|
||||
},
|
||||
},
|
||||
"packages/observability": {
|
||||
"name": "@wrnexus/observability",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
},
|
||||
},
|
||||
"packages/playground": {
|
||||
"name": "@wrnexus/playground",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/compiler": "workspace:*",
|
||||
"@wrnexus/syntax": "workspace:*",
|
||||
@@ -396,18 +396,18 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@wrnexus/plugin",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/syntax": "workspace:*",
|
||||
},
|
||||
},
|
||||
"packages/pubsub": {
|
||||
"name": "@wrnexus/pubsub",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
},
|
||||
"packages/pwa": {
|
||||
"name": "@wrnexus/pwa",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.14",
|
||||
"typescript": "^5.9.2",
|
||||
@@ -415,18 +415,18 @@
|
||||
},
|
||||
"packages/queue": {
|
||||
"name": "@wrnexus/queue",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
},
|
||||
},
|
||||
"packages/reactive": {
|
||||
"name": "@wrnexus/reactive",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
},
|
||||
"packages/realtime": {
|
||||
"name": "@wrnexus/realtime",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
"@wrnexus/plugin": "workspace:*",
|
||||
@@ -440,7 +440,7 @@
|
||||
},
|
||||
"packages/router": {
|
||||
"name": "@wrnexus/router",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/compiler": "workspace:*",
|
||||
"@wrnexus/core": "workspace:*",
|
||||
@@ -448,7 +448,7 @@
|
||||
},
|
||||
"packages/rpc": {
|
||||
"name": "@wrnexus/rpc",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/authz": "workspace:*",
|
||||
"@wrnexus/core": "workspace:*",
|
||||
@@ -463,14 +463,14 @@
|
||||
},
|
||||
"packages/security": {
|
||||
"name": "@wrnexus/security",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
},
|
||||
},
|
||||
"packages/ssr": {
|
||||
"name": "@wrnexus/ssr",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
"@wrnexus/security": "workspace:*",
|
||||
@@ -479,11 +479,11 @@
|
||||
},
|
||||
"packages/store": {
|
||||
"name": "@wrnexus/store",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
},
|
||||
"packages/styles": {
|
||||
"name": "@wrnexus/styles",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
"@wrnexus/plugin": "workspace:*",
|
||||
@@ -492,19 +492,19 @@
|
||||
},
|
||||
"packages/syntax": {
|
||||
"name": "@wrnexus/syntax",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
},
|
||||
"packages/test": {
|
||||
"name": "@wrnexus/test",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
},
|
||||
"packages/tracking": {
|
||||
"name": "@wrnexus/tracking",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
},
|
||||
"packages/typecheck": {
|
||||
"name": "@wrnexus/typecheck",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/syntax": "workspace:*",
|
||||
"typescript": "^5.5.0",
|
||||
@@ -512,14 +512,14 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@wrnexus/ui",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
},
|
||||
},
|
||||
"packages/uploader": {
|
||||
"name": "@wrnexus/uploader",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
"@wrnexus/plugin": "workspace:*",
|
||||
@@ -533,7 +533,7 @@
|
||||
},
|
||||
"packages/validation": {
|
||||
"name": "@wrnexus/validation",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "workspace:*",
|
||||
"@wrnexus/plugin": "workspace:*",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,184 +0,0 @@
|
||||
# Navigation component group — design
|
||||
|
||||
Date: 2026-08-07
|
||||
Status: approved, not yet implemented
|
||||
|
||||
## Problem
|
||||
|
||||
The navigation group has nine components. Five of them — Nav, MegaMenu,
|
||||
Scrollspy, Pagination, Stepper — are byte-identical scaffold stubs that differ
|
||||
only in one CSS class name. Each renders `{#each items}<a href>{label}</a>{/each}`
|
||||
and nothing else. MegaMenu has no panel, Scrollspy never observes scroll,
|
||||
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-*` +
|
||||
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
|
||||
tabindex makes every inactive tab unreachable by Tab while arrows do nothing.
|
||||
|
||||
## Scope
|
||||
|
||||
All nine components, delivered in three phases.
|
||||
|
||||
## Decisions
|
||||
|
||||
### Styling
|
||||
|
||||
Every navigation component gets a local `style {}` block using `wire-*`
|
||||
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
|
||||
this work.
|
||||
|
||||
### Dropdowns: Nav vs MegaMenu
|
||||
|
||||
Both get dropdowns, of deliberately different kinds.
|
||||
|
||||
- **Nav** gets multi-level cascading submenus. It is the link bar, so nested
|
||||
submenus are its job.
|
||||
- **MegaMenu** gets a single-level rich panel: columns of grouped links with
|
||||
headings, descriptions and icons. This is deliberate, not a shortcut. A mega
|
||||
menu exists to show breadth flat so everything is one click away; nesting
|
||||
inside the panel buries content behind hover-within-hover and is close to
|
||||
unusable by keyboard and touch.
|
||||
|
||||
Neither reuses the existing Dropdown component: Dropdown is click-triggered and
|
||||
has no nesting support.
|
||||
|
||||
**Depth limit.** There is no recursive-component precedent in this library, so
|
||||
multi-level means fixed depth via nested `{#each}` loops — the pattern Navbar
|
||||
(4 loops) and Sidebar (2 loops) already use. Depth is **3 levels**. Unlimited
|
||||
nesting would require proving out component self-reference, which is out of
|
||||
scope here.
|
||||
|
||||
### Roving focus lives in the runtime
|
||||
|
||||
Arrow-key roving focus is identical logic for Tabs, Nav, MegaMenu, Sidebar and
|
||||
Stepper. It goes in the reactive runtime as a declarative attribute rather than
|
||||
five near-identical client functions:
|
||||
|
||||
- `data-wrn-roving="horizontal|vertical|both"` on the container
|
||||
- `[data-wrn-roving-item]` on each focusable child
|
||||
|
||||
The runtime owns arrow keys, Home/End, wrap-around, skip-disabled, and
|
||||
maintenance of the roving `tabindex`. Components declare intent only.
|
||||
|
||||
This follows the modal-dialog focus work already in the runtime, and for the
|
||||
same reason: a client function cannot hold focus state across callbacks,
|
||||
because state written after the function returns is dropped.
|
||||
|
||||
### Scrollspy needs runtime support too
|
||||
|
||||
`data-wrn-scrollspy` backed by `IntersectionObserver`. It cannot be a client
|
||||
function — the observer callback fires long after the function returns, and
|
||||
that state write would be lost.
|
||||
|
||||
### Runtime budget
|
||||
|
||||
Roving focus is roughly 3–4k, scrollspy roughly 1.5k. The runtime is at 167k
|
||||
against the 175k ceiling raised on 2026-08-07. This fits, but leaves little
|
||||
room. The group after this one forces the decision about splitting the runtime
|
||||
into loadable chunks so pages pay only for behaviour they use.
|
||||
|
||||
### Tabs URL mode
|
||||
|
||||
`mode="client" | "url"`. URL mode uses a query parameter (`?tab=value`) driven
|
||||
by `history.pushState`, so content swaps with no page load and the back button
|
||||
works.
|
||||
|
||||
Query parameter rather than hash: it is shareable, survives reload, and does
|
||||
not collide with in-page anchors or with Scrollspy, which wants the hash.
|
||||
|
||||
Tabs also gets a panel transition on change.
|
||||
|
||||
### Sidebar composes Drawer
|
||||
|
||||
Sidebar does not reimplement off-canvas behaviour. Desktop renders a static
|
||||
rail; mobile renders inside Drawer. This inherits Drawer's focus trap and
|
||||
scroll lock rather than duplicating them.
|
||||
|
||||
### Cross-cutting requirements
|
||||
|
||||
- Icons on every menu item, tab, and step
|
||||
- Dropdown arrows that animate on open
|
||||
- Responsive behaviour per component: Nav collapses to a toggle, MegaMenu
|
||||
stacks its panel, Tabs becomes a scrollable strip, Stepper goes vertical,
|
||||
Pagination goes compact
|
||||
- Full ARIA Authoring Practices patterns for each role, including correct
|
||||
`aria-current` / `aria-selected` / `aria-expanded`
|
||||
|
||||
## Components
|
||||
|
||||
| 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 |
|
||||
| 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 |
|
||||
| Scrollspy | Build. Observes section ids, moves `aria-current` to the matching link |
|
||||
| Navbar | Audit. Styles move to a local block, roving focus on the link group, keyboard for the mobile toggle |
|
||||
| Sidebar | Audit and extend. Local styles, composes Drawer for mobile, single items / labelled groups / multi-level (3 deep), vertical roving |
|
||||
| Breadcrumb | Audit only — already the strongest of the nine |
|
||||
|
||||
Component count stays at 108; all nine files already exist.
|
||||
|
||||
## Data flow
|
||||
|
||||
Props in, outputs out, no global state. Every component takes its data as props
|
||||
and reports interaction through declared `outputs`.
|
||||
|
||||
## Error handling
|
||||
|
||||
`items` arrives as an HTML attribute and is frequently a JSON string, so:
|
||||
|
||||
- A non-array `items` renders empty rather than throwing
|
||||
- Out-of-range `active` / `page` clamps to bounds
|
||||
|
||||
## Testing
|
||||
|
||||
- Per-component entries in `packages/ui/test/ui.test.ts` covering names,
|
||||
declared outputs and props
|
||||
- Showcase profiles for each so every component gets live demos
|
||||
- Regenerate component reference, catalog, showcase, and the UI visual contract
|
||||
- Each phase ends with `bun run check:production` green
|
||||
|
||||
## Phases
|
||||
|
||||
Each phase ends green, committed and pushed.
|
||||
|
||||
1. **Runtime and primitives** — roving-focus runtime, Nav, Pagination, Stepper
|
||||
2. **Composed** — Tabs (rewrite, URL sync, animation), Sidebar (on Drawer),
|
||||
MegaMenu
|
||||
3. **Audit and polish** — Navbar, Breadcrumb, Scrollspy, responsive pass,
|
||||
showcase generation
|
||||
|
||||
## Risks
|
||||
|
||||
- **Scrollspy and MegaMenu** are the only two needing new runtime behaviour.
|
||||
MegaMenu leans on the anchored clamp, which could not be verified
|
||||
interactively on 2026-08-07 because the browser pane was degraded
|
||||
(screenshots timing out, `scrollIntoView` inert). Verify the pane works
|
||||
before starting phase 2.
|
||||
- **Tabs is a breaking change.** Replacing raw `CustomEvent`s with declared
|
||||
outputs changes its public contract; anything listening for the old events
|
||||
breaks. 0.8.5 shipped on 2026-08-07, so this needs a migration entry in
|
||||
`packages/cli/src/update.ts`.
|
||||
|
||||
## Codebase constraints to respect
|
||||
|
||||
Hazards this codebase has already hit:
|
||||
|
||||
- No apostrophes in `.wrn` comments — the brace scanner breaks on them
|
||||
- `/* */` only inside style blocks; `//` is not a CSS comment and silently eats
|
||||
the following rule
|
||||
- No deferred state writes in client functions; state written after the
|
||||
function returns is dropped
|
||||
- Never call a peer function after an application callback — the wrapper
|
||||
flushes the entry-time snapshot
|
||||
- No boolean attributes bound to loop variables
|
||||
- Package components need explicit imports
|
||||
@@ -61,14 +61,14 @@
|
||||
"packages/ui/components/Map.wrn": "7b8a0d5412a464fd7cab8977d816542c506d8c5dab8230a3c984c2caee407c91",
|
||||
"packages/ui/components/MarketingSectionHeader.wrn": "7d6ffcc01a9331474475ea57ca58598be757abd9428b66bdfaf6f3603c5b145b",
|
||||
"packages/ui/components/Marquee.wrn": "b2b35eedf3297ba12ab3776385a9f3eab001027648d87a2a1968f576eee6c025",
|
||||
"packages/ui/components/MegaMenu.wrn": "48f4ced485df0e8de5217630c8bdcec0b2317bf04e6b279399f2c93d98d56995",
|
||||
"packages/ui/components/MegaMenu.wrn": "4a084eaf6aae77bb9023d2f3589bc6b80119b9be63982a90a80f9d280cc9c0a5",
|
||||
"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/Nav.wrn": "78f215c94caf68e0968449a23e23bd3409a689e0c52a6c1770aa8373c767d080",
|
||||
"packages/ui/components/Navbar.wrn": "e68f9d3643e500e43124e9c7a6d4c7f6722657377ea7313f3e3cf5093a81b360",
|
||||
"packages/ui/components/PageHeader.wrn": "0761235a4924eec09877be40b292d27b70db22d210be7d8e989493165c20df86",
|
||||
"packages/ui/components/Pagination.wrn": "9ceb74745b159150b015bbbb1974c68e14a7d4b92bd03491cb23b8855aa07983",
|
||||
"packages/ui/components/Pagination.wrn": "9169e724f89992dacd10e9492a95438c8016affb39c0fd17a4f6fe26bd21d8b4",
|
||||
"packages/ui/components/PinInput.wrn": "5196f584de8d548a5dfa03688c3c95da3c948cead2662b05e927386ccea74299",
|
||||
"packages/ui/components/Popover.wrn": "167f6c476cf3114ac5062ecf7739bddd9b5a81b1d209396a3675067dad1577b2",
|
||||
"packages/ui/components/PortalDashboard.wrn": "037d4300b59c7d60543abc7d4aba5c738efc143e9b61abc48aad0ddfcfe6845b",
|
||||
@@ -82,14 +82,14 @@
|
||||
"packages/ui/components/Section.wrn": "21485de07d8bb986837a65c61c5dd01ba6c2f3d4e37d58c154a584c7b58de0ed",
|
||||
"packages/ui/components/SectionHeader.wrn": "512cb96636ee1f0540a0f4b4c75603fc0fe7536e7ed7ed7dc82173a16f48a4d3",
|
||||
"packages/ui/components/Select.wrn": "7f046bb11b7c2470dae26d91a4b2261c66a40ae054d0e04c69b6748912d1e204",
|
||||
"packages/ui/components/Sidebar.wrn": "03f1bbce75ca6d50ed940e62df39c539610e89eadd2064fe24abc7d5470f98bf",
|
||||
"packages/ui/components/Sidebar.wrn": "05f4bd216ae8bfcee2460fe638e431174d5f3c8e10003f346644e5a2939e7ce5",
|
||||
"packages/ui/components/SplitHero.wrn": "70e843565ff869bcf413b11b6d9830b2e2bd229863a00904596f71e2dff0e76d",
|
||||
"packages/ui/components/StatsBar.wrn": "c7d1df3895f25b6d3a2e1012a18b97592c7f33e65418b880d486f20c2d490686",
|
||||
"packages/ui/components/Stepper.wrn": "09f216a44f888421091bd1bce760a076927500a573550d5b2b10c4f27f608e92",
|
||||
"packages/ui/components/Stepper.wrn": "4fec0c91a9006319ec27f3198d1176acdfd93abf62d76159aa55c0879bb081d9",
|
||||
"packages/ui/components/StrongPassword.wrn": "c7c5ef26ece6170dd7db9882f0dc98cb2e4607f1e5d43eb3fd39e5d15bbd3a2e",
|
||||
"packages/ui/components/StyledIcon.wrn": "4a4504e357dee9dd0418edbe85fc90b824ccdb3752123a2125da95b77bf0b336",
|
||||
"packages/ui/components/Switch.wrn": "ccb74599fab72b0d68b09a7f1f90b7732cb2f9cbed67a84219e897575ce30c28",
|
||||
"packages/ui/components/Tabs.wrn": "4fa0c0854700532960043290700d7cf99663ec41692068101f0aae4c2b1a1181",
|
||||
"packages/ui/components/Tabs.wrn": "8a1b98c7395b27b09f16f0ebdc14d3d84473b06023ec2b3ed0af495cc2f076bb",
|
||||
"packages/ui/components/TextLink.wrn": "30782039293eb36d63b7b3a4f32a71a47177a3a68c7e90184be7cf7b4385eb19",
|
||||
"packages/ui/components/Textarea.wrn": "ddf0b4f124b2cf0c0ab3d820d3ac0085f7c20466e977231949be264cd0cee8cf",
|
||||
"packages/ui/components/TimePicker.wrn": "2e8e7a90f6b6069a07e7ffd2725ba1e1031e84d55a4f1254025befbb314fa695",
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "wrnexus",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wrnexus",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
"dependencies": {
|
||||
"vscode-languageclient": "^10.1.0"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "wrnexus",
|
||||
"displayName": "WRNexus Language Support",
|
||||
"description": "Complete WRNexus v0.8.3 language support for typed imports, props, state, outputs, runtime functions, stores, diagnostics, formatting, navigation, and migration assistance.",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"publisher": "wrnexus",
|
||||
"private": true,
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// WRN editor extension source hash: 6afaf7958331407986761b491ad81d56458dcb162f56369a4cc29f86ff95d981
|
||||
// WRN editor extension source hash: 174fee91d6ec09c86f71f1204aeb46a20e5a563cc8af1484051d68dde01c8e10
|
||||
// WRN editor extension generator hash: 456d1d614e44e5fb1f19b784176c09cf2ade9b64ef73a17934c2698150b62728
|
||||
"use strict";
|
||||
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
// WRN editor language server source hash: c4362f7edf117e0c403c9bce9435bc02ae0febd963edb4af9a18d2d74d87eb47
|
||||
// WRN editor language server source hash: de46b5767d808fb99bb470ac9ccd0bc9504aa9ab40f0cf8ad9ec4e945303200d
|
||||
// WRN editor language server generator hash: f593a44aaf05495b789ce7a3086bee1eebb951b884d41c0e017bbcfe5f547e72
|
||||
// @bun @bun-cjs
|
||||
(function(exports, require, module, __filename, __dirname) {var __create = Object.create;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
// Generated by scripts/generate-showcase.mjs. Do not edit directly.
|
||||
page MegaMenuDetail {
|
||||
layout = "showcase"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_size = ctx.url.searchParams.get("pg_size") ?? "default"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_label = ctx.url.searchParams.get("pg_label") ?? "Mega Menu"
|
||||
state playground_icon = ctx.url.searchParams.get("pg_icon") ?? ""
|
||||
state playground_columns = JSON.parse(ctx.url.searchParams.get("pg_columns") ?? "[{\"id\":\"mega-menu-0-1\",\"key\":\"mega-menu-0-1\",\"value\":\"primary\",\"label\":\"Primary workflow\",\"title\":\"Primary workflow\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"A configurable sample message.\",\"href\":\"#mega-menu-demo\",\"actionHref\":\"#mega-menu-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":true,\"selected\":true,\"checked\":true,\"disabled\":false,\"outgoing\":false,\"open\":true,\"number\":1,\"count\":16,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 1\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]},{\"id\":\"mega-menu-0-2\",\"key\":\"mega-menu-0-2\",\"value\":\"secondary\",\"label\":\"Additional option\",\"title\":\"Supporting example\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"Another configurable message.\",\"href\":\"#mega-menu-demo\",\"actionHref\":\"#mega-menu-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":false,\"selected\":false,\"checked\":false,\"disabled\":false,\"outgoing\":true,\"open\":true,\"number\":2,\"count\":32,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 2\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]}]")
|
||||
state playground_footer = ctx.url.searchParams.get("pg_footer") ?? ""
|
||||
state playground_defaultOpen = (ctx.url.searchParams.get("pg_defaultOpen") ?? "false") === "true"
|
||||
state playground_items = JSON.parse(ctx.url.searchParams.get("pg_items") ?? "[{\"id\":\"mega-menu-0-1\",\"key\":\"mega-menu-0-1\",\"value\":\"primary\",\"label\":\"Primary workflow\",\"title\":\"Primary workflow\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"A configurable sample message.\",\"href\":\"#mega-menu-demo\",\"actionHref\":\"#mega-menu-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":true,\"selected\":true,\"checked\":true,\"disabled\":false,\"outgoing\":false,\"open\":true,\"number\":1,\"count\":16,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 1\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]},{\"id\":\"mega-menu-0-2\",\"key\":\"mega-menu-0-2\",\"value\":\"secondary\",\"label\":\"Additional option\",\"title\":\"Supporting example\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"Another configurable message.\",\"href\":\"#mega-menu-demo\",\"actionHref\":\"#mega-menu-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":false,\"selected\":false,\"checked\":false,\"disabled\":false,\"outgoing\":true,\"open\":true,\"number\":2,\"count\":32,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 2\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]}]")
|
||||
state playground_active = ctx.url.searchParams.get("pg_active") ?? ""
|
||||
state playground_orientation = ctx.url.searchParams.get("pg_orientation") ?? "horizontal"
|
||||
state playground_class = ctx.url.searchParams.get("pg_class") ?? "showcase-instance showcase-instance--1"
|
||||
seo {
|
||||
title = "Mega Menu"
|
||||
@@ -22,7 +21,7 @@ page MegaMenuDetail {
|
||||
<span class="showcase-eyebrow">Navigation component</span>
|
||||
<h1>Mega Menu</h1>
|
||||
<p>Theme-aware, responsive mega menu component.</p>
|
||||
<div class="detail-badges"><span>8 props</span><span>1 slots</span><span>3 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
<div class="detail-badges"><span>7 props</span><span>1 slots</span><span>3 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
</div>
|
||||
<div class="detail-hero-icon"><span class="icon-[lucide--component] size-10" aria-hidden="true"></span></div>
|
||||
</header>
|
||||
@@ -31,12 +30,11 @@ page MegaMenuDetail {
|
||||
<div class="playground-workbench">
|
||||
<div class="playground-preview">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
<div class="playground-preview-source" data-playground-preview><MegaMenu color='{playground_color}' size='{playground_size}' label='{playground_label}' icon='{playground_icon}' columns='{playground_columns}' footer='{playground_footer}' defaultOpen='{playground_defaultOpen}' class='{playground_class}' /></div>
|
||||
<div class="playground-preview-source" data-playground-preview><MegaMenu size='{playground_size}' color='{playground_color}' label='{playground_label}' items='{playground_items}' active='{playground_active}' orientation='{playground_orientation}' class='{playground_class}' /></div>
|
||||
<section class="playground-code" aria-label="Current component code">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component code</span><button type="button" data-playground-copy><span class="icon-[lucide--copy] size-4" aria-hidden="true"></span>Copy</button></header>
|
||||
<pre><code data-playground-code><MegaMenu
|
||||
label="Mega Menu"
|
||||
columns='[
|
||||
items='[
|
||||
<span>{</span>
|
||||
"id": "mega-menu-0-1",
|
||||
"key": "mega-menu-0-1",
|
||||
@@ -150,8 +148,8 @@ page MegaMenuDetail {
|
||||
<div class="playground-event-log" data-playground-event-log aria-live="polite"><strong>Event output</strong><span>Interact with the preview to inspect the typed <code>payload</code>.</span></div>
|
||||
</div>
|
||||
<form class="playground-controls" data-playground-form>
|
||||
<header><div><span>Component props</span><strong>8 controls</strong></div><button type="reset"><span class="icon-[lucide--rotate-ccw] size-4" aria-hidden="true"></span>Reset</button></header>
|
||||
<div class="playground-fields"><label class="playground-field" for="playground-mega-menu-color"><span><strong>color</strong><small>string</small></span><select id="playground-mega-menu-color" name="pg_color"><option value="primary" selected>primary</option><option value="secondary">secondary</option><option value="success">success</option><option value="warning">warning</option><option value="danger">danger</option><option value="info">info</option></select></label><label class="playground-field" for="playground-mega-menu-size"><span><strong>size</strong><small>string</small></span><select id="playground-mega-menu-size" name="pg_size"><option value="default" selected>default</option><option value="xs">xs</option><option value="sm">sm</option><option value="md">md</option><option value="lg">lg</option><option value="xl">xl</option><option value="icon">icon</option><option value="icon-xs">icon-xs</option><option value="icon-sm">icon-sm</option><option value="icon-lg">icon-lg</option></select></label><label class="playground-field" for="playground-mega-menu-label"><span><strong>label</strong><small>string</small></span><input id="playground-mega-menu-label" name="pg_label" type="text" value="Mega Menu" /></label><label class="playground-field" for="playground-mega-menu-icon"><span><strong>icon</strong><small>string</small></span><input id="playground-mega-menu-icon" name="pg_icon" type="text" value="" /></label><label class="playground-field" for="playground-mega-menu-columns"><span><strong>columns</strong><small>unknown[]</small></span><textarea id="playground-mega-menu-columns" name="pg_columns" rows="5" spellcheck="false" data-playground-json>[
|
||||
<header><div><span>Component props</span><strong>7 controls</strong></div><button type="reset"><span class="icon-[lucide--rotate-ccw] size-4" aria-hidden="true"></span>Reset</button></header>
|
||||
<div class="playground-fields"><label class="playground-field" for="playground-mega-menu-size"><span><strong>size</strong><small>string</small></span><select id="playground-mega-menu-size" name="pg_size"><option value="default" selected>default</option><option value="xs">xs</option><option value="sm">sm</option><option value="md">md</option><option value="lg">lg</option><option value="xl">xl</option><option value="icon">icon</option><option value="icon-xs">icon-xs</option><option value="icon-sm">icon-sm</option><option value="icon-lg">icon-lg</option></select></label><label class="playground-field" for="playground-mega-menu-color"><span><strong>color</strong><small>string</small></span><select id="playground-mega-menu-color" name="pg_color"><option value="primary" selected>primary</option><option value="secondary">secondary</option><option value="success">success</option><option value="warning">warning</option><option value="danger">danger</option><option value="info">info</option></select></label><label class="playground-field" for="playground-mega-menu-label"><span><strong>label</strong><small>string</small></span><input id="playground-mega-menu-label" name="pg_label" type="text" value="Mega Menu" /></label><label class="playground-field" for="playground-mega-menu-items"><span><strong>items</strong><small>unknown[]</small></span><textarea id="playground-mega-menu-items" name="pg_items" rows="5" spellcheck="false" data-playground-json>[
|
||||
{
|
||||
"id": "mega-menu-0-1",
|
||||
"key": "mega-menu-0-1",
|
||||
@@ -258,7 +256,7 @@ page MegaMenuDetail {
|
||||
"Standard"
|
||||
]
|
||||
}
|
||||
]</textarea><em data-playground-error></em></label><label class="playground-field" for="playground-mega-menu-footer"><span><strong>footer</strong><small>string</small></span><input id="playground-mega-menu-footer" name="pg_footer" type="text" value="" /></label><label class="playground-toggle" for="playground-mega-menu-defaultOpen"><span><strong>default Open</strong><small>boolean</small></span><input id="playground-mega-menu-defaultOpen" name="pg_defaultOpen" type="checkbox" value="true" data-playground-boolean /><i aria-hidden="true"></i></label><label class="playground-field" for="playground-mega-menu-class"><span><strong>class</strong><small>string</small></span><input id="playground-mega-menu-class" name="pg_class" type="text" value="showcase-instance showcase-instance--1" /></label></div>
|
||||
]</textarea><em data-playground-error></em></label><label class="playground-field" for="playground-mega-menu-active"><span><strong>active</strong><small>string</small></span><input id="playground-mega-menu-active" name="pg_active" type="text" value="" /></label><label class="playground-field" for="playground-mega-menu-orientation"><span><strong>orientation</strong><small>string</small></span><select id="playground-mega-menu-orientation" name="pg_orientation"><option value="horizontal" selected>horizontal</option><option value="vertical">vertical</option></select></label><label class="playground-field" for="playground-mega-menu-class"><span><strong>class</strong><small>string</small></span><input id="playground-mega-menu-class" name="pg_class" type="text" value="showcase-instance showcase-instance--1" /></label></div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
@@ -267,49 +265,123 @@ page MegaMenuDetail {
|
||||
<section class="detail-section"><div class="detail-section-heading"><span>Live examples</span><h2>Designed for real product surfaces</h2><p>Compare configurations and resize the browser to check responsive behavior.</p></div><div class="demo-list">
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Grouped columns</h2><p>One level deep by design: a mega menu shows breadth flat so everything is one click away. Nesting inside the panel would bury content behind hover-within-hover. Use Nav when you want cascading submenus.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Production default</h2><p>Balanced spacing, hierarchy, and content for the most common product workflow.</p></div>
|
||||
<span class="demo-case-number">01</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="mega-menu-demo-1" class="demo-canvas demo-canvas--1">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><MegaMenu size="default" label="Products" icon="icon-[lucide--box]" columns='[{"heading":"Platform","items":[{"label":"Runtime","href":"/runtime","description":"The browser half of the framework."},{"label":"Compiler","href":"/compiler","description":"WRN to JavaScript."}]},{"heading":"Tooling","items":[{"label":"CLI","href":"/cli","description":"Scaffold, build and deploy."},{"label":"Editor","href":"/editor","description":"Language server and syntax."}]}]' defaultOpen="false" class="showcase-instance showcase-instance--1" /></div>
|
||||
<div class="demo-render"><MegaMenu size="default" label="Mega Menu" items='[{"id":"mega-menu-0-1","key":"mega-menu-0-1","value":"primary","label":"Primary workflow","title":"Primary workflow","description":"A clean default configuration for everyday product interfaces.","text":"A configurable sample message.","href":"#mega-menu-demo","actionHref":"#mega-menu-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":16,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"mega-menu-0-2","key":"mega-menu-0-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A clean default configuration for everyday product interfaces.","text":"Another configurable message.","href":"#mega-menu-demo","actionHref":"#mega-menu-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":32,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' class="showcase-instance showcase-instance--1" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Grouped columns usage">
|
||||
<section class="demo-code" aria-label="Production default usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><MegaMenu
|
||||
label="Products"
|
||||
icon="icon-[lucide--box]"
|
||||
columns='[
|
||||
items='[
|
||||
<span>{</span>
|
||||
"heading": "Platform",
|
||||
"id": "mega-menu-0-1",
|
||||
"key": "mega-menu-0-1",
|
||||
"value": "primary",
|
||||
"label": "Primary workflow",
|
||||
"title": "Primary workflow",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#mega-menu-demo",
|
||||
"actionHref": "#mega-menu-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 16,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Runtime",
|
||||
"href": "/runtime",
|
||||
"description": "The browser half of the framework."
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Compiler",
|
||||
"href": "/compiler",
|
||||
"description": "WRN to JavaScript."
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"heading": "Tooling",
|
||||
"id": "mega-menu-0-2",
|
||||
"key": "mega-menu-0-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#mega-menu-demo",
|
||||
"actionHref": "#mega-menu-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": false,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 32,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "CLI",
|
||||
"href": "/cli",
|
||||
"description": "Scaffold, build and deploy."
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Editor",
|
||||
"href": "/editor",
|
||||
"description": "Language server and syntax."
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
@@ -319,57 +391,256 @@ page MegaMenuDetail {
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Advanced</span><h2>With a footer note</h2><p>The panel is anchored, so the runtime clamp pulls it back inside the viewport instead of letting it hang off a wide layout. On a phone it stops floating and joins the flow.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Dense UI</span><h2>Compact application</h2><p>A tighter variation for dashboards, side panels, tables, and operational interfaces.</p></div>
|
||||
<span class="demo-case-number">02</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="mega-menu-demo-2" class="demo-canvas demo-canvas--2">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><MegaMenu size="sm" label="Solutions" icon="icon-[lucide--arrow-right]" columns='[{"heading":"By team","items":[{"label":"Engineering","href":"/eng","icon":"icon-[lucide--code]"},{"label":"Design","href":"/design","icon":"icon-[lucide--palette]"},{"label":"Support","href":"/support","icon":"icon-[lucide--life-buoy]"}]},{"heading":"By size","items":[{"label":"Startup","href":"/startup"},{"label":"Enterprise","href":"/enterprise"}]}]' footer="Not sure where to start? Talk to us." defaultOpen="false" class="showcase-instance showcase-instance--2" /></div>
|
||||
<div class="demo-render"><MegaMenu size="sm" label="Compact example" items='[{"id":"mega-menu-1-1","key":"mega-menu-1-1","value":"primary","label":"Secondary workflow","title":"Secondary workflow","description":"A compact configuration designed for dense application layouts.","text":"A configurable sample message.","href":"#mega-menu-demo","actionHref":"#mega-menu-demo","actionLabel":"View details","icon":"icon-[lucide--zap]","iconClass":"icon-[lucide--zap]","variant":"secondary","status":"Active","time":"10:15","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":24,"percentage":48,"color":"#0284c7","target":"_self","ariaLabel":"Open secondary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"mega-menu-1-2","key":"mega-menu-1-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A compact configuration designed for dense application layouts.","text":"Another configurable message.","href":"#mega-menu-demo","actionHref":"#mega-menu-demo","actionLabel":"View details","icon":"icon-[lucide--zap]","iconClass":"icon-[lucide--zap]","variant":"secondary","status":"Active","time":"10:15","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":48,"percentage":48,"color":"#0284c7","target":"_self","ariaLabel":"Open secondary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' class="showcase-instance showcase-instance--2" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="With a footer note usage">
|
||||
<section class="demo-code" aria-label="Compact application usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><MegaMenu
|
||||
size="sm"
|
||||
label="Solutions"
|
||||
icon="icon-[lucide--arrow-right]"
|
||||
columns='[
|
||||
label="Compact example"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"heading": "By team",
|
||||
"id": "mega-menu-1-1",
|
||||
"key": "mega-menu-1-1",
|
||||
"value": "primary",
|
||||
"label": "Secondary workflow",
|
||||
"title": "Secondary workflow",
|
||||
"description": "A compact configuration designed for dense application layouts.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#mega-menu-demo",
|
||||
"actionHref": "#mega-menu-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--zap]",
|
||||
"iconClass": "icon-[lucide--zap]",
|
||||
"variant": "secondary",
|
||||
"status": "Active",
|
||||
"time": "10:15",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 24,
|
||||
"percentage": 48,
|
||||
"color": "#0284c7",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open secondary workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Engineering",
|
||||
"href": "/eng",
|
||||
"icon": "icon-[lucide--code]"
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Design",
|
||||
"href": "/design",
|
||||
"icon": "icon-[lucide--palette]"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Support",
|
||||
"href": "/support",
|
||||
"icon": "icon-[lucide--life-buoy]"
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"heading": "By size",
|
||||
"id": "mega-menu-1-2",
|
||||
"key": "mega-menu-1-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A compact configuration designed for dense application layouts.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#mega-menu-demo",
|
||||
"actionHref": "#mega-menu-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--zap]",
|
||||
"iconClass": "icon-[lucide--zap]",
|
||||
"variant": "secondary",
|
||||
"status": "Active",
|
||||
"time": "10:15",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": false,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 48,
|
||||
"percentage": 48,
|
||||
"color": "#0284c7",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open secondary workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Startup",
|
||||
"href": "/startup"
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Enterprise",
|
||||
"href": "/enterprise"
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Extended</span><h2>Rich configuration</h2><p>A more expressive variation using additional data, stronger emphasis, and optional states.</p></div>
|
||||
<span class="demo-case-number">03</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="mega-menu-demo-3" class="demo-canvas demo-canvas--3">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><MegaMenu size="lg" label="Advanced example" items='[{"id":"mega-menu-2-1","key":"mega-menu-2-1","value":"primary","label":"Advanced workflow","title":"Advanced workflow","description":"A richer configuration with more supporting information and actions.","text":"A configurable sample message.","href":"#mega-menu-demo","actionHref":"#mega-menu-demo","actionLabel":"Explore workflow","icon":"icon-[lucide--circle-check]","iconClass":"icon-[lucide--circle-check]","variant":"success","status":"Complete","time":"11:45","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":32,"percentage":91,"color":"#059669","target":"_self","ariaLabel":"Open advanced workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Unlimited"]},{"id":"mega-menu-2-2","key":"mega-menu-2-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A richer configuration with more supporting information and actions.","text":"Another configurable message.","href":"#mega-menu-demo","actionHref":"#mega-menu-demo","actionLabel":"Explore workflow","icon":"icon-[lucide--circle-check]","iconClass":"icon-[lucide--circle-check]","variant":"success","status":"Complete","time":"11:45","current":false,"selected":false,"checked":false,"disabled":true,"outgoing":true,"open":true,"number":2,"count":64,"percentage":91,"color":"#059669","target":"_self","ariaLabel":"Open advanced workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Unlimited"]}]' class="showcase-instance showcase-instance--3" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Rich configuration usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><MegaMenu
|
||||
size="lg"
|
||||
label="Advanced example"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"id": "mega-menu-2-1",
|
||||
"key": "mega-menu-2-1",
|
||||
"value": "primary",
|
||||
"label": "Advanced workflow",
|
||||
"title": "Advanced workflow",
|
||||
"description": "A richer configuration with more supporting information and actions.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#mega-menu-demo",
|
||||
"actionHref": "#mega-menu-demo",
|
||||
"actionLabel": "Explore workflow",
|
||||
"icon": "icon-[lucide--circle-check]",
|
||||
"iconClass": "icon-[lucide--circle-check]",
|
||||
"variant": "success",
|
||||
"status": "Complete",
|
||||
"time": "11:45",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 32,
|
||||
"percentage": 91,
|
||||
"color": "#059669",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open advanced workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Unlimited"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"id": "mega-menu-2-2",
|
||||
"key": "mega-menu-2-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A richer configuration with more supporting information and actions.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#mega-menu-demo",
|
||||
"actionHref": "#mega-menu-demo",
|
||||
"actionLabel": "Explore workflow",
|
||||
"icon": "icon-[lucide--circle-check]",
|
||||
"iconClass": "icon-[lucide--circle-check]",
|
||||
"variant": "success",
|
||||
"status": "Complete",
|
||||
"time": "11:45",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": true,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 64,
|
||||
"percentage": 91,
|
||||
"color": "#059669",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open advanced workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Unlimited"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
footer="Not sure where to start? Talk to us."
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
@@ -393,10 +664,10 @@ if (component) registerOutputHandler(component, "close", (payload) => <span>&
|
||||
if (component) registerOutputHandler(component, "select", (payload) => <span>{</span>
|
||||
console.log("select", payload)
|
||||
<span>}</span>)</code></pre></section></div></div></section>
|
||||
<section id="api" class="detail-section"><div class="detail-section-heading"><span>Component API</span><h2>Props and configuration</h2><p>All content and behavior shown above is supplied through these props and slots.</p></div><div class="docs-table-wrap"><table class="docs-table"><thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Required</th></tr></thead><tbody><tr><td><code>color</code></td><td>string</td><td><code>"primary"</code></td><td>No</td></tr><tr><td><code>size</code></td><td>string</td><td><code>"default"</code></td><td>No</td></tr><tr><td><code>label</code></td><td>string</td><td><code>"Menu"</code></td><td>No</td></tr><tr><td><code>icon</code></td><td>string</td><td><code>""</code></td><td>No</td></tr><tr><td><code>columns</code></td><td>unknown[]</td><td><code>[]</code></td><td>No</td></tr><tr><td><code>footer</code></td><td>string</td><td><code>""</code></td><td>No</td></tr><tr><td><code>defaultOpen</code></td><td>boolean</td><td><code>false</code></td><td>No</td></tr><tr><td><code>class</code></td><td>string</td><td><code>""</code></td><td>No</td></tr></tbody></table></div></section>
|
||||
<section id="api" class="detail-section"><div class="detail-section-heading"><span>Component API</span><h2>Props and configuration</h2><p>All content and behavior shown above is supplied through these props and slots.</p></div><div class="docs-table-wrap"><table class="docs-table"><thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Required</th></tr></thead><tbody><tr><td><code>size</code></td><td>string</td><td><code>"default"</code></td><td>No</td></tr><tr><td><code>color</code></td><td>string</td><td><code>"primary"</code></td><td>No</td></tr><tr><td><code>label</code></td><td>string</td><td><code>"Mega Menu"</code></td><td>No</td></tr><tr><td><code>items</code></td><td>unknown[]</td><td><code>[]</code></td><td>No</td></tr><tr><td><code>active</code></td><td>string</td><td><code>""</code></td><td>No</td></tr><tr><td><code>orientation</code></td><td>string</td><td><code>"horizontal"</code></td><td>No</td></tr><tr><td><code>class</code></td><td>string</td><td><code>""</code></td><td>No</td></tr></tbody></table></div></section>
|
||||
</main>
|
||||
<aside class="detail-aside">
|
||||
<div class="detail-toc"><strong>On this page</strong><a href="#playground">Playground</a><a href="#mega-menu-demo-1">Grouped columns</a><a href="#mega-menu-demo-2">With a footer note</a><a href="#events">Outputs</a><a href="#api">Props API</a></div>
|
||||
<div class="detail-toc"><strong>On this page</strong><a href="#playground">Playground</a><a href="#mega-menu-demo-1">Production default</a><a href="#mega-menu-demo-2">Compact application</a><a href="#mega-menu-demo-3">Rich configuration</a><a href="#events">Outputs</a><a href="#api">Props API</a></div>
|
||||
</aside>
|
||||
</div>
|
||||
<nav class="detail-pagination">
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
// Generated by scripts/generate-showcase.mjs. Do not edit directly.
|
||||
page NavDetail {
|
||||
layout = "showcase"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_size = ctx.url.searchParams.get("pg_size") ?? "default"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_label = ctx.url.searchParams.get("pg_label") ?? "Nav"
|
||||
state playground_items = JSON.parse(ctx.url.searchParams.get("pg_items") ?? "[{\"id\":\"nav-0-1\",\"key\":\"nav-0-1\",\"value\":\"primary\",\"label\":\"Primary workflow\",\"title\":\"Primary workflow\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"A configurable sample message.\",\"href\":\"#nav-demo\",\"actionHref\":\"#nav-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":true,\"selected\":true,\"checked\":true,\"disabled\":false,\"outgoing\":false,\"open\":true,\"number\":1,\"count\":16,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 1\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]},{\"id\":\"nav-0-2\",\"key\":\"nav-0-2\",\"value\":\"secondary\",\"label\":\"Additional option\",\"title\":\"Supporting example\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"Another configurable message.\",\"href\":\"#nav-demo\",\"actionHref\":\"#nav-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":false,\"selected\":false,\"checked\":false,\"disabled\":false,\"outgoing\":true,\"open\":true,\"number\":2,\"count\":32,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 2\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]}]")
|
||||
state playground_active = ctx.url.searchParams.get("pg_active") ?? ""
|
||||
state playground_orientation = ctx.url.searchParams.get("pg_orientation") ?? "horizontal"
|
||||
state playground_label = ctx.url.searchParams.get("pg_label") ?? "Nav"
|
||||
state playground_collapsible = (ctx.url.searchParams.get("pg_collapsible") ?? "true") === "true"
|
||||
state playground_toggleLabel = ctx.url.searchParams.get("pg_toggleLabel") ?? "Nav"
|
||||
state playground_class = ctx.url.searchParams.get("pg_class") ?? "showcase-instance showcase-instance--1"
|
||||
seo {
|
||||
title = "Nav"
|
||||
@@ -23,16 +21,16 @@ page NavDetail {
|
||||
<span class="showcase-eyebrow">Navigation component</span>
|
||||
<h1>Nav</h1>
|
||||
<p>Theme-aware, responsive nav component.</p>
|
||||
<div class="detail-badges"><span>9 props</span><span>1 slots</span><span>1 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
<div class="detail-badges"><span>7 props</span><span>1 slots</span><span>2 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
</div>
|
||||
<div class="detail-hero-icon"><span class="icon-[lucide--component] size-10" aria-hidden="true"></span></div>
|
||||
</header>
|
||||
<section id="playground" class="detail-section playground-section" data-playground data-playground-component="Nav" data-playground-public-tag="true" data-playground-has-slot="true" data-playground-events="select">
|
||||
<section id="playground" class="detail-section playground-section" data-playground data-playground-component="Nav" data-playground-public-tag="true" data-playground-has-slot="true" data-playground-events="select,change">
|
||||
<div class="detail-section-heading"><span>Interactive playground</span><h2>Configure Nav</h2><p>Change any prop and inspect the server-rendered component immediately.</p></div>
|
||||
<div class="playground-workbench">
|
||||
<div class="playground-preview">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
<div class="playground-preview-source" data-playground-preview><Nav color='{playground_color}' size='{playground_size}' items='{playground_items}' active='{playground_active}' orientation='{playground_orientation}' label='{playground_label}' collapsible='{playground_collapsible}' toggleLabel='{playground_toggleLabel}' class='{playground_class}' /></div>
|
||||
<div class="playground-preview-source" data-playground-preview><Nav size='{playground_size}' color='{playground_color}' label='{playground_label}' items='{playground_items}' active='{playground_active}' orientation='{playground_orientation}' class='{playground_class}' /></div>
|
||||
<section class="playground-code" aria-label="Current component code">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component code</span><button type="button" data-playground-copy><span class="icon-[lucide--copy] size-4" aria-hidden="true"></span>Copy</button></header>
|
||||
<pre><code data-playground-code><Nav
|
||||
@@ -144,16 +142,14 @@ page NavDetail {
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
label="Nav"
|
||||
toggleLabel="Nav"
|
||||
/></code></pre>
|
||||
</section>
|
||||
<div class="playground-status" data-playground-status aria-live="polite"></div>
|
||||
<div class="playground-event-log" data-playground-event-log aria-live="polite"><strong>Event output</strong><span>Interact with the preview to inspect the typed <code>payload</code>.</span></div>
|
||||
</div>
|
||||
<form class="playground-controls" data-playground-form>
|
||||
<header><div><span>Component props</span><strong>9 controls</strong></div><button type="reset"><span class="icon-[lucide--rotate-ccw] size-4" aria-hidden="true"></span>Reset</button></header>
|
||||
<div class="playground-fields"><label class="playground-field" for="playground-nav-color"><span><strong>color</strong><small>string</small></span><select id="playground-nav-color" name="pg_color"><option value="primary" selected>primary</option><option value="secondary">secondary</option><option value="success">success</option><option value="warning">warning</option><option value="danger">danger</option><option value="info">info</option></select></label><label class="playground-field" for="playground-nav-size"><span><strong>size</strong><small>string</small></span><select id="playground-nav-size" name="pg_size"><option value="default" selected>default</option><option value="xs">xs</option><option value="sm">sm</option><option value="md">md</option><option value="lg">lg</option><option value="xl">xl</option><option value="icon">icon</option><option value="icon-xs">icon-xs</option><option value="icon-sm">icon-sm</option><option value="icon-lg">icon-lg</option></select></label><label class="playground-field" for="playground-nav-items"><span><strong>items</strong><small>unknown[]</small></span><textarea id="playground-nav-items" name="pg_items" rows="5" spellcheck="false" data-playground-json>[
|
||||
<header><div><span>Component props</span><strong>7 controls</strong></div><button type="reset"><span class="icon-[lucide--rotate-ccw] size-4" aria-hidden="true"></span>Reset</button></header>
|
||||
<div class="playground-fields"><label class="playground-field" for="playground-nav-size"><span><strong>size</strong><small>string</small></span><select id="playground-nav-size" name="pg_size"><option value="default" selected>default</option><option value="xs">xs</option><option value="sm">sm</option><option value="md">md</option><option value="lg">lg</option><option value="xl">xl</option><option value="icon">icon</option><option value="icon-xs">icon-xs</option><option value="icon-sm">icon-sm</option><option value="icon-lg">icon-lg</option></select></label><label class="playground-field" for="playground-nav-color"><span><strong>color</strong><small>string</small></span><select id="playground-nav-color" name="pg_color"><option value="primary" selected>primary</option><option value="secondary">secondary</option><option value="success">success</option><option value="warning">warning</option><option value="danger">danger</option><option value="info">info</option></select></label><label class="playground-field" for="playground-nav-label"><span><strong>label</strong><small>string</small></span><input id="playground-nav-label" name="pg_label" type="text" value="Nav" /></label><label class="playground-field" for="playground-nav-items"><span><strong>items</strong><small>unknown[]</small></span><textarea id="playground-nav-items" name="pg_items" rows="5" spellcheck="false" data-playground-json>[
|
||||
{
|
||||
"id": "nav-0-1",
|
||||
"key": "nav-0-1",
|
||||
@@ -260,7 +256,7 @@ page NavDetail {
|
||||
"Standard"
|
||||
]
|
||||
}
|
||||
]</textarea><em data-playground-error></em></label><label class="playground-field" for="playground-nav-active"><span><strong>active</strong><small>string</small></span><input id="playground-nav-active" name="pg_active" type="text" value="" /></label><label class="playground-field" for="playground-nav-orientation"><span><strong>orientation</strong><small>string</small></span><select id="playground-nav-orientation" name="pg_orientation"><option value="horizontal" selected>horizontal</option><option value="vertical">vertical</option></select></label><label class="playground-field" for="playground-nav-label"><span><strong>label</strong><small>string</small></span><input id="playground-nav-label" name="pg_label" type="text" value="Nav" /></label><label class="playground-toggle" for="playground-nav-collapsible"><span><strong>collapsible</strong><small>boolean</small></span><input id="playground-nav-collapsible" name="pg_collapsible" type="checkbox" value="true" checked data-playground-boolean /><i aria-hidden="true"></i></label><label class="playground-field" for="playground-nav-toggleLabel"><span><strong>toggle Label</strong><small>string</small></span><input id="playground-nav-toggleLabel" name="pg_toggleLabel" type="text" value="Nav" /></label><label class="playground-field" for="playground-nav-class"><span><strong>class</strong><small>string</small></span><input id="playground-nav-class" name="pg_class" type="text" value="showcase-instance showcase-instance--1" /></label></div>
|
||||
]</textarea><em data-playground-error></em></label><label class="playground-field" for="playground-nav-active"><span><strong>active</strong><small>string</small></span><input id="playground-nav-active" name="pg_active" type="text" value="" /></label><label class="playground-field" for="playground-nav-orientation"><span><strong>orientation</strong><small>string</small></span><select id="playground-nav-orientation" name="pg_orientation"><option value="horizontal" selected>horizontal</option><option value="vertical">vertical</option></select></label><label class="playground-field" for="playground-nav-class"><span><strong>class</strong><small>string</small></span><input id="playground-nav-class" name="pg_class" type="text" value="showcase-instance showcase-instance--1" /></label></div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
@@ -269,163 +265,404 @@ page NavDetail {
|
||||
<section class="detail-section"><div class="detail-section-heading"><span>Live examples</span><h2>Designed for real product surfaces</h2><p>Compare configurations and resize the browser to check responsive behavior.</p></div><div class="demo-list">
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Horizontal links</h2><p>A flat link bar. The active item is marked with aria-current, and the arrow keys move between items.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Production default</h2><p>Balanced spacing, hierarchy, and content for the most common product workflow.</p></div>
|
||||
<span class="demo-case-number">01</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="nav-demo-1" class="demo-canvas demo-canvas--1">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Nav size="default" items='[{"label":"Home","href":"/","value":"home","icon":"icon-[lucide--house]"},{"label":"Inbox","href":"/inbox","value":"inbox","badge":"9"},{"label":"Reports","href":"/reports","value":"reports"},{"label":"Archive","href":"/archive","value":"archive","disabled":true}]' active="inbox" label="Nav" collapsible="true" toggleLabel="Nav" class="showcase-instance showcase-instance--1" /></div>
|
||||
<div class="demo-render"><Nav size="default" label="Nav" items='[{"id":"nav-0-1","key":"nav-0-1","value":"primary","label":"Primary workflow","title":"Primary workflow","description":"A clean default configuration for everyday product interfaces.","text":"A configurable sample message.","href":"#nav-demo","actionHref":"#nav-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":16,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"nav-0-2","key":"nav-0-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A clean default configuration for everyday product interfaces.","text":"Another configurable message.","href":"#nav-demo","actionHref":"#nav-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":32,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' class="showcase-instance showcase-instance--1" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Horizontal links usage">
|
||||
<section class="demo-code" aria-label="Production default usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Nav
|
||||
items='[
|
||||
<span>{</span>
|
||||
"label": "Home",
|
||||
"href": "/",
|
||||
"value": "home",
|
||||
"icon": "icon-[lucide--house]"
|
||||
"id": "nav-0-1",
|
||||
"key": "nav-0-1",
|
||||
"value": "primary",
|
||||
"label": "Primary workflow",
|
||||
"title": "Primary workflow",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#nav-demo",
|
||||
"actionHref": "#nav-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 16,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Inbox",
|
||||
"href": "/inbox",
|
||||
"value": "inbox",
|
||||
"badge": "9"
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Reports",
|
||||
"href": "/reports",
|
||||
"value": "reports"
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Archive",
|
||||
"href": "/archive",
|
||||
"value": "archive",
|
||||
"disabled": true
|
||||
"id": "nav-0-2",
|
||||
"key": "nav-0-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#nav-demo",
|
||||
"actionHref": "#nav-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": false,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 32,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
active="inbox"
|
||||
label="Nav"
|
||||
toggleLabel="Nav"
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Advanced</span><h2>Nested submenus</h2><p>An item carrying its own items array opens a submenu on hover or focus, to a maximum of three levels. On a phone the submenus stack inline instead of floating, because a hover-opened overlay is unreachable on touch.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Dense UI</span><h2>Compact application</h2><p>A tighter variation for dashboards, side panels, tables, and operational interfaces.</p></div>
|
||||
<span class="demo-case-number">02</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="nav-demo-2" class="demo-canvas demo-canvas--2">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Nav size="sm" items='[{"label":"Home","href":"/","value":"home"},{"label":"Products","value":"products","items":[{"label":"Overview","href":"/p","value":"p-overview"},{"label":"Platform","value":"p-platform","items":[{"label":"Runtime","href":"/p/runtime","value":"runtime"},{"label":"Compiler","href":"/p/compiler","value":"compiler"}]}]}]' active="p-overview" label="Compact example" collapsible="true" toggleLabel="Compact example" class="showcase-instance showcase-instance--2" /></div>
|
||||
<div class="demo-render"><Nav size="sm" label="Compact example" items='[{"id":"nav-1-1","key":"nav-1-1","value":"primary","label":"Secondary workflow","title":"Secondary workflow","description":"A compact configuration designed for dense application layouts.","text":"A configurable sample message.","href":"#nav-demo","actionHref":"#nav-demo","actionLabel":"View details","icon":"icon-[lucide--zap]","iconClass":"icon-[lucide--zap]","variant":"secondary","status":"Active","time":"10:15","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":24,"percentage":48,"color":"#0284c7","target":"_self","ariaLabel":"Open secondary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"nav-1-2","key":"nav-1-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A compact configuration designed for dense application layouts.","text":"Another configurable message.","href":"#nav-demo","actionHref":"#nav-demo","actionLabel":"View details","icon":"icon-[lucide--zap]","iconClass":"icon-[lucide--zap]","variant":"secondary","status":"Active","time":"10:15","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":48,"percentage":48,"color":"#0284c7","target":"_self","ariaLabel":"Open secondary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' class="showcase-instance showcase-instance--2" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Nested submenus usage">
|
||||
<section class="demo-code" aria-label="Compact application usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Nav
|
||||
size="sm"
|
||||
label="Compact example"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"label": "Home",
|
||||
"href": "/",
|
||||
"value": "home"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Products",
|
||||
"value": "products",
|
||||
"id": "nav-1-1",
|
||||
"key": "nav-1-1",
|
||||
"value": "primary",
|
||||
"label": "Secondary workflow",
|
||||
"title": "Secondary workflow",
|
||||
"description": "A compact configuration designed for dense application layouts.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#nav-demo",
|
||||
"actionHref": "#nav-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--zap]",
|
||||
"iconClass": "icon-[lucide--zap]",
|
||||
"variant": "secondary",
|
||||
"status": "Active",
|
||||
"time": "10:15",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 24,
|
||||
"percentage": 48,
|
||||
"color": "#0284c7",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open secondary workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Overview",
|
||||
"href": "/p",
|
||||
"value": "p-overview"
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Platform",
|
||||
"value": "p-platform",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Runtime",
|
||||
"href": "/p/runtime",
|
||||
"value": "runtime"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Compiler",
|
||||
"href": "/p/compiler",
|
||||
"value": "compiler"
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"id": "nav-1-2",
|
||||
"key": "nav-1-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A compact configuration designed for dense application layouts.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#nav-demo",
|
||||
"actionHref": "#nav-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--zap]",
|
||||
"iconClass": "icon-[lucide--zap]",
|
||||
"variant": "secondary",
|
||||
"status": "Active",
|
||||
"time": "10:15",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": false,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 48,
|
||||
"percentage": 48,
|
||||
"color": "#0284c7",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open secondary workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
active="p-overview"
|
||||
label="Compact example"
|
||||
toggleLabel="Compact example"
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Vertical rail</h2><p>Vertical orientation switches the arrow keys to up and down.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Extended</span><h2>Rich configuration</h2><p>A more expressive variation using additional data, stronger emphasis, and optional states.</p></div>
|
||||
<span class="demo-case-number">03</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="nav-demo-3" class="demo-canvas demo-canvas--3">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Nav size="lg" items='[{"label":"Dashboard","href":"/","value":"dash","icon":"icon-[lucide--gauge]"},{"label":"Team","href":"/team","value":"team","icon":"icon-[lucide--users]"},{"label":"Settings","href":"/settings","value":"settings","icon":"icon-[lucide--settings]"}]' active="team" orientation="vertical" label="Advanced example" collapsible="false" toggleLabel="Advanced example" class="showcase-instance showcase-instance--3" /></div>
|
||||
<div class="demo-render"><Nav size="lg" label="Advanced example" items='[{"id":"nav-2-1","key":"nav-2-1","value":"primary","label":"Advanced workflow","title":"Advanced workflow","description":"A richer configuration with more supporting information and actions.","text":"A configurable sample message.","href":"#nav-demo","actionHref":"#nav-demo","actionLabel":"Explore workflow","icon":"icon-[lucide--circle-check]","iconClass":"icon-[lucide--circle-check]","variant":"success","status":"Complete","time":"11:45","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":32,"percentage":91,"color":"#059669","target":"_self","ariaLabel":"Open advanced workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Unlimited"]},{"id":"nav-2-2","key":"nav-2-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A richer configuration with more supporting information and actions.","text":"Another configurable message.","href":"#nav-demo","actionHref":"#nav-demo","actionLabel":"Explore workflow","icon":"icon-[lucide--circle-check]","iconClass":"icon-[lucide--circle-check]","variant":"success","status":"Complete","time":"11:45","current":false,"selected":false,"checked":false,"disabled":true,"outgoing":true,"open":true,"number":2,"count":64,"percentage":91,"color":"#059669","target":"_self","ariaLabel":"Open advanced workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Unlimited"]}]' class="showcase-instance showcase-instance--3" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Vertical rail usage">
|
||||
<section class="demo-code" aria-label="Rich configuration usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Nav
|
||||
size="lg"
|
||||
label="Advanced example"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"label": "Dashboard",
|
||||
"href": "/",
|
||||
"value": "dash",
|
||||
"icon": "icon-[lucide--gauge]"
|
||||
"id": "nav-2-1",
|
||||
"key": "nav-2-1",
|
||||
"value": "primary",
|
||||
"label": "Advanced workflow",
|
||||
"title": "Advanced workflow",
|
||||
"description": "A richer configuration with more supporting information and actions.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#nav-demo",
|
||||
"actionHref": "#nav-demo",
|
||||
"actionLabel": "Explore workflow",
|
||||
"icon": "icon-[lucide--circle-check]",
|
||||
"iconClass": "icon-[lucide--circle-check]",
|
||||
"variant": "success",
|
||||
"status": "Complete",
|
||||
"time": "11:45",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 32,
|
||||
"percentage": 91,
|
||||
"color": "#059669",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open advanced workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Team",
|
||||
"href": "/team",
|
||||
"value": "team",
|
||||
"icon": "icon-[lucide--users]"
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Settings",
|
||||
"href": "/settings",
|
||||
"value": "settings",
|
||||
"icon": "icon-[lucide--settings]"
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Unlimited"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"id": "nav-2-2",
|
||||
"key": "nav-2-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A richer configuration with more supporting information and actions.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#nav-demo",
|
||||
"actionHref": "#nav-demo",
|
||||
"actionLabel": "Explore workflow",
|
||||
"icon": "icon-[lucide--circle-check]",
|
||||
"iconClass": "icon-[lucide--circle-check]",
|
||||
"variant": "success",
|
||||
"status": "Complete",
|
||||
"time": "11:45",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": true,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 64,
|
||||
"percentage": 91,
|
||||
"color": "#059669",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open advanced workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Unlimited"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
active="team"
|
||||
orientation="vertical"
|
||||
label="Advanced example"
|
||||
collapsible="false"
|
||||
toggleLabel="Advanced example"
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article></div></section>
|
||||
<section id="events" class="detail-section"><div class="detail-section-heading"><span>Component outputs</span><h2>Receive every typed component output</h2><p>Use declarative output handlers in <code>.wrn</code> files or register a direct output handler from JavaScript. The canonical API exposes <code>payload</code> and does not require <code>event.detail</code>.</p></div><div class="detail-events-grid"><div class="detail-events-list"><div><code>@select</code><span>Fires when an item, option, card, or result is selected.</span></div></div><div class="detail-event-examples"><section class="demo-code"><header><span><span class="icon-[lucide--braces] size-4" aria-hidden="true"></span>Declarative handlers</span><small>.wrn</small></header><pre><code><Nav
|
||||
<section id="events" class="detail-section"><div class="detail-section-heading"><span>Component outputs</span><h2>Receive every typed component output</h2><p>Use declarative output handlers in <code>.wrn</code> files or register a direct output handler from JavaScript. The canonical API exposes <code>payload</code> and does not require <code>event.detail</code>.</p></div><div class="detail-events-grid"><div class="detail-events-list"><div><code>@select</code><span>Fires when an item, option, card, or result is selected.</span></div><div><code>@change</code><span>Fires when the component's committed value or selection changes.</span></div></div><div class="detail-event-examples"><section class="demo-code"><header><span><span class="icon-[lucide--braces] size-4" aria-hidden="true"></span>Declarative handlers</span><small>.wrn</small></header><pre><code><Nav
|
||||
@select='console.log(payload)'
|
||||
@change='console.log(payload)'
|
||||
/></code></pre></section><section class="demo-code"><header><span><span class="icon-[lucide--radio] size-4" aria-hidden="true"></span>Direct output handlers</span><small>.js</small></header><pre><code>import <span>{</span> registerOutputHandler <span>}</span> from "@wrnexus/csr/outputs"
|
||||
|
||||
const component = document.querySelector("[data-ui-component=\"Nav\"], [data-component=\"Nav\"]")
|
||||
|
||||
if (component) registerOutputHandler(component, "select", (payload) => <span>{</span>
|
||||
console.log("select", payload)
|
||||
<span>}</span>)
|
||||
|
||||
if (component) registerOutputHandler(component, "change", (payload) => <span>{</span>
|
||||
console.log("change", payload)
|
||||
<span>}</span>)</code></pre></section></div></div></section>
|
||||
<section id="api" class="detail-section"><div class="detail-section-heading"><span>Component API</span><h2>Props and configuration</h2><p>All content and behavior shown above is supplied through these props and slots.</p></div><div class="docs-table-wrap"><table class="docs-table"><thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Required</th></tr></thead><tbody><tr><td><code>color</code></td><td>string</td><td><code>"primary"</code></td><td>No</td></tr><tr><td><code>size</code></td><td>string</td><td><code>"default"</code></td><td>No</td></tr><tr><td><code>items</code></td><td>unknown[]</td><td><code>[]</code></td><td>No</td></tr><tr><td><code>active</code></td><td>string</td><td><code>""</code></td><td>No</td></tr><tr><td><code>orientation</code></td><td>string</td><td><code>"horizontal"</code></td><td>No</td></tr><tr><td><code>label</code></td><td>string</td><td><code>"Main"</code></td><td>No</td></tr><tr><td><code>collapsible</code></td><td>boolean</td><td><code>true</code></td><td>No</td></tr><tr><td><code>toggleLabel</code></td><td>string</td><td><code>"Menu"</code></td><td>No</td></tr><tr><td><code>class</code></td><td>string</td><td><code>""</code></td><td>No</td></tr></tbody></table></div></section>
|
||||
<section id="api" class="detail-section"><div class="detail-section-heading"><span>Component API</span><h2>Props and configuration</h2><p>All content and behavior shown above is supplied through these props and slots.</p></div><div class="docs-table-wrap"><table class="docs-table"><thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Required</th></tr></thead><tbody><tr><td><code>size</code></td><td>string</td><td><code>"default"</code></td><td>No</td></tr><tr><td><code>color</code></td><td>string</td><td><code>"primary"</code></td><td>No</td></tr><tr><td><code>label</code></td><td>string</td><td><code>"Nav"</code></td><td>No</td></tr><tr><td><code>items</code></td><td>unknown[]</td><td><code>[]</code></td><td>No</td></tr><tr><td><code>active</code></td><td>string</td><td><code>""</code></td><td>No</td></tr><tr><td><code>orientation</code></td><td>string</td><td><code>"horizontal"</code></td><td>No</td></tr><tr><td><code>class</code></td><td>string</td><td><code>""</code></td><td>No</td></tr></tbody></table></div></section>
|
||||
</main>
|
||||
<aside class="detail-aside">
|
||||
<div class="detail-toc"><strong>On this page</strong><a href="#playground">Playground</a><a href="#nav-demo-1">Horizontal links</a><a href="#nav-demo-2">Nested submenus</a><a href="#nav-demo-3">Vertical rail</a><a href="#events">Outputs</a><a href="#api">Props API</a></div>
|
||||
<div class="detail-toc"><strong>On this page</strong><a href="#playground">Playground</a><a href="#nav-demo-1">Production default</a><a href="#nav-demo-2">Compact application</a><a href="#nav-demo-3">Rich configuration</a><a href="#events">Outputs</a><a href="#api">Props API</a></div>
|
||||
</aside>
|
||||
</div>
|
||||
<nav class="detail-pagination">
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
// Generated by scripts/generate-showcase.mjs. Do not edit directly.
|
||||
page PaginationDetail {
|
||||
layout = "showcase"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_size = ctx.url.searchParams.get("pg_size") ?? "default"
|
||||
state playground_page = Number(ctx.url.searchParams.get("pg_page") ?? "3")
|
||||
state playground_pageSize = Number(ctx.url.searchParams.get("pg_pageSize") ?? "3")
|
||||
state playground_total = Number(ctx.url.searchParams.get("pg_total") ?? "3")
|
||||
state playground_variant = ctx.url.searchParams.get("pg_variant") ?? "compact"
|
||||
state playground_siblingCount = Number(ctx.url.searchParams.get("pg_siblingCount") ?? "3")
|
||||
state playground_showSummary = (ctx.url.searchParams.get("pg_showSummary") ?? "true") === "true"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_label = ctx.url.searchParams.get("pg_label") ?? "Pagination"
|
||||
state playground_previousLabel = ctx.url.searchParams.get("pg_previousLabel") ?? "Pagination"
|
||||
state playground_nextLabel = ctx.url.searchParams.get("pg_nextLabel") ?? "Pagination"
|
||||
state playground_items = JSON.parse(ctx.url.searchParams.get("pg_items") ?? "[{\"id\":\"pagination-0-1\",\"key\":\"pagination-0-1\",\"value\":\"primary\",\"label\":\"Primary workflow\",\"title\":\"Primary workflow\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"A configurable sample message.\",\"href\":\"#pagination-demo\",\"actionHref\":\"#pagination-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":true,\"selected\":true,\"checked\":true,\"disabled\":false,\"outgoing\":false,\"open\":true,\"number\":1,\"count\":16,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 1\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]},{\"id\":\"pagination-0-2\",\"key\":\"pagination-0-2\",\"value\":\"secondary\",\"label\":\"Additional option\",\"title\":\"Supporting example\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"Another configurable message.\",\"href\":\"#pagination-demo\",\"actionHref\":\"#pagination-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":false,\"selected\":false,\"checked\":false,\"disabled\":false,\"outgoing\":true,\"open\":true,\"number\":2,\"count\":32,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 2\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]}]")
|
||||
state playground_active = ctx.url.searchParams.get("pg_active") ?? ""
|
||||
state playground_orientation = ctx.url.searchParams.get("pg_orientation") ?? "horizontal"
|
||||
state playground_class = ctx.url.searchParams.get("pg_class") ?? "showcase-instance showcase-instance--1"
|
||||
seo {
|
||||
title = "Pagination"
|
||||
@@ -26,7 +21,7 @@ page PaginationDetail {
|
||||
<span class="showcase-eyebrow">Navigation component</span>
|
||||
<h1>Pagination</h1>
|
||||
<p>Theme-aware, responsive pagination component.</p>
|
||||
<div class="detail-badges"><span>12 props</span><span>1 slots</span><span>3 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
<div class="detail-badges"><span>7 props</span><span>1 slots</span><span>3 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
</div>
|
||||
<div class="detail-hero-icon"><span class="icon-[lucide--component] size-10" aria-hidden="true"></span></div>
|
||||
</header>
|
||||
@@ -35,24 +30,233 @@ page PaginationDetail {
|
||||
<div class="playground-workbench">
|
||||
<div class="playground-preview">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
<div class="playground-preview-source" data-playground-preview><Pagination color='{playground_color}' size='{playground_size}' page='{playground_page}' pageSize='{playground_pageSize}' total='{playground_total}' variant='{playground_variant}' siblingCount='{playground_siblingCount}' showSummary='{playground_showSummary}' label='{playground_label}' previousLabel='{playground_previousLabel}' nextLabel='{playground_nextLabel}' class='{playground_class}' /></div>
|
||||
<div class="playground-preview-source" data-playground-preview><Pagination size='{playground_size}' color='{playground_color}' label='{playground_label}' items='{playground_items}' active='{playground_active}' orientation='{playground_orientation}' class='{playground_class}' /></div>
|
||||
<section class="playground-code" aria-label="Current component code">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component code</span><button type="button" data-playground-copy><span class="icon-[lucide--copy] size-4" aria-hidden="true"></span>Copy</button></header>
|
||||
<pre><code data-playground-code><Pagination
|
||||
page="3"
|
||||
pageSize="3"
|
||||
total="3"
|
||||
siblingCount="3"
|
||||
previousLabel="Pagination"
|
||||
nextLabel="Pagination"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"id": "pagination-0-1",
|
||||
"key": "pagination-0-1",
|
||||
"value": "primary",
|
||||
"label": "Primary workflow",
|
||||
"title": "Primary workflow",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#pagination-demo",
|
||||
"actionHref": "#pagination-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 16,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"id": "pagination-0-2",
|
||||
"key": "pagination-0-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#pagination-demo",
|
||||
"actionHref": "#pagination-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": false,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 32,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
/></code></pre>
|
||||
</section>
|
||||
<div class="playground-status" data-playground-status aria-live="polite"></div>
|
||||
<div class="playground-event-log" data-playground-event-log aria-live="polite"><strong>Event output</strong><span>Interact with the preview to inspect the typed <code>payload</code>.</span></div>
|
||||
</div>
|
||||
<form class="playground-controls" data-playground-form>
|
||||
<header><div><span>Component props</span><strong>12 controls</strong></div><button type="reset"><span class="icon-[lucide--rotate-ccw] size-4" aria-hidden="true"></span>Reset</button></header>
|
||||
<div class="playground-fields"><label class="playground-field" for="playground-pagination-color"><span><strong>color</strong><small>string</small></span><select id="playground-pagination-color" name="pg_color"><option value="primary" selected>primary</option><option value="secondary">secondary</option><option value="success">success</option><option value="warning">warning</option><option value="danger">danger</option><option value="info">info</option></select></label><label class="playground-field" for="playground-pagination-size"><span><strong>size</strong><small>string</small></span><select id="playground-pagination-size" name="pg_size"><option value="default" selected>default</option><option value="xs">xs</option><option value="sm">sm</option><option value="md">md</option><option value="lg">lg</option><option value="xl">xl</option><option value="icon">icon</option><option value="icon-xs">icon-xs</option><option value="icon-sm">icon-sm</option><option value="icon-lg">icon-lg</option></select></label><label class="playground-field" for="playground-pagination-page"><span><strong>page</strong><small>number</small></span><input id="playground-pagination-page" name="pg_page" type="number" value="3" /></label><label class="playground-field" for="playground-pagination-pageSize"><span><strong>page Size</strong><small>number</small></span><input id="playground-pagination-pageSize" name="pg_pageSize" type="number" value="3" /></label><label class="playground-field" for="playground-pagination-total"><span><strong>total</strong><small>number</small></span><input id="playground-pagination-total" name="pg_total" type="number" value="3" /></label><label class="playground-field" for="playground-pagination-variant"><span><strong>variant</strong><small>string</small></span><input id="playground-pagination-variant" name="pg_variant" type="text" value="compact" /></label><label class="playground-field" for="playground-pagination-siblingCount"><span><strong>sibling Count</strong><small>number</small></span><input id="playground-pagination-siblingCount" name="pg_siblingCount" type="number" value="3" /></label><label class="playground-toggle" for="playground-pagination-showSummary"><span><strong>show Summary</strong><small>boolean</small></span><input id="playground-pagination-showSummary" name="pg_showSummary" type="checkbox" value="true" checked data-playground-boolean /><i aria-hidden="true"></i></label><label class="playground-field" for="playground-pagination-label"><span><strong>label</strong><small>string</small></span><input id="playground-pagination-label" name="pg_label" type="text" value="Pagination" /></label><label class="playground-field" for="playground-pagination-previousLabel"><span><strong>previous Label</strong><small>string</small></span><input id="playground-pagination-previousLabel" name="pg_previousLabel" type="text" value="Pagination" /></label><label class="playground-field" for="playground-pagination-nextLabel"><span><strong>next Label</strong><small>string</small></span><input id="playground-pagination-nextLabel" name="pg_nextLabel" type="text" value="Pagination" /></label><label class="playground-field" for="playground-pagination-class"><span><strong>class</strong><small>string</small></span><input id="playground-pagination-class" name="pg_class" type="text" value="showcase-instance showcase-instance--1" /></label></div>
|
||||
<header><div><span>Component props</span><strong>7 controls</strong></div><button type="reset"><span class="icon-[lucide--rotate-ccw] size-4" aria-hidden="true"></span>Reset</button></header>
|
||||
<div class="playground-fields"><label class="playground-field" for="playground-pagination-size"><span><strong>size</strong><small>string</small></span><select id="playground-pagination-size" name="pg_size"><option value="default" selected>default</option><option value="xs">xs</option><option value="sm">sm</option><option value="md">md</option><option value="lg">lg</option><option value="xl">xl</option><option value="icon">icon</option><option value="icon-xs">icon-xs</option><option value="icon-sm">icon-sm</option><option value="icon-lg">icon-lg</option></select></label><label class="playground-field" for="playground-pagination-color"><span><strong>color</strong><small>string</small></span><select id="playground-pagination-color" name="pg_color"><option value="primary" selected>primary</option><option value="secondary">secondary</option><option value="success">success</option><option value="warning">warning</option><option value="danger">danger</option><option value="info">info</option></select></label><label class="playground-field" for="playground-pagination-label"><span><strong>label</strong><small>string</small></span><input id="playground-pagination-label" name="pg_label" type="text" value="Pagination" /></label><label class="playground-field" for="playground-pagination-items"><span><strong>items</strong><small>unknown[]</small></span><textarea id="playground-pagination-items" name="pg_items" rows="5" spellcheck="false" data-playground-json>[
|
||||
{
|
||||
"id": "pagination-0-1",
|
||||
"key": "pagination-0-1",
|
||||
"value": "primary",
|
||||
"label": "Primary workflow",
|
||||
"title": "Primary workflow",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#pagination-demo",
|
||||
"actionHref": "#pagination-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 16,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 1",
|
||||
"items": [
|
||||
{
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
},
|
||||
{
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
},
|
||||
{
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
}
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "pagination-0-2",
|
||||
"key": "pagination-0-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#pagination-demo",
|
||||
"actionHref": "#pagination-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": false,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 32,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 2",
|
||||
"items": [
|
||||
{
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
},
|
||||
{
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
},
|
||||
{
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
}
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
}
|
||||
]</textarea><em data-playground-error></em></label><label class="playground-field" for="playground-pagination-active"><span><strong>active</strong><small>string</small></span><input id="playground-pagination-active" name="pg_active" type="text" value="" /></label><label class="playground-field" for="playground-pagination-orientation"><span><strong>orientation</strong><small>string</small></span><select id="playground-pagination-orientation" name="pg_orientation"><option value="horizontal" selected>horizontal</option><option value="vertical">vertical</option></select></label><label class="playground-field" for="playground-pagination-class"><span><strong>class</strong><small>string</small></span><input id="playground-pagination-class" name="pg_class" type="text" value="showcase-instance showcase-instance--1" /></label></div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
@@ -61,75 +265,382 @@ page PaginationDetail {
|
||||
<section class="detail-section"><div class="detail-section-heading"><span>Live examples</span><h2>Designed for real product surfaces</h2><p>Compare configurations and resize the browser to check responsive behavior.</p></div><div class="demo-list">
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Compact arrows</h2><p>The default: previous and next with a page counter, and a summary of the range in view.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Production default</h2><p>Balanced spacing, hierarchy, and content for the most common product workflow.</p></div>
|
||||
<span class="demo-case-number">01</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="pagination-demo-1" class="demo-canvas demo-canvas--1">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Pagination size="default" page="2" pageSize="10" total="137" variant="compact" siblingCount="3" showSummary="true" label="Pagination" previousLabel="Pagination" nextLabel="Pagination" class="showcase-instance showcase-instance--1" /></div>
|
||||
<div class="demo-render"><Pagination size="default" label="Pagination" items='[{"id":"pagination-0-1","key":"pagination-0-1","value":"primary","label":"Primary workflow","title":"Primary workflow","description":"A clean default configuration for everyday product interfaces.","text":"A configurable sample message.","href":"#pagination-demo","actionHref":"#pagination-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":16,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"pagination-0-2","key":"pagination-0-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A clean default configuration for everyday product interfaces.","text":"Another configurable message.","href":"#pagination-demo","actionHref":"#pagination-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":32,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' class="showcase-instance showcase-instance--1" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Compact arrows usage">
|
||||
<section class="demo-code" aria-label="Production default usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Pagination
|
||||
page="2"
|
||||
total="137"
|
||||
siblingCount="3"
|
||||
previousLabel="Pagination"
|
||||
nextLabel="Pagination"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"id": "pagination-0-1",
|
||||
"key": "pagination-0-1",
|
||||
"value": "primary",
|
||||
"label": "Primary workflow",
|
||||
"title": "Primary workflow",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#pagination-demo",
|
||||
"actionHref": "#pagination-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 16,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"id": "pagination-0-2",
|
||||
"key": "pagination-0-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#pagination-demo",
|
||||
"actionHref": "#pagination-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": false,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 32,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Numbered pages</h2><p>Page numbers windowed around the current page with ellipsis gaps, so a large set never renders hundreds of buttons.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Dense UI</span><h2>Compact application</h2><p>A tighter variation for dashboards, side panels, tables, and operational interfaces.</p></div>
|
||||
<span class="demo-case-number">02</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="pagination-demo-2" class="demo-canvas demo-canvas--2">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Pagination size="sm" page="5" pageSize="10" total="200" variant="numbered" siblingCount="1" showSummary="true" label="Compact example" previousLabel="Compact example" nextLabel="Compact example" class="showcase-instance showcase-instance--2" /></div>
|
||||
<div class="demo-render"><Pagination size="sm" label="Compact example" items='[{"id":"pagination-1-1","key":"pagination-1-1","value":"primary","label":"Secondary workflow","title":"Secondary workflow","description":"A compact configuration designed for dense application layouts.","text":"A configurable sample message.","href":"#pagination-demo","actionHref":"#pagination-demo","actionLabel":"View details","icon":"icon-[lucide--zap]","iconClass":"icon-[lucide--zap]","variant":"secondary","status":"Active","time":"10:15","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":24,"percentage":48,"color":"#0284c7","target":"_self","ariaLabel":"Open secondary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"pagination-1-2","key":"pagination-1-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A compact configuration designed for dense application layouts.","text":"Another configurable message.","href":"#pagination-demo","actionHref":"#pagination-demo","actionLabel":"View details","icon":"icon-[lucide--zap]","iconClass":"icon-[lucide--zap]","variant":"secondary","status":"Active","time":"10:15","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":48,"percentage":48,"color":"#0284c7","target":"_self","ariaLabel":"Open secondary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' class="showcase-instance showcase-instance--2" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Numbered pages usage">
|
||||
<section class="demo-code" aria-label="Compact application usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Pagination
|
||||
size="sm"
|
||||
page="5"
|
||||
total="200"
|
||||
variant="numbered"
|
||||
label="Compact example"
|
||||
previousLabel="Compact example"
|
||||
nextLabel="Compact example"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"id": "pagination-1-1",
|
||||
"key": "pagination-1-1",
|
||||
"value": "primary",
|
||||
"label": "Secondary workflow",
|
||||
"title": "Secondary workflow",
|
||||
"description": "A compact configuration designed for dense application layouts.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#pagination-demo",
|
||||
"actionHref": "#pagination-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--zap]",
|
||||
"iconClass": "icon-[lucide--zap]",
|
||||
"variant": "secondary",
|
||||
"status": "Active",
|
||||
"time": "10:15",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 24,
|
||||
"percentage": 48,
|
||||
"color": "#0284c7",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open secondary workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"id": "pagination-1-2",
|
||||
"key": "pagination-1-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A compact configuration designed for dense application layouts.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#pagination-demo",
|
||||
"actionHref": "#pagination-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--zap]",
|
||||
"iconClass": "icon-[lucide--zap]",
|
||||
"variant": "secondary",
|
||||
"status": "Active",
|
||||
"time": "10:15",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": false,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 48,
|
||||
"percentage": 48,
|
||||
"color": "#0284c7",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open secondary workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Advanced</span><h2>Wider window</h2><p>siblingCount widens how many pages sit either side of the current one.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Extended</span><h2>Rich configuration</h2><p>A more expressive variation using additional data, stronger emphasis, and optional states.</p></div>
|
||||
<span class="demo-case-number">03</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="pagination-demo-3" class="demo-canvas demo-canvas--3">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Pagination size="lg" page="8" pageSize="25" total="900" variant="numbered" siblingCount="2" showSummary="true" label="Advanced example" previousLabel="Advanced example" nextLabel="Advanced example" class="showcase-instance showcase-instance--3" /></div>
|
||||
<div class="demo-render"><Pagination size="lg" label="Advanced example" items='[{"id":"pagination-2-1","key":"pagination-2-1","value":"primary","label":"Advanced workflow","title":"Advanced workflow","description":"A richer configuration with more supporting information and actions.","text":"A configurable sample message.","href":"#pagination-demo","actionHref":"#pagination-demo","actionLabel":"Explore workflow","icon":"icon-[lucide--circle-check]","iconClass":"icon-[lucide--circle-check]","variant":"success","status":"Complete","time":"11:45","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":32,"percentage":91,"color":"#059669","target":"_self","ariaLabel":"Open advanced workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Unlimited"]},{"id":"pagination-2-2","key":"pagination-2-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A richer configuration with more supporting information and actions.","text":"Another configurable message.","href":"#pagination-demo","actionHref":"#pagination-demo","actionLabel":"Explore workflow","icon":"icon-[lucide--circle-check]","iconClass":"icon-[lucide--circle-check]","variant":"success","status":"Complete","time":"11:45","current":false,"selected":false,"checked":false,"disabled":true,"outgoing":true,"open":true,"number":2,"count":64,"percentage":91,"color":"#059669","target":"_self","ariaLabel":"Open advanced workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Unlimited"]}]' class="showcase-instance showcase-instance--3" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Wider window usage">
|
||||
<section class="demo-code" aria-label="Rich configuration usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Pagination
|
||||
size="lg"
|
||||
page="8"
|
||||
pageSize="25"
|
||||
total="900"
|
||||
variant="numbered"
|
||||
siblingCount="2"
|
||||
label="Advanced example"
|
||||
previousLabel="Advanced example"
|
||||
nextLabel="Advanced example"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"id": "pagination-2-1",
|
||||
"key": "pagination-2-1",
|
||||
"value": "primary",
|
||||
"label": "Advanced workflow",
|
||||
"title": "Advanced workflow",
|
||||
"description": "A richer configuration with more supporting information and actions.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#pagination-demo",
|
||||
"actionHref": "#pagination-demo",
|
||||
"actionLabel": "Explore workflow",
|
||||
"icon": "icon-[lucide--circle-check]",
|
||||
"iconClass": "icon-[lucide--circle-check]",
|
||||
"variant": "success",
|
||||
"status": "Complete",
|
||||
"time": "11:45",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 32,
|
||||
"percentage": 91,
|
||||
"color": "#059669",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open advanced workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Unlimited"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"id": "pagination-2-2",
|
||||
"key": "pagination-2-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A richer configuration with more supporting information and actions.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#pagination-demo",
|
||||
"actionHref": "#pagination-demo",
|
||||
"actionLabel": "Explore workflow",
|
||||
"icon": "icon-[lucide--circle-check]",
|
||||
"iconClass": "icon-[lucide--circle-check]",
|
||||
"variant": "success",
|
||||
"status": "Complete",
|
||||
"time": "11:45",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": true,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 64,
|
||||
"percentage": 91,
|
||||
"color": "#059669",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open advanced workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Unlimited"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
@@ -153,10 +664,10 @@ if (component) registerOutputHandler(component, "previous", (payload) => <spa
|
||||
if (component) registerOutputHandler(component, "next", (payload) => <span>{</span>
|
||||
console.log("next", payload)
|
||||
<span>}</span>)</code></pre></section></div></div></section>
|
||||
<section id="api" class="detail-section"><div class="detail-section-heading"><span>Component API</span><h2>Props and configuration</h2><p>All content and behavior shown above is supplied through these props and slots.</p></div><div class="docs-table-wrap"><table class="docs-table"><thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Required</th></tr></thead><tbody><tr><td><code>color</code></td><td>string</td><td><code>"primary"</code></td><td>No</td></tr><tr><td><code>size</code></td><td>string</td><td><code>"default"</code></td><td>No</td></tr><tr><td><code>page</code></td><td>number</td><td><code>1</code></td><td>No</td></tr><tr><td><code>pageSize</code></td><td>number</td><td><code>10</code></td><td>No</td></tr><tr><td><code>total</code></td><td>number</td><td><code>0</code></td><td>No</td></tr><tr><td><code>variant</code></td><td>string</td><td><code>"compact"</code></td><td>No</td></tr><tr><td><code>siblingCount</code></td><td>number</td><td><code>1</code></td><td>No</td></tr><tr><td><code>showSummary</code></td><td>boolean</td><td><code>true</code></td><td>No</td></tr><tr><td><code>label</code></td><td>string</td><td><code>"Pagination"</code></td><td>No</td></tr><tr><td><code>previousLabel</code></td><td>string</td><td><code>"Previous"</code></td><td>No</td></tr><tr><td><code>nextLabel</code></td><td>string</td><td><code>"Next"</code></td><td>No</td></tr><tr><td><code>class</code></td><td>string</td><td><code>""</code></td><td>No</td></tr></tbody></table></div></section>
|
||||
<section id="api" class="detail-section"><div class="detail-section-heading"><span>Component API</span><h2>Props and configuration</h2><p>All content and behavior shown above is supplied through these props and slots.</p></div><div class="docs-table-wrap"><table class="docs-table"><thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Required</th></tr></thead><tbody><tr><td><code>size</code></td><td>string</td><td><code>"default"</code></td><td>No</td></tr><tr><td><code>color</code></td><td>string</td><td><code>"primary"</code></td><td>No</td></tr><tr><td><code>label</code></td><td>string</td><td><code>"Pagination"</code></td><td>No</td></tr><tr><td><code>items</code></td><td>unknown[]</td><td><code>[]</code></td><td>No</td></tr><tr><td><code>active</code></td><td>string</td><td><code>""</code></td><td>No</td></tr><tr><td><code>orientation</code></td><td>string</td><td><code>"horizontal"</code></td><td>No</td></tr><tr><td><code>class</code></td><td>string</td><td><code>""</code></td><td>No</td></tr></tbody></table></div></section>
|
||||
</main>
|
||||
<aside class="detail-aside">
|
||||
<div class="detail-toc"><strong>On this page</strong><a href="#playground">Playground</a><a href="#pagination-demo-1">Compact arrows</a><a href="#pagination-demo-2">Numbered pages</a><a href="#pagination-demo-3">Wider window</a><a href="#events">Outputs</a><a href="#api">Props API</a></div>
|
||||
<div class="detail-toc"><strong>On this page</strong><a href="#playground">Playground</a><a href="#pagination-demo-1">Production default</a><a href="#pagination-demo-2">Compact application</a><a href="#pagination-demo-3">Rich configuration</a><a href="#events">Outputs</a><a href="#api">Props API</a></div>
|
||||
</aside>
|
||||
</div>
|
||||
<nav class="detail-pagination">
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Generated by scripts/generate-showcase.mjs. Do not edit directly.
|
||||
page SidebarDetail {
|
||||
layout = "showcase"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_size = ctx.url.searchParams.get("pg_size") ?? "default"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_label = ctx.url.searchParams.get("pg_label") ?? "Sidebar"
|
||||
state playground_items = JSON.parse(ctx.url.searchParams.get("pg_items") ?? "[{\"id\":\"sidebar-0-1\",\"key\":\"sidebar-0-1\",\"value\":\"primary\",\"label\":\"Primary workflow\",\"title\":\"Primary workflow\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"A configurable sample message.\",\"href\":\"#sidebar-demo\",\"actionHref\":\"#sidebar-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":true,\"selected\":true,\"checked\":true,\"disabled\":false,\"outgoing\":false,\"open\":true,\"number\":1,\"count\":16,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 1\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]},{\"id\":\"sidebar-0-2\",\"key\":\"sidebar-0-2\",\"value\":\"secondary\",\"label\":\"Additional option\",\"title\":\"Supporting example\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"Another configurable message.\",\"href\":\"#sidebar-demo\",\"actionHref\":\"#sidebar-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":false,\"selected\":false,\"checked\":false,\"disabled\":false,\"outgoing\":true,\"open\":true,\"number\":2,\"count\":32,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 2\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]}]")
|
||||
state playground_active = ctx.url.searchParams.get("pg_active") ?? ""
|
||||
state playground_orientation = ctx.url.searchParams.get("pg_orientation") ?? "horizontal"
|
||||
state playground_mobileLabel = ctx.url.searchParams.get("pg_mobileLabel") ?? "Sidebar"
|
||||
state playground_drawerTitle = ctx.url.searchParams.get("pg_drawerTitle") ?? "Sidebar example"
|
||||
state playground_class = ctx.url.searchParams.get("pg_class") ?? "showcase-instance showcase-instance--1"
|
||||
seo {
|
||||
title = "Sidebar"
|
||||
@@ -22,7 +22,7 @@ page SidebarDetail {
|
||||
<span class="showcase-eyebrow">Navigation component</span>
|
||||
<h1>Sidebar</h1>
|
||||
<p>Theme-aware, responsive sidebar component.</p>
|
||||
<div class="detail-badges"><span>8 props</span><span>2 slots</span><span>4 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
<div class="detail-badges"><span>8 props</span><span>1 slots</span><span>4 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
</div>
|
||||
<div class="detail-hero-icon"><span class="icon-[lucide--component] size-10" aria-hidden="true"></span></div>
|
||||
</header>
|
||||
@@ -31,7 +31,7 @@ page SidebarDetail {
|
||||
<div class="playground-workbench">
|
||||
<div class="playground-preview">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
<div class="playground-preview-source" data-playground-preview><Sidebar color='{playground_color}' size='{playground_size}' label='{playground_label}' items='{playground_items}' active='{playground_active}' mobileLabel='{playground_mobileLabel}' drawerTitle='{playground_drawerTitle}' class='{playground_class}' /></div>
|
||||
<div class="playground-preview-source" data-playground-preview><Sidebar size='{playground_size}' color='{playground_color}' label='{playground_label}' items='{playground_items}' active='{playground_active}' orientation='{playground_orientation}' mobileLabel='{playground_mobileLabel}' class='{playground_class}' /></div>
|
||||
<section class="playground-code" aria-label="Current component code">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component code</span><button type="button" data-playground-copy><span class="icon-[lucide--copy] size-4" aria-hidden="true"></span>Copy</button></header>
|
||||
<pre><code data-playground-code><Sidebar
|
||||
@@ -144,18 +144,14 @@ page SidebarDetail {
|
||||
<span>}</span>
|
||||
]'
|
||||
mobileLabel="Sidebar"
|
||||
drawerTitle="Sidebar example">
|
||||
<div data-slot="drawer">
|
||||
<div class="showcase-slot">drawer slot</div>
|
||||
</div>
|
||||
</Sidebar></code></pre>
|
||||
/></code></pre>
|
||||
</section>
|
||||
<div class="playground-status" data-playground-status aria-live="polite"></div>
|
||||
<div class="playground-event-log" data-playground-event-log aria-live="polite"><strong>Event output</strong><span>Interact with the preview to inspect the typed <code>payload</code>.</span></div>
|
||||
</div>
|
||||
<form class="playground-controls" data-playground-form>
|
||||
<header><div><span>Component props</span><strong>8 controls</strong></div><button type="reset"><span class="icon-[lucide--rotate-ccw] size-4" aria-hidden="true"></span>Reset</button></header>
|
||||
<div class="playground-fields"><label class="playground-field" for="playground-sidebar-color"><span><strong>color</strong><small>string</small></span><select id="playground-sidebar-color" name="pg_color"><option value="primary" selected>primary</option><option value="secondary">secondary</option><option value="success">success</option><option value="warning">warning</option><option value="danger">danger</option><option value="info">info</option></select></label><label class="playground-field" for="playground-sidebar-size"><span><strong>size</strong><small>string</small></span><select id="playground-sidebar-size" name="pg_size"><option value="default" selected>default</option><option value="xs">xs</option><option value="sm">sm</option><option value="md">md</option><option value="lg">lg</option><option value="xl">xl</option><option value="icon">icon</option><option value="icon-xs">icon-xs</option><option value="icon-sm">icon-sm</option><option value="icon-lg">icon-lg</option></select></label><label class="playground-field" for="playground-sidebar-label"><span><strong>label</strong><small>string</small></span><input id="playground-sidebar-label" name="pg_label" type="text" value="Sidebar" /></label><label class="playground-field" for="playground-sidebar-items"><span><strong>items</strong><small>unknown[]</small></span><textarea id="playground-sidebar-items" name="pg_items" rows="5" spellcheck="false" data-playground-json>[
|
||||
<div class="playground-fields"><label class="playground-field" for="playground-sidebar-size"><span><strong>size</strong><small>string</small></span><select id="playground-sidebar-size" name="pg_size"><option value="default" selected>default</option><option value="xs">xs</option><option value="sm">sm</option><option value="md">md</option><option value="lg">lg</option><option value="xl">xl</option><option value="icon">icon</option><option value="icon-xs">icon-xs</option><option value="icon-sm">icon-sm</option><option value="icon-lg">icon-lg</option></select></label><label class="playground-field" for="playground-sidebar-color"><span><strong>color</strong><small>string</small></span><select id="playground-sidebar-color" name="pg_color"><option value="primary" selected>primary</option><option value="secondary">secondary</option><option value="success">success</option><option value="warning">warning</option><option value="danger">danger</option><option value="info">info</option></select></label><label class="playground-field" for="playground-sidebar-label"><span><strong>label</strong><small>string</small></span><input id="playground-sidebar-label" name="pg_label" type="text" value="Sidebar" /></label><label class="playground-field" for="playground-sidebar-items"><span><strong>items</strong><small>unknown[]</small></span><textarea id="playground-sidebar-items" name="pg_items" rows="5" spellcheck="false" data-playground-json>[
|
||||
{
|
||||
"id": "sidebar-0-1",
|
||||
"key": "sidebar-0-1",
|
||||
@@ -262,7 +258,7 @@ page SidebarDetail {
|
||||
"Standard"
|
||||
]
|
||||
}
|
||||
]</textarea><em data-playground-error></em></label><label class="playground-field" for="playground-sidebar-active"><span><strong>active</strong><small>string</small></span><input id="playground-sidebar-active" name="pg_active" type="text" value="" /></label><label class="playground-field" for="playground-sidebar-mobileLabel"><span><strong>mobile Label</strong><small>string</small></span><input id="playground-sidebar-mobileLabel" name="pg_mobileLabel" type="text" value="Sidebar" /></label><label class="playground-field" for="playground-sidebar-drawerTitle"><span><strong>drawer Title</strong><small>string</small></span><input id="playground-sidebar-drawerTitle" name="pg_drawerTitle" type="text" value="Sidebar example" /></label><label class="playground-field" for="playground-sidebar-class"><span><strong>class</strong><small>string</small></span><input id="playground-sidebar-class" name="pg_class" type="text" value="showcase-instance showcase-instance--1" /></label></div>
|
||||
]</textarea><em data-playground-error></em></label><label class="playground-field" for="playground-sidebar-active"><span><strong>active</strong><small>string</small></span><input id="playground-sidebar-active" name="pg_active" type="text" value="" /></label><label class="playground-field" for="playground-sidebar-orientation"><span><strong>orientation</strong><small>string</small></span><select id="playground-sidebar-orientation" name="pg_orientation"><option value="horizontal" selected>horizontal</option><option value="vertical">vertical</option></select></label><label class="playground-field" for="playground-sidebar-mobileLabel"><span><strong>mobile Label</strong><small>string</small></span><input id="playground-sidebar-mobileLabel" name="pg_mobileLabel" type="text" value="Sidebar" /></label><label class="playground-field" for="playground-sidebar-class"><span><strong>class</strong><small>string</small></span><input id="playground-sidebar-class" name="pg_class" type="text" value="showcase-instance showcase-instance--1" /></label></div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
@@ -271,111 +267,386 @@ page SidebarDetail {
|
||||
<section class="detail-section"><div class="detail-section-heading"><span>Live examples</span><h2>Designed for real product surfaces</h2><p>Compare configurations and resize the browser to check responsive behavior.</p></div><div class="demo-list">
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Groups and nested levels</h2><p>An entry is a single link, a labelled group, or a branch nested up to three levels. Arrow keys move down the rail.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Production default</h2><p>Balanced spacing, hierarchy, and content for the most common product workflow.</p></div>
|
||||
<span class="demo-case-number">01</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="sidebar-demo-1" class="demo-canvas demo-canvas--1">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Sidebar size="default" label="Workspace" items='[{"label":"Dashboard","href":"/","value":"dash","icon":"icon-[lucide--gauge]"},{"heading":"Projects","items":[{"label":"Active","href":"/active","value":"active","badge":"4"},{"label":"Archive","value":"archive","items":[{"label":"2025","href":"/a/2025","value":"a2025"},{"label":"2024","href":"/a/2024","value":"a2024"}]}]},{"heading":"Account","items":[{"label":"Settings","href":"/settings","value":"settings","icon":"icon-[lucide--settings]"}]}]' active="active" mobileLabel="Sidebar" drawerTitle="Sidebar example" class="showcase-instance showcase-instance--1" /></div>
|
||||
<div class="demo-render"><Sidebar size="default" label="Sidebar" items='[{"id":"sidebar-0-1","key":"sidebar-0-1","value":"primary","label":"Primary workflow","title":"Primary workflow","description":"A clean default configuration for everyday product interfaces.","text":"A configurable sample message.","href":"#sidebar-demo","actionHref":"#sidebar-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":16,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"sidebar-0-2","key":"sidebar-0-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A clean default configuration for everyday product interfaces.","text":"Another configurable message.","href":"#sidebar-demo","actionHref":"#sidebar-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":32,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' mobileLabel="Sidebar" class="showcase-instance showcase-instance--1" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Groups and nested levels usage">
|
||||
<section class="demo-code" aria-label="Production default usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Sidebar
|
||||
label="Workspace"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"label": "Dashboard",
|
||||
"href": "/",
|
||||
"value": "dash",
|
||||
"icon": "icon-[lucide--gauge]"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"heading": "Projects",
|
||||
"id": "sidebar-0-1",
|
||||
"key": "sidebar-0-1",
|
||||
"value": "primary",
|
||||
"label": "Primary workflow",
|
||||
"title": "Primary workflow",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#sidebar-demo",
|
||||
"actionHref": "#sidebar-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 16,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Active",
|
||||
"href": "/active",
|
||||
"value": "active",
|
||||
"badge": "4"
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Archive",
|
||||
"value": "archive",
|
||||
"items": [
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "2025",
|
||||
"href": "/a/2025",
|
||||
"value": "a2025"
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "2024",
|
||||
"href": "/a/2024",
|
||||
"value": "a2024"
|
||||
<span>}</span>
|
||||
]
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"heading": "Account",
|
||||
"id": "sidebar-0-2",
|
||||
"key": "sidebar-0-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#sidebar-demo",
|
||||
"actionHref": "#sidebar-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": false,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 32,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Settings",
|
||||
"href": "/settings",
|
||||
"value": "settings",
|
||||
"icon": "icon-[lucide--settings]"
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
active="active"
|
||||
mobileLabel="Sidebar"
|
||||
drawerTitle="Sidebar example">
|
||||
<div data-slot="drawer">
|
||||
<div class="showcase-slot">drawer slot</div>
|
||||
</div>
|
||||
</Sidebar></code></pre>
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Advanced</span><h2>Drawer on small screens</h2><p>Below the tablet breakpoint the rail is replaced by a launcher that opens a Drawer. Composing Drawer rather than reimplementing it means the focus trap and the body scroll lock come from one place.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Dense UI</span><h2>Compact application</h2><p>A tighter variation for dashboards, side panels, tables, and operational interfaces.</p></div>
|
||||
<span class="demo-case-number">02</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="sidebar-demo-2" class="demo-canvas demo-canvas--2">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Sidebar size="sm" label="Operations" items='[{"label":"Queue","href":"/queue","value":"queue","icon":"icon-[lucide--inbox]"},{"label":"Reports","href":"/reports","value":"reports","icon":"icon-[lucide--chart-no-axes-column]"}]' active="queue" mobileLabel="Open navigation" drawerTitle="Operations" class="showcase-instance showcase-instance--2" /></div>
|
||||
<div class="demo-render"><Sidebar size="sm" label="Compact example" items='[{"id":"sidebar-1-1","key":"sidebar-1-1","value":"primary","label":"Secondary workflow","title":"Secondary workflow","description":"A compact configuration designed for dense application layouts.","text":"A configurable sample message.","href":"#sidebar-demo","actionHref":"#sidebar-demo","actionLabel":"View details","icon":"icon-[lucide--zap]","iconClass":"icon-[lucide--zap]","variant":"secondary","status":"Active","time":"10:15","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":24,"percentage":48,"color":"#0284c7","target":"_self","ariaLabel":"Open secondary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"sidebar-1-2","key":"sidebar-1-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A compact configuration designed for dense application layouts.","text":"Another configurable message.","href":"#sidebar-demo","actionHref":"#sidebar-demo","actionLabel":"View details","icon":"icon-[lucide--zap]","iconClass":"icon-[lucide--zap]","variant":"secondary","status":"Active","time":"10:15","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":48,"percentage":48,"color":"#0284c7","target":"_self","ariaLabel":"Open secondary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' mobileLabel="Compact example" class="showcase-instance showcase-instance--2" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Drawer on small screens usage">
|
||||
<section class="demo-code" aria-label="Compact application usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Sidebar
|
||||
size="sm"
|
||||
label="Operations"
|
||||
label="Compact example"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"label": "Queue",
|
||||
"href": "/queue",
|
||||
"value": "queue",
|
||||
"icon": "icon-[lucide--inbox]"
|
||||
"id": "sidebar-1-1",
|
||||
"key": "sidebar-1-1",
|
||||
"value": "primary",
|
||||
"label": "Secondary workflow",
|
||||
"title": "Secondary workflow",
|
||||
"description": "A compact configuration designed for dense application layouts.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#sidebar-demo",
|
||||
"actionHref": "#sidebar-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--zap]",
|
||||
"iconClass": "icon-[lucide--zap]",
|
||||
"variant": "secondary",
|
||||
"status": "Active",
|
||||
"time": "10:15",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 24,
|
||||
"percentage": 48,
|
||||
"color": "#0284c7",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open secondary workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Reports",
|
||||
"href": "/reports",
|
||||
"value": "reports",
|
||||
"icon": "icon-[lucide--chart-no-axes-column]"
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"id": "sidebar-1-2",
|
||||
"key": "sidebar-1-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A compact configuration designed for dense application layouts.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#sidebar-demo",
|
||||
"actionHref": "#sidebar-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--zap]",
|
||||
"iconClass": "icon-[lucide--zap]",
|
||||
"variant": "secondary",
|
||||
"status": "Active",
|
||||
"time": "10:15",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": false,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 48,
|
||||
"percentage": 48,
|
||||
"color": "#0284c7",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open secondary workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
active="queue"
|
||||
drawerTitle="Operations">
|
||||
<div data-slot="drawer">
|
||||
<div class="showcase-slot">drawer slot</div>
|
||||
</div>
|
||||
</Sidebar></code></pre>
|
||||
mobileLabel="Compact example"
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Extended</span><h2>Rich configuration</h2><p>A more expressive variation using additional data, stronger emphasis, and optional states.</p></div>
|
||||
<span class="demo-case-number">03</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="sidebar-demo-3" class="demo-canvas demo-canvas--3">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Sidebar size="lg" label="Advanced example" items='[{"id":"sidebar-2-1","key":"sidebar-2-1","value":"primary","label":"Advanced workflow","title":"Advanced workflow","description":"A richer configuration with more supporting information and actions.","text":"A configurable sample message.","href":"#sidebar-demo","actionHref":"#sidebar-demo","actionLabel":"Explore workflow","icon":"icon-[lucide--circle-check]","iconClass":"icon-[lucide--circle-check]","variant":"success","status":"Complete","time":"11:45","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":32,"percentage":91,"color":"#059669","target":"_self","ariaLabel":"Open advanced workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Unlimited"]},{"id":"sidebar-2-2","key":"sidebar-2-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A richer configuration with more supporting information and actions.","text":"Another configurable message.","href":"#sidebar-demo","actionHref":"#sidebar-demo","actionLabel":"Explore workflow","icon":"icon-[lucide--circle-check]","iconClass":"icon-[lucide--circle-check]","variant":"success","status":"Complete","time":"11:45","current":false,"selected":false,"checked":false,"disabled":true,"outgoing":true,"open":true,"number":2,"count":64,"percentage":91,"color":"#059669","target":"_self","ariaLabel":"Open advanced workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Unlimited"]}]' mobileLabel="Advanced example" class="showcase-instance showcase-instance--3" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Rich configuration usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Sidebar
|
||||
size="lg"
|
||||
label="Advanced example"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"id": "sidebar-2-1",
|
||||
"key": "sidebar-2-1",
|
||||
"value": "primary",
|
||||
"label": "Advanced workflow",
|
||||
"title": "Advanced workflow",
|
||||
"description": "A richer configuration with more supporting information and actions.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#sidebar-demo",
|
||||
"actionHref": "#sidebar-demo",
|
||||
"actionLabel": "Explore workflow",
|
||||
"icon": "icon-[lucide--circle-check]",
|
||||
"iconClass": "icon-[lucide--circle-check]",
|
||||
"variant": "success",
|
||||
"status": "Complete",
|
||||
"time": "11:45",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 32,
|
||||
"percentage": 91,
|
||||
"color": "#059669",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open advanced workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Unlimited"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"id": "sidebar-2-2",
|
||||
"key": "sidebar-2-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A richer configuration with more supporting information and actions.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#sidebar-demo",
|
||||
"actionHref": "#sidebar-demo",
|
||||
"actionLabel": "Explore workflow",
|
||||
"icon": "icon-[lucide--circle-check]",
|
||||
"iconClass": "icon-[lucide--circle-check]",
|
||||
"variant": "success",
|
||||
"status": "Complete",
|
||||
"time": "11:45",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": true,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 64,
|
||||
"percentage": 91,
|
||||
"color": "#059669",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open advanced workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Unlimited"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
mobileLabel="Advanced example"
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article></div></section>
|
||||
@@ -403,10 +674,10 @@ if (component) registerOutputHandler(component, "close", (payload) => <span>&
|
||||
if (component) registerOutputHandler(component, "select", (payload) => <span>{</span>
|
||||
console.log("select", payload)
|
||||
<span>}</span>)</code></pre></section></div></div></section>
|
||||
<section id="api" class="detail-section"><div class="detail-section-heading"><span>Component API</span><h2>Props and configuration</h2><p>All content and behavior shown above is supplied through these props and slots.</p></div><div class="docs-table-wrap"><table class="docs-table"><thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Required</th></tr></thead><tbody><tr><td><code>color</code></td><td>string</td><td><code>"primary"</code></td><td>No</td></tr><tr><td><code>size</code></td><td>string</td><td><code>"default"</code></td><td>No</td></tr><tr><td><code>label</code></td><td>string</td><td><code>"Sidebar"</code></td><td>No</td></tr><tr><td><code>items</code></td><td>unknown[]</td><td><code>[]</code></td><td>No</td></tr><tr><td><code>active</code></td><td>string</td><td><code>""</code></td><td>No</td></tr><tr><td><code>mobileLabel</code></td><td>string</td><td><code>"Open navigation"</code></td><td>No</td></tr><tr><td><code>drawerTitle</code></td><td>string</td><td><code>"Navigation"</code></td><td>No</td></tr><tr><td><code>class</code></td><td>string</td><td><code>""</code></td><td>No</td></tr></tbody></table></div></section>
|
||||
<section id="api" class="detail-section"><div class="detail-section-heading"><span>Component API</span><h2>Props and configuration</h2><p>All content and behavior shown above is supplied through these props and slots.</p></div><div class="docs-table-wrap"><table class="docs-table"><thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Required</th></tr></thead><tbody><tr><td><code>size</code></td><td>string</td><td><code>"default"</code></td><td>No</td></tr><tr><td><code>color</code></td><td>string</td><td><code>"primary"</code></td><td>No</td></tr><tr><td><code>label</code></td><td>string</td><td><code>"Sidebar"</code></td><td>No</td></tr><tr><td><code>items</code></td><td>unknown[]</td><td><code>[]</code></td><td>No</td></tr><tr><td><code>active</code></td><td>string</td><td><code>""</code></td><td>No</td></tr><tr><td><code>orientation</code></td><td>string</td><td><code>"horizontal"</code></td><td>No</td></tr><tr><td><code>mobileLabel</code></td><td>string</td><td><code>"Open navigation"</code></td><td>No</td></tr><tr><td><code>class</code></td><td>string</td><td><code>""</code></td><td>No</td></tr></tbody></table></div></section>
|
||||
</main>
|
||||
<aside class="detail-aside">
|
||||
<div class="detail-toc"><strong>On this page</strong><a href="#playground">Playground</a><a href="#sidebar-demo-1">Groups and nested levels</a><a href="#sidebar-demo-2">Drawer on small screens</a><a href="#events">Outputs</a><a href="#api">Props API</a></div>
|
||||
<div class="detail-toc"><strong>On this page</strong><a href="#playground">Playground</a><a href="#sidebar-demo-1">Production default</a><a href="#sidebar-demo-2">Compact application</a><a href="#sidebar-demo-3">Rich configuration</a><a href="#events">Outputs</a><a href="#api">Props API</a></div>
|
||||
</aside>
|
||||
</div>
|
||||
<nav class="detail-pagination">
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
// Generated by scripts/generate-showcase.mjs. Do not edit directly.
|
||||
page StepperDetail {
|
||||
layout = "showcase"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_size = ctx.url.searchParams.get("pg_size") ?? "default"
|
||||
state playground_steps = JSON.parse(ctx.url.searchParams.get("pg_steps") ?? "[{\"id\":\"stepper-0-1\",\"key\":\"stepper-0-1\",\"value\":\"primary\",\"label\":\"Primary workflow\",\"title\":\"Primary workflow\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"A configurable sample message.\",\"href\":\"#stepper-demo\",\"actionHref\":\"#stepper-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":true,\"selected\":true,\"checked\":true,\"disabled\":false,\"outgoing\":false,\"open\":true,\"number\":1,\"count\":16,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 1\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]},{\"id\":\"stepper-0-2\",\"key\":\"stepper-0-2\",\"value\":\"secondary\",\"label\":\"Additional option\",\"title\":\"Supporting example\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"Another configurable message.\",\"href\":\"#stepper-demo\",\"actionHref\":\"#stepper-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":false,\"selected\":false,\"checked\":false,\"disabled\":false,\"outgoing\":true,\"open\":true,\"number\":2,\"count\":32,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 2\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]}]")
|
||||
state playground_active = Number(ctx.url.searchParams.get("pg_active") ?? "0")
|
||||
state playground_orientation = ctx.url.searchParams.get("pg_orientation") ?? "horizontal"
|
||||
state playground_clickable = (ctx.url.searchParams.get("pg_clickable") ?? "false") === "true"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_label = ctx.url.searchParams.get("pg_label") ?? "Stepper"
|
||||
state playground_items = JSON.parse(ctx.url.searchParams.get("pg_items") ?? "[{\"id\":\"stepper-0-1\",\"key\":\"stepper-0-1\",\"value\":\"primary\",\"label\":\"Primary workflow\",\"title\":\"Primary workflow\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"A configurable sample message.\",\"href\":\"#stepper-demo\",\"actionHref\":\"#stepper-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":true,\"selected\":true,\"checked\":true,\"disabled\":false,\"outgoing\":false,\"open\":true,\"number\":1,\"count\":16,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 1\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]},{\"id\":\"stepper-0-2\",\"key\":\"stepper-0-2\",\"value\":\"secondary\",\"label\":\"Additional option\",\"title\":\"Supporting example\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"Another configurable message.\",\"href\":\"#stepper-demo\",\"actionHref\":\"#stepper-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":false,\"selected\":false,\"checked\":false,\"disabled\":false,\"outgoing\":true,\"open\":true,\"number\":2,\"count\":32,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 2\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]}]")
|
||||
state playground_active = ctx.url.searchParams.get("pg_active") ?? ""
|
||||
state playground_orientation = ctx.url.searchParams.get("pg_orientation") ?? "horizontal"
|
||||
state playground_class = ctx.url.searchParams.get("pg_class") ?? "showcase-instance showcase-instance--1"
|
||||
seo {
|
||||
title = "Stepper"
|
||||
@@ -22,20 +21,20 @@ page StepperDetail {
|
||||
<span class="showcase-eyebrow">Navigation component</span>
|
||||
<h1>Stepper</h1>
|
||||
<p>Theme-aware, responsive stepper component.</p>
|
||||
<div class="detail-badges"><span>8 props</span><span>2 slots</span><span>1 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
<div class="detail-badges"><span>7 props</span><span>1 slots</span><span>4 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
</div>
|
||||
<div class="detail-hero-icon"><span class="icon-[lucide--component] size-10" aria-hidden="true"></span></div>
|
||||
</header>
|
||||
<section id="playground" class="detail-section playground-section" data-playground data-playground-component="Stepper" data-playground-public-tag="true" data-playground-has-slot="true" data-playground-events="change">
|
||||
<section id="playground" class="detail-section playground-section" data-playground data-playground-component="Stepper" data-playground-public-tag="true" data-playground-has-slot="true" data-playground-events="change,previous,next,complete">
|
||||
<div class="detail-section-heading"><span>Interactive playground</span><h2>Configure Stepper</h2><p>Change any prop and inspect the server-rendered component immediately.</p></div>
|
||||
<div class="playground-workbench">
|
||||
<div class="playground-preview">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
<div class="playground-preview-source" data-playground-preview><Stepper color='{playground_color}' size='{playground_size}' steps='{playground_steps}' active='{playground_active}' orientation='{playground_orientation}' clickable='{playground_clickable}' label='{playground_label}' class='{playground_class}' /></div>
|
||||
<div class="playground-preview-source" data-playground-preview><Stepper size='{playground_size}' color='{playground_color}' label='{playground_label}' items='{playground_items}' active='{playground_active}' orientation='{playground_orientation}' class='{playground_class}' /></div>
|
||||
<section class="playground-code" aria-label="Current component code">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component code</span><button type="button" data-playground-copy><span class="icon-[lucide--copy] size-4" aria-hidden="true"></span>Copy</button></header>
|
||||
<pre><code data-playground-code><Stepper
|
||||
steps='[
|
||||
items='[
|
||||
<span>{</span>
|
||||
"id": "stepper-0-1",
|
||||
"key": "stepper-0-1",
|
||||
@@ -143,18 +142,14 @@ page StepperDetail {
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
label="Stepper">
|
||||
<div data-slot="step-<span>{</span>index<span>}</span>">
|
||||
<div class="showcase-slot">step-<span>{</span>index<span>}</span> slot</div>
|
||||
</div>
|
||||
</Stepper></code></pre>
|
||||
/></code></pre>
|
||||
</section>
|
||||
<div class="playground-status" data-playground-status aria-live="polite"></div>
|
||||
<div class="playground-event-log" data-playground-event-log aria-live="polite"><strong>Event output</strong><span>Interact with the preview to inspect the typed <code>payload</code>.</span></div>
|
||||
</div>
|
||||
<form class="playground-controls" data-playground-form>
|
||||
<header><div><span>Component props</span><strong>8 controls</strong></div><button type="reset"><span class="icon-[lucide--rotate-ccw] size-4" aria-hidden="true"></span>Reset</button></header>
|
||||
<div class="playground-fields"><label class="playground-field" for="playground-stepper-color"><span><strong>color</strong><small>string</small></span><select id="playground-stepper-color" name="pg_color"><option value="primary" selected>primary</option><option value="secondary">secondary</option><option value="success">success</option><option value="warning">warning</option><option value="danger">danger</option><option value="info">info</option></select></label><label class="playground-field" for="playground-stepper-size"><span><strong>size</strong><small>string</small></span><select id="playground-stepper-size" name="pg_size"><option value="default" selected>default</option><option value="xs">xs</option><option value="sm">sm</option><option value="md">md</option><option value="lg">lg</option><option value="xl">xl</option><option value="icon">icon</option><option value="icon-xs">icon-xs</option><option value="icon-sm">icon-sm</option><option value="icon-lg">icon-lg</option></select></label><label class="playground-field" for="playground-stepper-steps"><span><strong>steps</strong><small>unknown[]</small></span><textarea id="playground-stepper-steps" name="pg_steps" rows="5" spellcheck="false" data-playground-json>[
|
||||
<header><div><span>Component props</span><strong>7 controls</strong></div><button type="reset"><span class="icon-[lucide--rotate-ccw] size-4" aria-hidden="true"></span>Reset</button></header>
|
||||
<div class="playground-fields"><label class="playground-field" for="playground-stepper-size"><span><strong>size</strong><small>string</small></span><select id="playground-stepper-size" name="pg_size"><option value="default" selected>default</option><option value="xs">xs</option><option value="sm">sm</option><option value="md">md</option><option value="lg">lg</option><option value="xl">xl</option><option value="icon">icon</option><option value="icon-xs">icon-xs</option><option value="icon-sm">icon-sm</option><option value="icon-lg">icon-lg</option></select></label><label class="playground-field" for="playground-stepper-color"><span><strong>color</strong><small>string</small></span><select id="playground-stepper-color" name="pg_color"><option value="primary" selected>primary</option><option value="secondary">secondary</option><option value="success">success</option><option value="warning">warning</option><option value="danger">danger</option><option value="info">info</option></select></label><label class="playground-field" for="playground-stepper-label"><span><strong>label</strong><small>string</small></span><input id="playground-stepper-label" name="pg_label" type="text" value="Stepper" /></label><label class="playground-field" for="playground-stepper-items"><span><strong>items</strong><small>unknown[]</small></span><textarea id="playground-stepper-items" name="pg_items" rows="5" spellcheck="false" data-playground-json>[
|
||||
{
|
||||
"id": "stepper-0-1",
|
||||
"key": "stepper-0-1",
|
||||
@@ -261,7 +256,7 @@ page StepperDetail {
|
||||
"Standard"
|
||||
]
|
||||
}
|
||||
]</textarea><em data-playground-error></em></label><label class="playground-field" for="playground-stepper-active"><span><strong>active</strong><small>number</small></span><input id="playground-stepper-active" name="pg_active" type="number" value="0" /></label><label class="playground-field" for="playground-stepper-orientation"><span><strong>orientation</strong><small>string</small></span><select id="playground-stepper-orientation" name="pg_orientation"><option value="horizontal" selected>horizontal</option><option value="vertical">vertical</option></select></label><label class="playground-toggle" for="playground-stepper-clickable"><span><strong>clickable</strong><small>boolean</small></span><input id="playground-stepper-clickable" name="pg_clickable" type="checkbox" value="true" data-playground-boolean /><i aria-hidden="true"></i></label><label class="playground-field" for="playground-stepper-label"><span><strong>label</strong><small>string</small></span><input id="playground-stepper-label" name="pg_label" type="text" value="Stepper" /></label><label class="playground-field" for="playground-stepper-class"><span><strong>class</strong><small>string</small></span><input id="playground-stepper-class" name="pg_class" type="text" value="showcase-instance showcase-instance--1" /></label></div>
|
||||
]</textarea><em data-playground-error></em></label><label class="playground-field" for="playground-stepper-active"><span><strong>active</strong><small>string</small></span><input id="playground-stepper-active" name="pg_active" type="text" value="" /></label><label class="playground-field" for="playground-stepper-orientation"><span><strong>orientation</strong><small>string</small></span><select id="playground-stepper-orientation" name="pg_orientation"><option value="horizontal" selected>horizontal</option><option value="vertical">vertical</option></select></label><label class="playground-field" for="playground-stepper-class"><span><strong>class</strong><small>string</small></span><input id="playground-stepper-class" name="pg_class" type="text" value="showcase-instance showcase-instance--1" /></label></div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
@@ -270,128 +265,414 @@ page StepperDetail {
|
||||
<section class="detail-section"><div class="detail-section-heading"><span>Live examples</span><h2>Designed for real product surfaces</h2><p>Compare configurations and resize the browser to check responsive behavior.</p></div><div class="demo-list">
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Horizontal progress</h2><p>Steps before the active one read as complete, the active one is highlighted, and the rest are muted.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Production default</h2><p>Balanced spacing, hierarchy, and content for the most common product workflow.</p></div>
|
||||
<span class="demo-case-number">01</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="stepper-demo-1" class="demo-canvas demo-canvas--1">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Stepper size="default" steps='[{"label":"Account","description":"Your details"},{"label":"Billing","description":"Payment method"},{"label":"Confirm","description":"Review and submit"}]' active="1" clickable="false" label="Stepper" class="showcase-instance showcase-instance--1" /></div>
|
||||
<div class="demo-render"><Stepper size="default" label="Stepper" items='[{"id":"stepper-0-1","key":"stepper-0-1","value":"primary","label":"Primary workflow","title":"Primary workflow","description":"A clean default configuration for everyday product interfaces.","text":"A configurable sample message.","href":"#stepper-demo","actionHref":"#stepper-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":16,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"stepper-0-2","key":"stepper-0-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A clean default configuration for everyday product interfaces.","text":"Another configurable message.","href":"#stepper-demo","actionHref":"#stepper-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":32,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' class="showcase-instance showcase-instance--1" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Horizontal progress usage">
|
||||
<section class="demo-code" aria-label="Production default usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Stepper
|
||||
steps='[
|
||||
items='[
|
||||
<span>{</span>
|
||||
"label": "Account",
|
||||
"description": "Your details"
|
||||
"id": "stepper-0-1",
|
||||
"key": "stepper-0-1",
|
||||
"value": "primary",
|
||||
"label": "Primary workflow",
|
||||
"title": "Primary workflow",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#stepper-demo",
|
||||
"actionHref": "#stepper-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 16,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Billing",
|
||||
"description": "Payment method"
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Confirm",
|
||||
"description": "Review and submit"
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"id": "stepper-0-2",
|
||||
"key": "stepper-0-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A clean default configuration for everyday product interfaces.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#stepper-demo",
|
||||
"actionHref": "#stepper-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--sparkles]",
|
||||
"iconClass": "icon-[lucide--sparkles]",
|
||||
"variant": "primary",
|
||||
"status": "Active",
|
||||
"time": "09:30",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": false,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 32,
|
||||
"percentage": 72,
|
||||
"color": "#7c3aed",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open primary workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
active="1"
|
||||
label="Stepper">
|
||||
<div data-slot="step-<span>{</span>index<span>}</span>">
|
||||
<div class="showcase-slot">step-<span>{</span>index<span>}</span> slot</div>
|
||||
</div>
|
||||
</Stepper></code></pre>
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Recommended</span><h2>Vertical with icons</h2><p>Vertical orientation suits a sidebar or a narrow column. Any step may carry an iconify class instead of its number.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Dense UI</span><h2>Compact application</h2><p>A tighter variation for dashboards, side panels, tables, and operational interfaces.</p></div>
|
||||
<span class="demo-case-number">02</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="stepper-demo-2" class="demo-canvas demo-canvas--2">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Stepper size="sm" steps='[{"label":"Cloned","icon":"icon-[lucide--git-branch]"},{"label":"Built","icon":"icon-[lucide--hammer]"},{"label":"Deployed","icon":"icon-[lucide--rocket]"}]' active="2" orientation="vertical" clickable="false" label="Compact example" class="showcase-instance showcase-instance--2" /></div>
|
||||
<div class="demo-render"><Stepper size="sm" label="Compact example" items='[{"id":"stepper-1-1","key":"stepper-1-1","value":"primary","label":"Secondary workflow","title":"Secondary workflow","description":"A compact configuration designed for dense application layouts.","text":"A configurable sample message.","href":"#stepper-demo","actionHref":"#stepper-demo","actionLabel":"View details","icon":"icon-[lucide--zap]","iconClass":"icon-[lucide--zap]","variant":"secondary","status":"Active","time":"10:15","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":24,"percentage":48,"color":"#0284c7","target":"_self","ariaLabel":"Open secondary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"stepper-1-2","key":"stepper-1-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A compact configuration designed for dense application layouts.","text":"Another configurable message.","href":"#stepper-demo","actionHref":"#stepper-demo","actionLabel":"View details","icon":"icon-[lucide--zap]","iconClass":"icon-[lucide--zap]","variant":"secondary","status":"Active","time":"10:15","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":48,"percentage":48,"color":"#0284c7","target":"_self","ariaLabel":"Open secondary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' class="showcase-instance showcase-instance--2" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Vertical with icons usage">
|
||||
<section class="demo-code" aria-label="Compact application usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Stepper
|
||||
size="sm"
|
||||
steps='[
|
||||
label="Compact example"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"label": "Cloned",
|
||||
"icon": "icon-[lucide--git-branch]"
|
||||
"id": "stepper-1-1",
|
||||
"key": "stepper-1-1",
|
||||
"value": "primary",
|
||||
"label": "Secondary workflow",
|
||||
"title": "Secondary workflow",
|
||||
"description": "A compact configuration designed for dense application layouts.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#stepper-demo",
|
||||
"actionHref": "#stepper-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--zap]",
|
||||
"iconClass": "icon-[lucide--zap]",
|
||||
"variant": "secondary",
|
||||
"status": "Active",
|
||||
"time": "10:15",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 24,
|
||||
"percentage": 48,
|
||||
"color": "#0284c7",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open secondary workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Built",
|
||||
"icon": "icon-[lucide--hammer]"
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Deployed",
|
||||
"icon": "icon-[lucide--rocket]"
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"id": "stepper-1-2",
|
||||
"key": "stepper-1-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A compact configuration designed for dense application layouts.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#stepper-demo",
|
||||
"actionHref": "#stepper-demo",
|
||||
"actionLabel": "View details",
|
||||
"icon": "icon-[lucide--zap]",
|
||||
"iconClass": "icon-[lucide--zap]",
|
||||
"variant": "secondary",
|
||||
"status": "Active",
|
||||
"time": "10:15",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": false,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 48,
|
||||
"percentage": 48,
|
||||
"color": "#0284c7",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open secondary workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
active="2"
|
||||
orientation="vertical"
|
||||
label="Compact example">
|
||||
<div data-slot="step-<span>{</span>index<span>}</span>">
|
||||
<div class="showcase-slot">step-<span>{</span>index<span>}</span> slot</div>
|
||||
</div>
|
||||
</Stepper></code></pre>
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Advanced</span><h2>Clickable steps</h2><p>With clickable the steps emit a change output and take arrow-key roving focus. Without it the stepper is read-only and stays out of the tab order.</p></div>
|
||||
<div><span class="demo-case-eyebrow">Extended</span><h2>Rich configuration</h2><p>A more expressive variation using additional data, stronger emphasis, and optional states.</p></div>
|
||||
<span class="demo-case-number">03</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="stepper-demo-3" class="demo-canvas demo-canvas--3">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Stepper size="lg" steps='[{"label":"One"},{"label":"Two"},{"label":"Three"}]' active="0" clickable="true" label="Advanced example" class="showcase-instance showcase-instance--3" /></div>
|
||||
<div class="demo-render"><Stepper size="lg" label="Advanced example" items='[{"id":"stepper-2-1","key":"stepper-2-1","value":"primary","label":"Advanced workflow","title":"Advanced workflow","description":"A richer configuration with more supporting information and actions.","text":"A configurable sample message.","href":"#stepper-demo","actionHref":"#stepper-demo","actionLabel":"Explore workflow","icon":"icon-[lucide--circle-check]","iconClass":"icon-[lucide--circle-check]","variant":"success","status":"Complete","time":"11:45","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":32,"percentage":91,"color":"#059669","target":"_self","ariaLabel":"Open advanced workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Unlimited"]},{"id":"stepper-2-2","key":"stepper-2-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A richer configuration with more supporting information and actions.","text":"Another configurable message.","href":"#stepper-demo","actionHref":"#stepper-demo","actionLabel":"Explore workflow","icon":"icon-[lucide--circle-check]","iconClass":"icon-[lucide--circle-check]","variant":"success","status":"Complete","time":"11:45","current":false,"selected":false,"checked":false,"disabled":true,"outgoing":true,"open":true,"number":2,"count":64,"percentage":91,"color":"#059669","target":"_self","ariaLabel":"Open advanced workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Unlimited"]}]' class="showcase-instance showcase-instance--3" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Clickable steps usage">
|
||||
<section class="demo-code" aria-label="Rich configuration usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Stepper
|
||||
size="lg"
|
||||
steps='[
|
||||
label="Advanced example"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"label": "One"
|
||||
"id": "stepper-2-1",
|
||||
"key": "stepper-2-1",
|
||||
"value": "primary",
|
||||
"label": "Advanced workflow",
|
||||
"title": "Advanced workflow",
|
||||
"description": "A richer configuration with more supporting information and actions.",
|
||||
"text": "A configurable sample message.",
|
||||
"href": "#stepper-demo",
|
||||
"actionHref": "#stepper-demo",
|
||||
"actionLabel": "Explore workflow",
|
||||
"icon": "icon-[lucide--circle-check]",
|
||||
"iconClass": "icon-[lucide--circle-check]",
|
||||
"variant": "success",
|
||||
"status": "Complete",
|
||||
"time": "11:45",
|
||||
"current": true,
|
||||
"selected": true,
|
||||
"checked": true,
|
||||
"disabled": false,
|
||||
"outgoing": false,
|
||||
"open": true,
|
||||
"number": 1,
|
||||
"count": 32,
|
||||
"percentage": 91,
|
||||
"color": "#059669",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open advanced workflow 1",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Two"
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Three"
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Unlimited"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"id": "stepper-2-2",
|
||||
"key": "stepper-2-2",
|
||||
"value": "secondary",
|
||||
"label": "Additional option",
|
||||
"title": "Supporting example",
|
||||
"description": "A richer configuration with more supporting information and actions.",
|
||||
"text": "Another configurable message.",
|
||||
"href": "#stepper-demo",
|
||||
"actionHref": "#stepper-demo",
|
||||
"actionLabel": "Explore workflow",
|
||||
"icon": "icon-[lucide--circle-check]",
|
||||
"iconClass": "icon-[lucide--circle-check]",
|
||||
"variant": "success",
|
||||
"status": "Complete",
|
||||
"time": "11:45",
|
||||
"current": false,
|
||||
"selected": false,
|
||||
"checked": false,
|
||||
"disabled": true,
|
||||
"outgoing": true,
|
||||
"open": true,
|
||||
"number": 2,
|
||||
"count": 64,
|
||||
"percentage": 91,
|
||||
"color": "#059669",
|
||||
"target": "_self",
|
||||
"ariaLabel": "Open advanced workflow 2",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Unlimited"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
clickable="true"
|
||||
label="Advanced example">
|
||||
<div data-slot="step-<span>{</span>index<span>}</span>">
|
||||
<div class="showcase-slot">step-<span>{</span>index<span>}</span> slot</div>
|
||||
</div>
|
||||
</Stepper></code></pre>
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article></div></section>
|
||||
<section id="events" class="detail-section"><div class="detail-section-heading"><span>Component outputs</span><h2>Receive every typed component output</h2><p>Use declarative output handlers in <code>.wrn</code> files or register a direct output handler from JavaScript. The canonical API exposes <code>payload</code> and does not require <code>event.detail</code>.</p></div><div class="detail-events-grid"><div class="detail-events-list"><div><code>@change</code><span>Fires when the component's committed value or selection changes.</span></div></div><div class="detail-event-examples"><section class="demo-code"><header><span><span class="icon-[lucide--braces] size-4" aria-hidden="true"></span>Declarative handlers</span><small>.wrn</small></header><pre><code><Stepper
|
||||
<section id="events" class="detail-section"><div class="detail-section-heading"><span>Component outputs</span><h2>Receive every typed component output</h2><p>Use declarative output handlers in <code>.wrn</code> files or register a direct output handler from JavaScript. The canonical API exposes <code>payload</code> and does not require <code>event.detail</code>.</p></div><div class="detail-events-grid"><div class="detail-events-list"><div><code>@change</code><span>Fires when the component's committed value or selection changes.</span></div><div><code>@previous</code><span>Fires when the component emits the previous event.</span></div><div><code>@next</code><span>Fires when the component emits the next event.</span></div><div><code>@complete</code><span>Fires when the component emits the complete event.</span></div></div><div class="detail-event-examples"><section class="demo-code"><header><span><span class="icon-[lucide--braces] size-4" aria-hidden="true"></span>Declarative handlers</span><small>.wrn</small></header><pre><code><Stepper
|
||||
@change='console.log(payload)'
|
||||
@previous='console.log(payload)'
|
||||
@next='console.log(payload)'
|
||||
@complete='console.log(payload)'
|
||||
/></code></pre></section><section class="demo-code"><header><span><span class="icon-[lucide--radio] size-4" aria-hidden="true"></span>Direct output handlers</span><small>.js</small></header><pre><code>import <span>{</span> registerOutputHandler <span>}</span> from "@wrnexus/csr/outputs"
|
||||
|
||||
const component = document.querySelector("[data-ui-component=\"Stepper\"], [data-component=\"Stepper\"]")
|
||||
|
||||
if (component) registerOutputHandler(component, "change", (payload) => <span>{</span>
|
||||
console.log("change", payload)
|
||||
<span>}</span>)
|
||||
|
||||
if (component) registerOutputHandler(component, "previous", (payload) => <span>{</span>
|
||||
console.log("previous", payload)
|
||||
<span>}</span>)
|
||||
|
||||
if (component) registerOutputHandler(component, "next", (payload) => <span>{</span>
|
||||
console.log("next", payload)
|
||||
<span>}</span>)
|
||||
|
||||
if (component) registerOutputHandler(component, "complete", (payload) => <span>{</span>
|
||||
console.log("complete", payload)
|
||||
<span>}</span>)</code></pre></section></div></div></section>
|
||||
<section id="api" class="detail-section"><div class="detail-section-heading"><span>Component API</span><h2>Props and configuration</h2><p>All content and behavior shown above is supplied through these props and slots.</p></div><div class="docs-table-wrap"><table class="docs-table"><thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Required</th></tr></thead><tbody><tr><td><code>color</code></td><td>string</td><td><code>"primary"</code></td><td>No</td></tr><tr><td><code>size</code></td><td>string</td><td><code>"default"</code></td><td>No</td></tr><tr><td><code>steps</code></td><td>unknown[]</td><td><code>[]</code></td><td>No</td></tr><tr><td><code>active</code></td><td>number</td><td><code>0</code></td><td>No</td></tr><tr><td><code>orientation</code></td><td>string</td><td><code>"horizontal"</code></td><td>No</td></tr><tr><td><code>clickable</code></td><td>boolean</td><td><code>false</code></td><td>No</td></tr><tr><td><code>label</code></td><td>string</td><td><code>"Progress"</code></td><td>No</td></tr><tr><td><code>class</code></td><td>string</td><td><code>""</code></td><td>No</td></tr></tbody></table></div></section>
|
||||
<section id="api" class="detail-section"><div class="detail-section-heading"><span>Component API</span><h2>Props and configuration</h2><p>All content and behavior shown above is supplied through these props and slots.</p></div><div class="docs-table-wrap"><table class="docs-table"><thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Required</th></tr></thead><tbody><tr><td><code>size</code></td><td>string</td><td><code>"default"</code></td><td>No</td></tr><tr><td><code>color</code></td><td>string</td><td><code>"primary"</code></td><td>No</td></tr><tr><td><code>label</code></td><td>string</td><td><code>"Stepper"</code></td><td>No</td></tr><tr><td><code>items</code></td><td>unknown[]</td><td><code>[]</code></td><td>No</td></tr><tr><td><code>active</code></td><td>string</td><td><code>""</code></td><td>No</td></tr><tr><td><code>orientation</code></td><td>string</td><td><code>"horizontal"</code></td><td>No</td></tr><tr><td><code>class</code></td><td>string</td><td><code>""</code></td><td>No</td></tr></tbody></table></div></section>
|
||||
</main>
|
||||
<aside class="detail-aside">
|
||||
<div class="detail-toc"><strong>On this page</strong><a href="#playground">Playground</a><a href="#stepper-demo-1">Horizontal progress</a><a href="#stepper-demo-2">Vertical with icons</a><a href="#stepper-demo-3">Clickable steps</a><a href="#events">Outputs</a><a href="#api">Props API</a></div>
|
||||
<div class="detail-toc"><strong>On this page</strong><a href="#playground">Playground</a><a href="#stepper-demo-1">Production default</a><a href="#stepper-demo-2">Compact application</a><a href="#stepper-demo-3">Rich configuration</a><a href="#events">Outputs</a><a href="#api">Props API</a></div>
|
||||
</aside>
|
||||
</div>
|
||||
<nav class="detail-pagination">
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
// Generated by scripts/generate-showcase.mjs. Do not edit directly.
|
||||
page TabsDetail {
|
||||
layout = "showcase"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_size = ctx.url.searchParams.get("pg_size") ?? "default"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_label = ctx.url.searchParams.get("pg_label") ?? "Tabs"
|
||||
state playground_items = JSON.parse(ctx.url.searchParams.get("pg_items") ?? "[{\"id\":\"tabs-0-1\",\"key\":\"tabs-0-1\",\"value\":\"primary\",\"label\":\"Primary workflow\",\"title\":\"Primary workflow\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"A configurable sample message.\",\"href\":\"#tabs-demo\",\"actionHref\":\"#tabs-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":true,\"selected\":true,\"checked\":true,\"disabled\":false,\"outgoing\":false,\"open\":true,\"number\":1,\"count\":16,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 1\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]},{\"id\":\"tabs-0-2\",\"key\":\"tabs-0-2\",\"value\":\"secondary\",\"label\":\"Additional option\",\"title\":\"Supporting example\",\"description\":\"A clean default configuration for everyday product interfaces.\",\"text\":\"Another configurable message.\",\"href\":\"#tabs-demo\",\"actionHref\":\"#tabs-demo\",\"actionLabel\":\"View details\",\"icon\":\"icon-[lucide--sparkles]\",\"iconClass\":\"icon-[lucide--sparkles]\",\"variant\":\"primary\",\"status\":\"Active\",\"time\":\"09:30\",\"current\":false,\"selected\":false,\"checked\":false,\"disabled\":false,\"outgoing\":true,\"open\":true,\"number\":2,\"count\":32,\"percentage\":72,\"color\":\"#7c3aed\",\"target\":\"_self\",\"ariaLabel\":\"Open primary workflow 2\",\"items\":[{\"label\":\"Nested option A\",\"value\":\"nested-a\"},{\"label\":\"Nested option B\",\"value\":\"nested-b\"}],\"links\":[{\"label\":\"Documentation\",\"href\":\"#documentation\"},{\"label\":\"API reference\",\"href\":\"#api-reference\"}],\"values\":[\"Included\",\"Standard\"]}]")
|
||||
state playground_active = ctx.url.searchParams.get("pg_active") ?? ""
|
||||
state playground_orientation = ctx.url.searchParams.get("pg_orientation") ?? "horizontal"
|
||||
state playground_mode = ctx.url.searchParams.get("pg_mode") ?? "client"
|
||||
state playground_param = ctx.url.searchParams.get("pg_param") ?? "tab"
|
||||
state playground_label = ctx.url.searchParams.get("pg_label") ?? "Tabs"
|
||||
state playground_class = ctx.url.searchParams.get("pg_class") ?? "showcase-instance showcase-instance--1"
|
||||
seo {
|
||||
title = "Tabs"
|
||||
@@ -23,16 +21,16 @@ page TabsDetail {
|
||||
<span class="showcase-eyebrow">Navigation component</span>
|
||||
<h1>Tabs</h1>
|
||||
<p>Switch between related responsive content panels with horizontal or vertical orientation and selection events.</p>
|
||||
<div class="detail-badges"><span>9 props</span><span>2 slots</span><span>2 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
<div class="detail-badges"><span>7 props</span><span>1 slots</span><span>0 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
</div>
|
||||
<div class="detail-hero-icon"><span class="icon-[lucide--component] size-10" aria-hidden="true"></span></div>
|
||||
</header>
|
||||
<section id="playground" class="detail-section playground-section" data-playground data-playground-component="Tabs" data-playground-public-tag="true" data-playground-has-slot="true" data-playground-events="change,select">
|
||||
<section id="playground" class="detail-section playground-section" data-playground data-playground-component="Tabs" data-playground-public-tag="true" data-playground-has-slot="true" data-playground-events="">
|
||||
<div class="detail-section-heading"><span>Interactive playground</span><h2>Configure Tabs</h2><p>Change any prop and inspect the server-rendered component immediately.</p></div>
|
||||
<div class="playground-workbench">
|
||||
<div class="playground-preview">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
<div class="playground-preview-source" data-playground-preview><Tabs color='{playground_color}' size='{playground_size}' items='{playground_items}' active='{playground_active}' orientation='{playground_orientation}' mode='{playground_mode}' param='{playground_param}' label='{playground_label}' class='{playground_class}' /></div>
|
||||
<div class="playground-preview-source" data-playground-preview><Tabs size='{playground_size}' color='{playground_color}' label='{playground_label}' items='{playground_items}' active='{playground_active}' orientation='{playground_orientation}' class='{playground_class}' /></div>
|
||||
<section class="playground-code" aria-label="Current component code">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component code</span><button type="button" data-playground-copy><span class="icon-[lucide--copy] size-4" aria-hidden="true"></span>Copy</button></header>
|
||||
<pre><code data-playground-code><Tabs
|
||||
@@ -143,18 +141,15 @@ page TabsDetail {
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'>
|
||||
<div data-slot="panel-<span>{</span>valueOf(item, index)<span>}</span>">
|
||||
<div class="showcase-slot">panel-<span>{</span>value Of(item, index)<span>}</span> slot</div>
|
||||
</div>
|
||||
</Tabs></code></pre>
|
||||
]'
|
||||
/></code></pre>
|
||||
</section>
|
||||
<div class="playground-status" data-playground-status aria-live="polite"></div>
|
||||
<div class="playground-event-log" data-playground-event-log aria-live="polite"><strong>Event output</strong><span>Interact with the preview to inspect the typed <code>payload</code>.</span></div>
|
||||
|
||||
</div>
|
||||
<form class="playground-controls" data-playground-form>
|
||||
<header><div><span>Component props</span><strong>9 controls</strong></div><button type="reset"><span class="icon-[lucide--rotate-ccw] size-4" aria-hidden="true"></span>Reset</button></header>
|
||||
<div class="playground-fields"><label class="playground-field" for="playground-tabs-color"><span><strong>color</strong><small>string</small></span><select id="playground-tabs-color" name="pg_color"><option value="primary" selected>primary</option><option value="secondary">secondary</option><option value="success">success</option><option value="warning">warning</option><option value="danger">danger</option><option value="info">info</option></select></label><label class="playground-field" for="playground-tabs-size"><span><strong>size</strong><small>string</small></span><select id="playground-tabs-size" name="pg_size"><option value="default" selected>default</option><option value="sm">sm</option><option value="lg">lg</option><option value="xs">xs</option><option value="md">md</option><option value="xl">xl</option><option value="icon">icon</option><option value="icon-xs">icon-xs</option><option value="icon-sm">icon-sm</option><option value="icon-lg">icon-lg</option></select></label><label class="playground-field" for="playground-tabs-items"><span><strong>items</strong><small>unknown[]</small></span><textarea id="playground-tabs-items" name="pg_items" rows="5" spellcheck="false" data-playground-json>[
|
||||
<header><div><span>Component props</span><strong>7 controls</strong></div><button type="reset"><span class="icon-[lucide--rotate-ccw] size-4" aria-hidden="true"></span>Reset</button></header>
|
||||
<div class="playground-fields"><label class="playground-field" for="playground-tabs-size"><span><strong>size</strong><small>string</small></span><select id="playground-tabs-size" name="pg_size"><option value="default" selected>default</option><option value="sm">sm</option><option value="lg">lg</option><option value="xs">xs</option><option value="md">md</option><option value="xl">xl</option><option value="icon">icon</option><option value="icon-xs">icon-xs</option><option value="icon-sm">icon-sm</option><option value="icon-lg">icon-lg</option></select></label><label class="playground-field" for="playground-tabs-color"><span><strong>color</strong><small>string</small></span><select id="playground-tabs-color" name="pg_color"><option value="primary" selected>primary</option><option value="secondary">secondary</option><option value="success">success</option><option value="warning">warning</option><option value="danger">danger</option><option value="info">info</option></select></label><label class="playground-field" for="playground-tabs-label"><span><strong>label</strong><small>string</small></span><input id="playground-tabs-label" name="pg_label" type="text" value="Tabs" /></label><label class="playground-field" for="playground-tabs-items"><span><strong>items</strong><small>unknown[]</small></span><textarea id="playground-tabs-items" name="pg_items" rows="5" spellcheck="false" data-playground-json>[
|
||||
{
|
||||
"id": "tabs-0-1",
|
||||
"key": "tabs-0-1",
|
||||
@@ -261,7 +256,7 @@ page TabsDetail {
|
||||
"Standard"
|
||||
]
|
||||
}
|
||||
]</textarea><em data-playground-error></em></label><label class="playground-field" for="playground-tabs-active"><span><strong>active</strong><small>string</small></span><input id="playground-tabs-active" name="pg_active" type="text" value="" /></label><label class="playground-field" for="playground-tabs-orientation"><span><strong>orientation</strong><small>string</small></span><select id="playground-tabs-orientation" name="pg_orientation"><option value="horizontal" selected>horizontal</option><option value="vertical">vertical</option></select></label><label class="playground-field" for="playground-tabs-mode"><span><strong>mode</strong><small>string</small></span><input id="playground-tabs-mode" name="pg_mode" type="text" value="client" /></label><label class="playground-field" for="playground-tabs-param"><span><strong>param</strong><small>string</small></span><input id="playground-tabs-param" name="pg_param" type="text" value="tab" /></label><label class="playground-field" for="playground-tabs-label"><span><strong>label</strong><small>string</small></span><input id="playground-tabs-label" name="pg_label" type="text" value="Tabs" /></label><label class="playground-field" for="playground-tabs-class"><span><strong>class</strong><small>string</small></span><input id="playground-tabs-class" name="pg_class" type="text" value="showcase-instance showcase-instance--1" /></label></div>
|
||||
]</textarea><em data-playground-error></em></label><label class="playground-field" for="playground-tabs-active"><span><strong>active</strong><small>string</small></span><input id="playground-tabs-active" name="pg_active" type="text" value="" /></label><label class="playground-field" for="playground-tabs-orientation"><span><strong>orientation</strong><small>string</small></span><select id="playground-tabs-orientation" name="pg_orientation"><option value="horizontal" selected>horizontal</option><option value="vertical">vertical</option></select></label><label class="playground-field" for="playground-tabs-class"><span><strong>class</strong><small>string</small></span><input id="playground-tabs-class" name="pg_class" type="text" value="showcase-instance showcase-instance--1" /></label></div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
@@ -277,11 +272,12 @@ page TabsDetail {
|
||||
<div id="tabs-demo-1" class="demo-canvas demo-canvas--1">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Tabs size="default" items='[{"label":"Overview","value":"overview","content":"Overview content"},{"label":"Requirements","value":"requirements","content":"Requirements content"},{"label":"Process","value":"process","content":"Process content"}]' active="overview" orientation="horizontal" label="Service information" class="showcase-instance showcase-instance--1" /></div>
|
||||
<div class="demo-render"><Tabs size="default" label="Service information" items='[{"label":"Overview","value":"overview","content":"Overview content"},{"label":"Requirements","value":"requirements","content":"Requirements content"},{"label":"Process","value":"process","content":"Process content"}]' active="overview" orientation="horizontal" class="showcase-instance showcase-instance--1" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Horizontal content tabs usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Tabs
|
||||
label="Service information"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"label": "Overview",
|
||||
@@ -300,71 +296,26 @@ page TabsDetail {
|
||||
<span>}</span>
|
||||
]'
|
||||
active="overview"
|
||||
label="Service information">
|
||||
<div data-slot="panel-<span>{</span>valueOf(item, index)<span>}</span>">
|
||||
<div class="showcase-slot">panel-<span>{</span>value Of(item, index)<span>}</span> slot</div>
|
||||
</div>
|
||||
</Tabs></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Advanced</span><h2>Mirrored into the URL</h2><p>With mode=url the selection is written to a query parameter using pushState, so the panel swaps without a page load, the tab survives a reload, and the back button steps through the tabs you visited.</p></div>
|
||||
<span class="demo-case-number">02</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="tabs-demo-2" class="demo-canvas demo-canvas--2">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Tabs size="sm" items='[{"label":"Account","value":"account","description":"Profile and credentials."},{"label":"Billing","value":"billing","description":"Invoices and payment method."},{"label":"Team","value":"team","description":"Members and their roles."}]' active="account" mode="url" param="tab" label="Account settings" class="showcase-instance showcase-instance--2" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Mirrored into the URL usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Tabs
|
||||
size="sm"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"label": "Account",
|
||||
"value": "account",
|
||||
"description": "Profile and credentials."
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Billing",
|
||||
"value": "billing",
|
||||
"description": "Invoices and payment method."
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Team",
|
||||
"value": "team",
|
||||
"description": "Members and their roles."
|
||||
<span>}</span>
|
||||
]'
|
||||
active="account"
|
||||
mode="url"
|
||||
label="Account settings">
|
||||
<div data-slot="panel-<span>{</span>valueOf(item, index)<span>}</span>">
|
||||
<div class="showcase-slot">panel-<span>{</span>value Of(item, index)<span>}</span> slot</div>
|
||||
</div>
|
||||
</Tabs></code></pre>
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Compact</span><h2>Compact application tabs</h2><p>Use smaller tabs in dashboards, panels, and dense product interfaces.</p></div>
|
||||
<span class="demo-case-number">03</span>
|
||||
<span class="demo-case-number">02</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="tabs-demo-3" class="demo-canvas demo-canvas--3">
|
||||
<div id="tabs-demo-2" class="demo-canvas demo-canvas--2">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Tabs size="sm" items='[{"label":"Details","value":"details"},{"label":"History","value":"history"},{"label":"Files","value":"files"}]' active="details" label="Record views" class="showcase-instance showcase-instance--3" /></div>
|
||||
<div class="demo-render"><Tabs size="sm" label="Record views" items='[{"label":"Details","value":"details"},{"label":"History","value":"history"},{"label":"Files","value":"files"}]' active="details" class="showcase-instance showcase-instance--2" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Compact application tabs usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Tabs
|
||||
size="sm"
|
||||
label="Record views"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"label": "Details",
|
||||
@@ -380,29 +331,26 @@ page TabsDetail {
|
||||
<span>}</span>
|
||||
]'
|
||||
active="details"
|
||||
label="Record views">
|
||||
<div data-slot="panel-<span>{</span>valueOf(item, index)<span>}</span>">
|
||||
<div class="showcase-slot">panel-<span>{</span>value Of(item, index)<span>}</span> slot</div>
|
||||
</div>
|
||||
</Tabs></code></pre>
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<div><span class="demo-case-eyebrow">Advanced</span><h2>Vertical settings tabs</h2><p>Use vertical tabs for settings, configuration, and long-form navigation.</p></div>
|
||||
<span class="demo-case-number">04</span>
|
||||
<span class="demo-case-number">03</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="tabs-demo-4" class="demo-canvas demo-canvas--4">
|
||||
<div id="tabs-demo-3" class="demo-canvas demo-canvas--3">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
|
||||
<div class="demo-render"><Tabs size="lg" items='[{"label":"Profile","value":"profile","icon":"icon-[lucide--user]"},{"label":"Security","value":"security","icon":"icon-[lucide--shield]"},{"label":"Notifications","value":"notifications","icon":"icon-[lucide--bell]"}]' active="security" orientation="vertical" label="Settings" class="showcase-instance showcase-instance--4" /></div>
|
||||
<div class="demo-render"><Tabs size="lg" label="Settings" items='[{"label":"Profile","value":"profile","icon":"icon-[lucide--user]"},{"label":"Security","value":"security","icon":"icon-[lucide--shield]"},{"label":"Notifications","value":"notifications","icon":"icon-[lucide--bell]"}]' active="security" orientation="vertical" class="showcase-instance showcase-instance--3" /></div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="Vertical settings tabs usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
<pre><code><Tabs
|
||||
size="lg"
|
||||
label="Settings"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"label": "Profile",
|
||||
@@ -422,32 +370,15 @@ page TabsDetail {
|
||||
]'
|
||||
active="security"
|
||||
orientation="vertical"
|
||||
label="Settings">
|
||||
<div data-slot="panel-<span>{</span>valueOf(item, index)<span>}</span>">
|
||||
<div class="showcase-slot">panel-<span>{</span>value Of(item, index)<span>}</span> slot</div>
|
||||
</div>
|
||||
</Tabs></code></pre>
|
||||
/></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article></div></section>
|
||||
<section id="events" class="detail-section"><div class="detail-section-heading"><span>Component outputs</span><h2>Receive every typed component output</h2><p>Use declarative output handlers in <code>.wrn</code> files or register a direct output handler from JavaScript. The canonical API exposes <code>payload</code> and does not require <code>event.detail</code>.</p></div><div class="detail-events-grid"><div class="detail-events-list"><div><code>@change</code><span>Fires when the component's committed value or selection changes.</span></div><div><code>@select</code><span>Fires when an item, option, card, or result is selected.</span></div></div><div class="detail-event-examples"><section class="demo-code"><header><span><span class="icon-[lucide--braces] size-4" aria-hidden="true"></span>Declarative handlers</span><small>.wrn</small></header><pre><code><Tabs
|
||||
@change='console.log(payload)'
|
||||
@select='console.log(payload)'
|
||||
/></code></pre></section><section class="demo-code"><header><span><span class="icon-[lucide--radio] size-4" aria-hidden="true"></span>Direct output handlers</span><small>.js</small></header><pre><code>import <span>{</span> registerOutputHandler <span>}</span> from "@wrnexus/csr/outputs"
|
||||
|
||||
const component = document.querySelector("[data-ui-component=\"Tabs\"], [data-component=\"Tabs\"]")
|
||||
|
||||
if (component) registerOutputHandler(component, "change", (payload) => <span>{</span>
|
||||
console.log("change", payload)
|
||||
<span>}</span>)
|
||||
|
||||
if (component) registerOutputHandler(component, "select", (payload) => <span>{</span>
|
||||
console.log("select", payload)
|
||||
<span>}</span>)</code></pre></section></div></div></section>
|
||||
<section id="api" class="detail-section"><div class="detail-section-heading"><span>Component API</span><h2>Props and configuration</h2><p>All content and behavior shown above is supplied through these props and slots.</p></div><div class="docs-table-wrap"><table class="docs-table"><thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Required</th></tr></thead><tbody><tr><td><code>color</code></td><td>string</td><td><code>"primary"</code></td><td>No</td></tr><tr><td><code>size</code></td><td>string</td><td><code>"default"</code></td><td>No</td></tr><tr><td><code>items</code></td><td>unknown[]</td><td><code>[]</code></td><td>No</td></tr><tr><td><code>active</code></td><td>string</td><td><code>""</code></td><td>No</td></tr><tr><td><code>orientation</code></td><td>string</td><td><code>"horizontal"</code></td><td>No</td></tr><tr><td><code>mode</code></td><td>string</td><td><code>"client"</code></td><td>No</td></tr><tr><td><code>param</code></td><td>string</td><td><code>"tab"</code></td><td>No</td></tr><tr><td><code>label</code></td><td>string</td><td><code>"Tabs"</code></td><td>No</td></tr><tr><td><code>class</code></td><td>string</td><td><code>""</code></td><td>No</td></tr></tbody></table></div></section>
|
||||
<section id="api" class="detail-section"><div class="detail-section-heading"><span>Component API</span><h2>Props and configuration</h2><p>All content and behavior shown above is supplied through these props and slots.</p></div><div class="docs-table-wrap"><table class="docs-table"><thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Required</th></tr></thead><tbody><tr><td><code>size</code></td><td>string</td><td><code>"default"</code></td><td>No</td></tr><tr><td><code>color</code></td><td>string</td><td><code>"primary"</code></td><td>No</td></tr><tr><td><code>label</code></td><td>string</td><td><code>"Tabs"</code></td><td>No</td></tr><tr><td><code>items</code></td><td>unknown[]</td><td><code>[]</code></td><td>No</td></tr><tr><td><code>active</code></td><td>string</td><td><code>""</code></td><td>No</td></tr><tr><td><code>orientation</code></td><td>string</td><td><code>"horizontal"</code></td><td>No</td></tr><tr><td><code>class</code></td><td>string</td><td><code>""</code></td><td>No</td></tr></tbody></table></div></section>
|
||||
</main>
|
||||
<aside class="detail-aside">
|
||||
<div class="detail-toc"><strong>On this page</strong><a href="#playground">Playground</a><a href="#tabs-demo-1">Horizontal content tabs</a><a href="#tabs-demo-2">Mirrored into the URL</a><a href="#tabs-demo-3">Compact application tabs</a><a href="#tabs-demo-4">Vertical settings tabs</a><a href="#events">Outputs</a><a href="#api">Props API</a></div>
|
||||
<div class="detail-toc"><strong>On this page</strong><a href="#playground">Playground</a><a href="#tabs-demo-1">Horizontal content tabs</a><a href="#tabs-demo-2">Compact application tabs</a><a href="#tabs-demo-3">Vertical settings tabs</a><a href="#api">Props API</a></div>
|
||||
</aside>
|
||||
</div>
|
||||
<nav class="detail-pagination">
|
||||
|
||||
@@ -17,11 +17,11 @@ page ComponentShowcase {
|
||||
<section class="home-product-grid"><article><span class="icon-[lucide--component] size-7"></span><strong>108 components</strong><p>Accessible primitives for every product surface.</p><a href="/base">Browse components →</a></article><article><span class="icon-[lucide--layout-template] size-7"></span><strong>Ready-made blocks</strong><p>Composable sections assembled from WRNexus UI.</p><a href="/block-library">Explore blocks →</a></article><article><span class="icon-[lucide--panels-top-left] size-7"></span><strong>Page templates</strong><p>Complete responsive pages ready to customize.</p><a href="/templates">View templates →</a></article></section>
|
||||
<section class="showcase-stats">
|
||||
<div class="showcase-stat"><strong>108</strong><span>Unique components</span></div>
|
||||
<div class="showcase-stat"><strong>420</strong><span>Live configurations</span></div>
|
||||
<div class="showcase-stat"><strong>421</strong><span>Live configurations</span></div>
|
||||
<div class="showcase-stat"><strong>0</strong><span>Duplicate implementations</span></div>
|
||||
<div class="showcase-stat"><strong>11</strong><span>Focused categories</span></div>
|
||||
</section>
|
||||
<section class="home-categories"><div class="home-section-heading"><span>Explore the system</span><h2>Everything your product needs</h2></div><div class="home-category-grid"><a class="home-category home-category--1" href="/advanced-forms"><span class="home-category-index">01</span><div><strong>Advanced Forms</strong><p>8 components · 112 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--2" href="/base"><span class="home-category-index">02</span><div><strong>Base</strong><p>27 components · 86 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--3" href="/core"><span class="home-category-index">03</span><div><strong>Core</strong><p>5 components · 13 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--4" href="/data"><span class="home-category-index">04</span><div><strong>Data</strong><p>3 components · 9 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--1" href="/forms"><span class="home-category-index">05</span><div><strong>Forms</strong><p>12 components · 36 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--2" href="/integrations"><span class="home-category-index">06</span><div><strong>Integrations</strong><p>11 components · 33 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--3" href="/layout"><span class="home-category-index">07</span><div><strong>Layout</strong><p>15 components · 45 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--4" href="/marketing"><span class="home-category-index">08</span><div><strong>Marketing</strong><p>10 components · 30 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--1" href="/navigation"><span class="home-category-index">09</span><div><strong>Navigation</strong><p>10 components · 29 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--2" href="/overlays"><span class="home-category-index">010</span><div><strong>Overlays</strong><p>6 components · 18 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--3" href="/tables"><span class="home-category-index">011</span><div><strong>Tables</strong><p>1 components · 9 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a></div></section>
|
||||
<section class="home-categories"><div class="home-section-heading"><span>Explore the system</span><h2>Everything your product needs</h2></div><div class="home-category-grid"><a class="home-category home-category--1" href="/advanced-forms"><span class="home-category-index">01</span><div><strong>Advanced Forms</strong><p>8 components · 112 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--2" href="/base"><span class="home-category-index">02</span><div><strong>Base</strong><p>27 components · 86 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--3" href="/core"><span class="home-category-index">03</span><div><strong>Core</strong><p>5 components · 13 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--4" href="/data"><span class="home-category-index">04</span><div><strong>Data</strong><p>3 components · 9 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--1" href="/forms"><span class="home-category-index">05</span><div><strong>Forms</strong><p>12 components · 36 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--2" href="/integrations"><span class="home-category-index">06</span><div><strong>Integrations</strong><p>11 components · 33 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--3" href="/layout"><span class="home-category-index">07</span><div><strong>Layout</strong><p>15 components · 45 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--4" href="/marketing"><span class="home-category-index">08</span><div><strong>Marketing</strong><p>10 components · 30 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--1" href="/navigation"><span class="home-category-index">09</span><div><strong>Navigation</strong><p>10 components · 30 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--2" href="/overlays"><span class="home-category-index">010</span><div><strong>Overlays</strong><p>6 components · 18 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a><a class="home-category home-category--3" href="/tables"><span class="home-category-index">011</span><div><strong>Tables</strong><p>1 components · 9 live demos</p></div><span class="icon-[lucide--arrow-up-right] size-5" aria-hidden="true"></span></a></div></section>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ page NavigationShowcase {
|
||||
<span class="showcase-eyebrow">Component category</span>
|
||||
<h1 class="showcase-title">Navigation</h1>
|
||||
<p class="showcase-description">10 unique, responsive, theme-aware components. Open a component to inspect multiple live configurations and its complete props API.</p>
|
||||
<div class="category-meta"><span>10 components</span><span>Multiple use cases</span><span>29 live configurations</span></div>
|
||||
<div class="category-meta"><span>10 components</span><span>Multiple use cases</span><span>30 live configurations</span></div>
|
||||
</header>
|
||||
<div class="catalog-grid">
|
||||
<article class="catalog-card" data-interactive-preview="false">
|
||||
@@ -36,21 +36,21 @@ page NavigationShowcase {
|
||||
<article class="catalog-card" data-interactive-preview="false">
|
||||
<div class="catalog-card-preview">
|
||||
<div class="catalog-card-glow" aria-hidden="true"></div>
|
||||
<div class="catalog-card-stage"><MegaMenu size="default" label="Products" icon="icon-[lucide--box]" columns='[{"heading":"Platform","items":[{"label":"Runtime","href":"/runtime","description":"The browser half of the framework."},{"label":"Compiler","href":"/compiler","description":"WRN to JavaScript."}]},{"heading":"Tooling","items":[{"label":"CLI","href":"/cli","description":"Scaffold, build and deploy."},{"label":"Editor","href":"/editor","description":"Language server and syntax."}]}]' defaultOpen="false" class="showcase-instance showcase-instance--1" /></div>
|
||||
<div class="catalog-card-stage"><MegaMenu size="default" label="Mega Menu" items='[{"id":"mega-menu-0-1","key":"mega-menu-0-1","value":"primary","label":"Primary workflow","title":"Primary workflow","description":"A clean default configuration for everyday product interfaces.","text":"A configurable sample message.","href":"#mega-menu-demo","actionHref":"#mega-menu-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":16,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"mega-menu-0-2","key":"mega-menu-0-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A clean default configuration for everyday product interfaces.","text":"Another configurable message.","href":"#mega-menu-demo","actionHref":"#mega-menu-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":32,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' class="showcase-instance showcase-instance--1" /></div>
|
||||
</div>
|
||||
<div class="catalog-card-body">
|
||||
<div><span class="catalog-card-category">Navigation</span><h2>Mega Menu</h2><p>Theme-aware, responsive mega menu component.</p></div>
|
||||
<div class="catalog-card-footer"><span>8 props · 1 slots</span><a href="/components/mega-menu">Explore component <span aria-hidden="true">→</span></a></div>
|
||||
<div class="catalog-card-footer"><span>7 props · 1 slots</span><a href="/components/mega-menu">Explore component <span aria-hidden="true">→</span></a></div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="catalog-card" data-interactive-preview="false">
|
||||
<div class="catalog-card-preview">
|
||||
<div class="catalog-card-glow" aria-hidden="true"></div>
|
||||
<div class="catalog-card-stage"><Nav size="default" items='[{"label":"Home","href":"/","value":"home","icon":"icon-[lucide--house]"},{"label":"Inbox","href":"/inbox","value":"inbox","badge":"9"},{"label":"Reports","href":"/reports","value":"reports"},{"label":"Archive","href":"/archive","value":"archive","disabled":true}]' active="inbox" label="Nav" collapsible="true" toggleLabel="Nav" class="showcase-instance showcase-instance--1" /></div>
|
||||
<div class="catalog-card-stage"><Nav size="default" label="Nav" items='[{"id":"nav-0-1","key":"nav-0-1","value":"primary","label":"Primary workflow","title":"Primary workflow","description":"A clean default configuration for everyday product interfaces.","text":"A configurable sample message.","href":"#nav-demo","actionHref":"#nav-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":16,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"nav-0-2","key":"nav-0-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A clean default configuration for everyday product interfaces.","text":"Another configurable message.","href":"#nav-demo","actionHref":"#nav-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":32,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' class="showcase-instance showcase-instance--1" /></div>
|
||||
</div>
|
||||
<div class="catalog-card-body">
|
||||
<div><span class="catalog-card-category">Navigation</span><h2>Nav</h2><p>Theme-aware, responsive nav component.</p></div>
|
||||
<div class="catalog-card-footer"><span>9 props · 1 slots</span><a href="/components/nav">Explore component <span aria-hidden="true">→</span></a></div>
|
||||
<div class="catalog-card-footer"><span>7 props · 1 slots</span><a href="/components/nav">Explore component <span aria-hidden="true">→</span></a></div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="catalog-card" data-interactive-preview="false">
|
||||
@@ -66,11 +66,11 @@ page NavigationShowcase {
|
||||
<article class="catalog-card" data-interactive-preview="false">
|
||||
<div class="catalog-card-preview">
|
||||
<div class="catalog-card-glow" aria-hidden="true"></div>
|
||||
<div class="catalog-card-stage"><Pagination size="default" page="2" pageSize="10" total="137" variant="compact" siblingCount="3" showSummary="true" label="Pagination" previousLabel="Pagination" nextLabel="Pagination" class="showcase-instance showcase-instance--1" /></div>
|
||||
<div class="catalog-card-stage"><Pagination size="default" label="Pagination" items='[{"id":"pagination-0-1","key":"pagination-0-1","value":"primary","label":"Primary workflow","title":"Primary workflow","description":"A clean default configuration for everyday product interfaces.","text":"A configurable sample message.","href":"#pagination-demo","actionHref":"#pagination-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":16,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"pagination-0-2","key":"pagination-0-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A clean default configuration for everyday product interfaces.","text":"Another configurable message.","href":"#pagination-demo","actionHref":"#pagination-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":32,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' class="showcase-instance showcase-instance--1" /></div>
|
||||
</div>
|
||||
<div class="catalog-card-body">
|
||||
<div><span class="catalog-card-category">Navigation</span><h2>Pagination</h2><p>Theme-aware, responsive pagination component.</p></div>
|
||||
<div class="catalog-card-footer"><span>12 props · 1 slots</span><a href="/components/pagination">Explore component <span aria-hidden="true">→</span></a></div>
|
||||
<div class="catalog-card-footer"><span>7 props · 1 slots</span><a href="/components/pagination">Explore component <span aria-hidden="true">→</span></a></div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="catalog-card" data-interactive-preview="false">
|
||||
@@ -86,31 +86,31 @@ page NavigationShowcase {
|
||||
<article class="catalog-card" data-interactive-preview="false">
|
||||
<div class="catalog-card-preview">
|
||||
<div class="catalog-card-glow" aria-hidden="true"></div>
|
||||
<div class="catalog-card-stage"><Sidebar size="default" label="Workspace" items='[{"label":"Dashboard","href":"/","value":"dash","icon":"icon-[lucide--gauge]"},{"heading":"Projects","items":[{"label":"Active","href":"/active","value":"active","badge":"4"},{"label":"Archive","value":"archive","items":[{"label":"2025","href":"/a/2025","value":"a2025"},{"label":"2024","href":"/a/2024","value":"a2024"}]}]},{"heading":"Account","items":[{"label":"Settings","href":"/settings","value":"settings","icon":"icon-[lucide--settings]"}]}]' active="active" mobileLabel="Sidebar" drawerTitle="Sidebar example" class="showcase-instance showcase-instance--1" /></div>
|
||||
<div class="catalog-card-stage"><Sidebar size="default" label="Sidebar" items='[{"id":"sidebar-0-1","key":"sidebar-0-1","value":"primary","label":"Primary workflow","title":"Primary workflow","description":"A clean default configuration for everyday product interfaces.","text":"A configurable sample message.","href":"#sidebar-demo","actionHref":"#sidebar-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":16,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"sidebar-0-2","key":"sidebar-0-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A clean default configuration for everyday product interfaces.","text":"Another configurable message.","href":"#sidebar-demo","actionHref":"#sidebar-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":32,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' mobileLabel="Sidebar" class="showcase-instance showcase-instance--1" /></div>
|
||||
</div>
|
||||
<div class="catalog-card-body">
|
||||
<div><span class="catalog-card-category">Navigation</span><h2>Sidebar</h2><p>Theme-aware, responsive sidebar component.</p></div>
|
||||
<div class="catalog-card-footer"><span>8 props · 2 slots</span><a href="/components/sidebar">Explore component <span aria-hidden="true">→</span></a></div>
|
||||
<div class="catalog-card-footer"><span>8 props · 1 slots</span><a href="/components/sidebar">Explore component <span aria-hidden="true">→</span></a></div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="catalog-card" data-interactive-preview="false">
|
||||
<div class="catalog-card-preview">
|
||||
<div class="catalog-card-glow" aria-hidden="true"></div>
|
||||
<div class="catalog-card-stage"><Stepper size="default" steps='[{"label":"Account","description":"Your details"},{"label":"Billing","description":"Payment method"},{"label":"Confirm","description":"Review and submit"}]' active="1" clickable="false" label="Stepper" class="showcase-instance showcase-instance--1" /></div>
|
||||
<div class="catalog-card-stage"><Stepper size="default" label="Stepper" items='[{"id":"stepper-0-1","key":"stepper-0-1","value":"primary","label":"Primary workflow","title":"Primary workflow","description":"A clean default configuration for everyday product interfaces.","text":"A configurable sample message.","href":"#stepper-demo","actionHref":"#stepper-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":true,"selected":true,"checked":true,"disabled":false,"outgoing":false,"open":true,"number":1,"count":16,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 1","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]},{"id":"stepper-0-2","key":"stepper-0-2","value":"secondary","label":"Additional option","title":"Supporting example","description":"A clean default configuration for everyday product interfaces.","text":"Another configurable message.","href":"#stepper-demo","actionHref":"#stepper-demo","actionLabel":"View details","icon":"icon-[lucide--sparkles]","iconClass":"icon-[lucide--sparkles]","variant":"primary","status":"Active","time":"09:30","current":false,"selected":false,"checked":false,"disabled":false,"outgoing":true,"open":true,"number":2,"count":32,"percentage":72,"color":"#7c3aed","target":"_self","ariaLabel":"Open primary workflow 2","items":[{"label":"Nested option A","value":"nested-a"},{"label":"Nested option B","value":"nested-b"}],"links":[{"label":"Documentation","href":"#documentation"},{"label":"API reference","href":"#api-reference"}],"values":["Included","Standard"]}]' class="showcase-instance showcase-instance--1" /></div>
|
||||
</div>
|
||||
<div class="catalog-card-body">
|
||||
<div><span class="catalog-card-category">Navigation</span><h2>Stepper</h2><p>Theme-aware, responsive stepper component.</p></div>
|
||||
<div class="catalog-card-footer"><span>8 props · 2 slots</span><a href="/components/stepper">Explore component <span aria-hidden="true">→</span></a></div>
|
||||
<div class="catalog-card-footer"><span>7 props · 1 slots</span><a href="/components/stepper">Explore component <span aria-hidden="true">→</span></a></div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="catalog-card" data-interactive-preview="false">
|
||||
<div class="catalog-card-preview">
|
||||
<div class="catalog-card-glow" aria-hidden="true"></div>
|
||||
<div class="catalog-card-stage"><Tabs size="default" items='[{"label":"Overview","value":"overview","content":"Overview content"},{"label":"Requirements","value":"requirements","content":"Requirements content"},{"label":"Process","value":"process","content":"Process content"}]' active="overview" orientation="horizontal" label="Service information" class="showcase-instance showcase-instance--1" /></div>
|
||||
<div class="catalog-card-stage"><Tabs size="default" label="Service information" items='[{"label":"Overview","value":"overview","content":"Overview content"},{"label":"Requirements","value":"requirements","content":"Requirements content"},{"label":"Process","value":"process","content":"Process content"}]' active="overview" orientation="horizontal" class="showcase-instance showcase-instance--1" /></div>
|
||||
</div>
|
||||
<div class="catalog-card-body">
|
||||
<div><span class="catalog-card-category">Navigation</span><h2>Tabs</h2><p>Switch between related responsive content panels with horizontal or vertical orientation and selection events.</p></div>
|
||||
<div class="catalog-card-footer"><span>9 props · 2 slots</span><a href="/components/tabs">Explore component <span aria-hidden="true">→</span></a></div>
|
||||
<div class="catalog-card-footer"><span>7 props · 1 slots</span><a href="/components/tabs">Explore component <span aria-hidden="true">→</span></a></div>
|
||||
</div>
|
||||
</article></div>
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ export interface Routes {
|
||||
"/components/strong-password": Record<string, never>;
|
||||
"/components/styled-icon": Record<string, never>;
|
||||
"/components/switch": Record<string, never>;
|
||||
"/components/table": Record<string, never>;
|
||||
"/components/tabs": Record<string, never>;
|
||||
"/components/text-link": Record<string, never>;
|
||||
"/components/textarea": Record<string, never>;
|
||||
@@ -245,6 +246,7 @@ export interface RouteNames {
|
||||
"components.strong.password": "/components/strong-password";
|
||||
"components.styled.icon": "/components/styled-icon";
|
||||
"components.switch": "/components/switch";
|
||||
"components.table": "/components/table";
|
||||
"components.tabs": "/components/tabs";
|
||||
"components.text.link": "/components/text-link";
|
||||
"components.textarea": "/components/textarea";
|
||||
@@ -457,6 +459,7 @@ export function route<N extends RouteName>(
|
||||
"components.strong.password": "/components/strong-password",
|
||||
"components.styled.icon": "/components/styled-icon",
|
||||
"components.switch": "/components/switch",
|
||||
"components.table": "/components/table",
|
||||
"components.tabs": "/components/tabs",
|
||||
"components.text.link": "/components/text-link",
|
||||
"components.textarea": "/components/textarea",
|
||||
|
||||
@@ -253,236 +253,6 @@ const DATATABLE_ROWS =
|
||||
'[{"id": 1, "name": "Northwind", "plan": "Scale", "owner": "A. Okafor", "seats": 6, "status": "Active", "statusHtml": "<span class=\\"showcase-pill showcase-pill--success\\">Active</span>"}, {"id": 2, "name": "Acme Industrial", "plan": "Team", "owner": "R. Silva", "seats": 13, "status": "Trial", "statusHtml": "<span class=\\"showcase-pill showcase-pill--info\\">Trial</span>"}, {"id": 3, "name": "Globex", "plan": "Enterprise", "owner": "M. Chen", "seats": 20, "status": "Past due", "statusHtml": "<span class=\\"showcase-pill showcase-pill--danger\\">Past due</span>"}, {"id": 4, "name": "Initech", "plan": "Starter", "owner": "J. Dubois", "seats": 27, "status": "Active", "statusHtml": "<span class=\\"showcase-pill showcase-pill--success\\">Active</span>"}, {"id": 5, "name": "Umbrella", "plan": "Scale", "owner": "P. Novak", "seats": 34, "status": "Trial", "statusHtml": "<span class=\\"showcase-pill showcase-pill--info\\">Trial</span>"}, {"id": 6, "name": "Stark Labs", "plan": "Team", "owner": "A. Okafor", "seats": 41, "status": "Past due", "statusHtml": "<span class=\\"showcase-pill showcase-pill--danger\\">Past due</span>"}, {"id": 7, "name": "Wayne Foods", "plan": "Enterprise", "owner": "R. Silva", "seats": 48, "status": "Active", "statusHtml": "<span class=\\"showcase-pill showcase-pill--success\\">Active</span>"}, {"id": 8, "name": "Soylent", "plan": "Starter", "owner": "M. Chen", "seats": 55, "status": "Trial", "statusHtml": "<span class=\\"showcase-pill showcase-pill--info\\">Trial</span>"}, {"id": 9, "name": "Hooli", "plan": "Scale", "owner": "J. Dubois", "seats": 62, "status": "Past due", "statusHtml": "<span class=\\"showcase-pill showcase-pill--danger\\">Past due</span>"}, {"id": 10, "name": "Vehement", "plan": "Team", "owner": "P. Novak", "seats": 69, "status": "Active", "statusHtml": "<span class=\\"showcase-pill showcase-pill--success\\">Active</span>"}, {"id": 11, "name": "Massive Dynamic", "plan": "Enterprise", "owner": "A. Okafor", "seats": 76, "status": "Trial", "statusHtml": "<span class=\\"showcase-pill showcase-pill--info\\">Trial</span>"}, {"id": 12, "name": "Cyberdyne", "plan": "Starter", "owner": "R. Silva", "seats": 83, "status": "Past due", "statusHtml": "<span class=\\"showcase-pill showcase-pill--danger\\">Past due</span>"}, {"id": 13, "name": "Tyrell", "plan": "Scale", "owner": "M. Chen", "seats": 90, "status": "Active", "statusHtml": "<span class=\\"showcase-pill showcase-pill--success\\">Active</span>"}, {"id": 14, "name": "Aperture", "plan": "Team", "owner": "J. Dubois", "seats": 97, "status": "Trial", "statusHtml": "<span class=\\"showcase-pill showcase-pill--info\\">Trial</span>"}, {"id": 15, "name": "Black Mesa", "plan": "Enterprise", "owner": "P. Novak", "seats": 104, "status": "Past due", "statusHtml": "<span class=\\"showcase-pill showcase-pill--danger\\">Past due</span>"}]';
|
||||
|
||||
export const componentProfiles = {
|
||||
MegaMenu: {
|
||||
demos: [
|
||||
standard(
|
||||
"Grouped columns",
|
||||
"One level deep by design: a mega menu shows breadth flat so everything is one click away. Nesting inside the panel would bury content behind hover-within-hover. Use Nav when you want cascading submenus.",
|
||||
{
|
||||
label: "Products",
|
||||
icon: "icon-[lucide--box]",
|
||||
columns: [
|
||||
{
|
||||
heading: "Platform",
|
||||
items: [
|
||||
{
|
||||
label: "Runtime",
|
||||
href: "/runtime",
|
||||
description: "The browser half of the framework.",
|
||||
},
|
||||
{ label: "Compiler", href: "/compiler", description: "WRN to JavaScript." },
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Tooling",
|
||||
items: [
|
||||
{ label: "CLI", href: "/cli", description: "Scaffold, build and deploy." },
|
||||
{ label: "Editor", href: "/editor", description: "Language server and syntax." },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
advanced(
|
||||
"With a footer note",
|
||||
"The panel is anchored, so the runtime clamp pulls it back inside the viewport instead of letting it hang off a wide layout. On a phone it stops floating and joins the flow.",
|
||||
{
|
||||
label: "Solutions",
|
||||
columns: [
|
||||
{
|
||||
heading: "By team",
|
||||
items: [
|
||||
{ label: "Engineering", href: "/eng", icon: "icon-[lucide--code]" },
|
||||
{ label: "Design", href: "/design", icon: "icon-[lucide--palette]" },
|
||||
{ label: "Support", href: "/support", icon: "icon-[lucide--life-buoy]" },
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "By size",
|
||||
items: [
|
||||
{ label: "Startup", href: "/startup" },
|
||||
{ label: "Enterprise", href: "/enterprise" },
|
||||
],
|
||||
},
|
||||
],
|
||||
footer: "Not sure where to start? Talk to us.",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
Sidebar: {
|
||||
demos: [
|
||||
standard(
|
||||
"Groups and nested levels",
|
||||
"An entry is a single link, a labelled group, or a branch nested up to three levels. Arrow keys move down the rail.",
|
||||
{
|
||||
label: "Workspace",
|
||||
items: [
|
||||
{ label: "Dashboard", href: "/", value: "dash", icon: "icon-[lucide--gauge]" },
|
||||
{
|
||||
heading: "Projects",
|
||||
items: [
|
||||
{ label: "Active", href: "/active", value: "active", badge: "4" },
|
||||
{
|
||||
label: "Archive",
|
||||
value: "archive",
|
||||
items: [
|
||||
{ label: "2025", href: "/a/2025", value: "a2025" },
|
||||
{ label: "2024", href: "/a/2024", value: "a2024" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Account",
|
||||
items: [
|
||||
{
|
||||
label: "Settings",
|
||||
href: "/settings",
|
||||
value: "settings",
|
||||
icon: "icon-[lucide--settings]",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
active: "active",
|
||||
},
|
||||
),
|
||||
advanced(
|
||||
"Drawer on small screens",
|
||||
"Below the tablet breakpoint the rail is replaced by a launcher that opens a Drawer. Composing Drawer rather than reimplementing it means the focus trap and the body scroll lock come from one place.",
|
||||
{
|
||||
label: "Operations",
|
||||
mobileLabel: "Open navigation",
|
||||
drawerTitle: "Operations",
|
||||
items: [
|
||||
{ label: "Queue", href: "/queue", value: "queue", icon: "icon-[lucide--inbox]" },
|
||||
{
|
||||
label: "Reports",
|
||||
href: "/reports",
|
||||
value: "reports",
|
||||
icon: "icon-[lucide--chart-no-axes-column]",
|
||||
},
|
||||
],
|
||||
active: "queue",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
Nav: {
|
||||
demos: [
|
||||
standard(
|
||||
"Horizontal links",
|
||||
"A flat link bar. The active item is marked with aria-current, and the arrow keys move between items.",
|
||||
{
|
||||
items: [
|
||||
{ label: "Home", href: "/", value: "home", icon: "icon-[lucide--house]" },
|
||||
{ label: "Inbox", href: "/inbox", value: "inbox", badge: "9" },
|
||||
{ label: "Reports", href: "/reports", value: "reports" },
|
||||
{ label: "Archive", href: "/archive", value: "archive", disabled: true },
|
||||
],
|
||||
active: "inbox",
|
||||
},
|
||||
),
|
||||
advanced(
|
||||
"Nested submenus",
|
||||
"An item carrying its own items array opens a submenu on hover or focus, to a maximum of three levels. On a phone the submenus stack inline instead of floating, because a hover-opened overlay is unreachable on touch.",
|
||||
{
|
||||
items: [
|
||||
{ label: "Home", href: "/", value: "home" },
|
||||
{
|
||||
label: "Products",
|
||||
value: "products",
|
||||
items: [
|
||||
{ label: "Overview", href: "/p", value: "p-overview" },
|
||||
{
|
||||
label: "Platform",
|
||||
value: "p-platform",
|
||||
items: [
|
||||
{ label: "Runtime", href: "/p/runtime", value: "runtime" },
|
||||
{ label: "Compiler", href: "/p/compiler", value: "compiler" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
active: "p-overview",
|
||||
},
|
||||
),
|
||||
standard("Vertical rail", "Vertical orientation switches the arrow keys to up and down.", {
|
||||
items: [
|
||||
{ label: "Dashboard", href: "/", value: "dash", icon: "icon-[lucide--gauge]" },
|
||||
{ label: "Team", href: "/team", value: "team", icon: "icon-[lucide--users]" },
|
||||
{
|
||||
label: "Settings",
|
||||
href: "/settings",
|
||||
value: "settings",
|
||||
icon: "icon-[lucide--settings]",
|
||||
},
|
||||
],
|
||||
active: "team",
|
||||
orientation: "vertical",
|
||||
collapsible: false,
|
||||
}),
|
||||
],
|
||||
},
|
||||
Stepper: {
|
||||
demos: [
|
||||
standard(
|
||||
"Horizontal progress",
|
||||
"Steps before the active one read as complete, the active one is highlighted, and the rest are muted.",
|
||||
{
|
||||
steps: [
|
||||
{ label: "Account", description: "Your details" },
|
||||
{ label: "Billing", description: "Payment method" },
|
||||
{ label: "Confirm", description: "Review and submit" },
|
||||
],
|
||||
active: 1,
|
||||
},
|
||||
),
|
||||
standard(
|
||||
"Vertical with icons",
|
||||
"Vertical orientation suits a sidebar or a narrow column. Any step may carry an iconify class instead of its number.",
|
||||
{
|
||||
steps: [
|
||||
{ label: "Cloned", icon: "icon-[lucide--git-branch]" },
|
||||
{ label: "Built", icon: "icon-[lucide--hammer]" },
|
||||
{ label: "Deployed", icon: "icon-[lucide--rocket]" },
|
||||
],
|
||||
active: 2,
|
||||
orientation: "vertical",
|
||||
},
|
||||
),
|
||||
advanced(
|
||||
"Clickable steps",
|
||||
"With clickable the steps emit a change output and take arrow-key roving focus. Without it the stepper is read-only and stays out of the tab order.",
|
||||
{
|
||||
steps: [{ label: "One" }, { label: "Two" }, { label: "Three" }],
|
||||
active: 0,
|
||||
clickable: true,
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
Pagination: {
|
||||
demos: [
|
||||
standard(
|
||||
"Compact arrows",
|
||||
"The default: previous and next with a page counter, and a summary of the range in view.",
|
||||
{ page: 2, pageSize: 10, total: 137, variant: "compact" },
|
||||
),
|
||||
standard(
|
||||
"Numbered pages",
|
||||
"Page numbers windowed around the current page with ellipsis gaps, so a large set never renders hundreds of buttons.",
|
||||
{ page: 5, pageSize: 10, total: 200, variant: "numbered", siblingCount: 1 },
|
||||
),
|
||||
advanced(
|
||||
"Wider window",
|
||||
"siblingCount widens how many pages sit either side of the current one.",
|
||||
{ page: 8, pageSize: 25, total: 900, variant: "numbered", siblingCount: 2 },
|
||||
),
|
||||
],
|
||||
},
|
||||
DataTable: {
|
||||
demos: [
|
||||
standard(
|
||||
@@ -2480,21 +2250,6 @@ export const componentProfiles = {
|
||||
orientation: "horizontal",
|
||||
},
|
||||
),
|
||||
advanced(
|
||||
"Mirrored into the URL",
|
||||
"With mode=url the selection is written to a query parameter using pushState, so the panel swaps without a page load, the tab survives a reload, and the back button steps through the tabs you visited.",
|
||||
{
|
||||
label: "Account settings",
|
||||
items: [
|
||||
{ label: "Account", value: "account", description: "Profile and credentials." },
|
||||
{ label: "Billing", value: "billing", description: "Invoices and payment method." },
|
||||
{ label: "Team", value: "team", description: "Members and their roles." },
|
||||
],
|
||||
active: "account",
|
||||
mode: "url",
|
||||
param: "tab",
|
||||
},
|
||||
),
|
||||
compact(
|
||||
"Compact application tabs",
|
||||
"Use smaller tabs in dashboards, panels, and dense product interfaces.",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"generatedFrom": "packages/ui/component-reference.json",
|
||||
"componentCount": 108,
|
||||
"categoryCount": 11,
|
||||
"totalDemoCount": 420,
|
||||
"totalDemoCount": 421,
|
||||
"components": [
|
||||
{
|
||||
"name": "Accordion",
|
||||
@@ -786,11 +786,11 @@
|
||||
"slug": "mega-menu",
|
||||
"category": "navigation",
|
||||
"purpose": "Theme-aware, responsive mega menu component.",
|
||||
"demoCount": 2,
|
||||
"propCount": 8,
|
||||
"demoCount": 3,
|
||||
"propCount": 7,
|
||||
"slots": ["default"],
|
||||
"events": ["open", "close", "select"],
|
||||
"profiled": true
|
||||
"profiled": false
|
||||
},
|
||||
{
|
||||
"name": "MetricCard",
|
||||
@@ -835,10 +835,10 @@
|
||||
"category": "navigation",
|
||||
"purpose": "Theme-aware, responsive nav component.",
|
||||
"demoCount": 3,
|
||||
"propCount": 9,
|
||||
"propCount": 7,
|
||||
"slots": ["default"],
|
||||
"events": ["select"],
|
||||
"profiled": true
|
||||
"events": ["select", "change"],
|
||||
"profiled": false
|
||||
},
|
||||
{
|
||||
"name": "Navbar",
|
||||
@@ -871,10 +871,10 @@
|
||||
"category": "navigation",
|
||||
"purpose": "Theme-aware, responsive pagination component.",
|
||||
"demoCount": 3,
|
||||
"propCount": 12,
|
||||
"propCount": 7,
|
||||
"slots": ["default"],
|
||||
"events": ["change", "previous", "next"],
|
||||
"profiled": true
|
||||
"profiled": false
|
||||
},
|
||||
{
|
||||
"name": "PinInput",
|
||||
@@ -1050,11 +1050,11 @@
|
||||
"slug": "sidebar",
|
||||
"category": "navigation",
|
||||
"purpose": "Theme-aware, responsive sidebar component.",
|
||||
"demoCount": 2,
|
||||
"demoCount": 3,
|
||||
"propCount": 8,
|
||||
"slots": ["default", "drawer"],
|
||||
"slots": ["default"],
|
||||
"events": ["toggle", "open", "close", "select"],
|
||||
"profiled": true
|
||||
"profiled": false
|
||||
},
|
||||
{
|
||||
"name": "Skeleton",
|
||||
@@ -1111,10 +1111,10 @@
|
||||
"category": "navigation",
|
||||
"purpose": "Theme-aware, responsive stepper component.",
|
||||
"demoCount": 3,
|
||||
"propCount": 8,
|
||||
"slots": ["step-{index}", "default"],
|
||||
"events": ["change"],
|
||||
"profiled": true
|
||||
"propCount": 7,
|
||||
"slots": ["default"],
|
||||
"events": ["change", "previous", "next", "complete"],
|
||||
"profiled": false
|
||||
},
|
||||
{
|
||||
"name": "StrongPassword",
|
||||
@@ -1158,10 +1158,10 @@
|
||||
"slug": "tabs",
|
||||
"category": "navigation",
|
||||
"purpose": "Switch between related responsive content panels with horizontal or vertical orientation and selection events.",
|
||||
"demoCount": 4,
|
||||
"propCount": 9,
|
||||
"slots": ["panel-{valueOf(item, index)}", "default"],
|
||||
"events": ["change", "select"],
|
||||
"demoCount": 3,
|
||||
"propCount": 7,
|
||||
"slots": ["default"],
|
||||
"events": [],
|
||||
"profiled": true
|
||||
},
|
||||
{
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wrnexus",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "An SSR-first full-stack web framework with server-rendered reactive components. Bun-first, Node-friendly.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ai",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/auth",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"description": "Complete authentication, account security, MFA, passkeys, recovery, devices, risk, and audit system for WRNexusJS.",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/authz",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/benchmark",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Deterministic benchmark runner and performance regression budgets for WRNexusJS.",
|
||||
"main": "src/index.ts",
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/cache",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Tag-aware memory and response caching with stale-while-revalidate for WRNexusJS.",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/captcha",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"description": "First-class CAPTCHA challenges, providers, verification guards, page gates, and WRNexusJS UI.",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/cli",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -2013,22 +2013,6 @@ const MIGRATIONS: Migration[] = [
|
||||
// WRNexus Language Support VS Code extension.
|
||||
},
|
||||
},
|
||||
{
|
||||
version: "0.8.5",
|
||||
id: "0.8.5-datatable-toaster-overlay-dialogs",
|
||||
description:
|
||||
"Adds the DataTable and Toaster components, removes the Table scaffold, and gives modal dialogs focus management, a Tab trap and a scroll lock.",
|
||||
apply() {
|
||||
// Applications using <Table> must move to <DataTable>. The two are not
|
||||
// prop-compatible -- Table took `columns`/`rows` and rendered them as
|
||||
// plain text, while DataTable owns sorting, filtering, paging and
|
||||
// selection -- so this is a source change no codemod can make safely.
|
||||
//
|
||||
// The `@wrnexus/ui` main entry no longer re-exports the filesystem
|
||||
// helpers; import them from `@wrnexus/ui/registry` instead. Everything
|
||||
// else arrives through the dependency update.
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/** Release tooling uses this to require an explicit migration entry per version. */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/compiler",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/content",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Typed Markdown content collections, loaders, indexes, feeds, and preview workflows for WRNexusJS.",
|
||||
"main": "./src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/core",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/csr",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -2927,18 +2927,11 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
var dialogRestoreFocus = null;
|
||||
var dialogScrollLock = null;
|
||||
|
||||
/*
|
||||
* Open/closed is expressed by the data-show marker these components already
|
||||
* emit, not by measured size. Measuring looks more thorough but made the
|
||||
* trap and the scroll lock impossible to cover: the test DOM reports every
|
||||
* element as zero-sized, so a dialog never counted as open and none of this
|
||||
* behaviour ran under test.
|
||||
*/
|
||||
function isDialogVisible(dialog) {
|
||||
if (!dialog || !dialog.isConnected) return false;
|
||||
if (dialog.hasAttribute("hidden")) return false;
|
||||
if (!dialog || !dialog.getBoundingClientRect) return false;
|
||||
if (dialog.closest('[data-show="false"]')) return false;
|
||||
return true;
|
||||
var rect = dialog.getBoundingClientRect();
|
||||
return rect.width > 0 && rect.height > 0;
|
||||
}
|
||||
|
||||
function focusableWithin(dialog) {
|
||||
@@ -2946,10 +2939,8 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
var candidates = dialog.querySelectorAll(FOCUSABLE_SELECTOR);
|
||||
for (var index = 0; index < candidates.length; index += 1) {
|
||||
var candidate = candidates[index];
|
||||
// Same rule as the roving items: markers, not measurement.
|
||||
if (candidate.hasAttribute("hidden")) continue;
|
||||
if (candidate.closest('[data-show="false"]')) continue;
|
||||
found.push(candidate);
|
||||
var rect = candidate.getBoundingClientRect();
|
||||
if (rect.width > 0 || rect.height > 0) found.push(candidate);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
@@ -3056,143 +3047,6 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
syncDialogs();
|
||||
}
|
||||
|
||||
/*
|
||||
* Roving arrow-key focus, the ARIA pattern shared by tabs, menus, sidebars
|
||||
* and steppers. A container marked data-wrn-roving owns its
|
||||
* [data-wrn-roving-item] descendants: exactly one carries tabindex="0" so
|
||||
* Tab reaches the group once, and the arrow keys move within it.
|
||||
*
|
||||
* This lives here rather than in each component because it is the same code
|
||||
* five times over, and because focus bookkeeping cannot be held in component
|
||||
* state -- a client function writing after it returns has that write dropped.
|
||||
*/
|
||||
var ROVING_SELECTOR = "[data-wrn-roving]";
|
||||
var ROVING_ITEM_SELECTOR = "[data-wrn-roving-item]";
|
||||
|
||||
/*
|
||||
* Templates stringify these, so data-wrn-roving="" and
|
||||
* data-wrn-roving-item="false" mean "not this time". A bare [attr] selector
|
||||
* matches either, so the value must be checked.
|
||||
*/
|
||||
// A bare data-wrn-roving-item means yes; only an explicit "false" opts out.
|
||||
function rovingItemOff(value) {
|
||||
return value === null || value === "false";
|
||||
}
|
||||
|
||||
/*
|
||||
* The container is stricter: it must name an axis. An empty value is what a
|
||||
* template emits for {cond ? "horizontal" : ""}, so empty means off rather
|
||||
* than defaulting to horizontal.
|
||||
*/
|
||||
function rovingOrientation(container) {
|
||||
var value = container.getAttribute("data-wrn-roving");
|
||||
if (value === null || value === "" || value === "false") return "";
|
||||
return value;
|
||||
}
|
||||
|
||||
function rovingItems(container) {
|
||||
var found = [];
|
||||
var candidates = container.querySelectorAll(ROVING_ITEM_SELECTOR);
|
||||
for (var index = 0; index < candidates.length; index += 1) {
|
||||
var candidate = candidates[index];
|
||||
if (rovingItemOff(candidate.getAttribute("data-wrn-roving-item"))) continue;
|
||||
// A nested group owns its own items; do not steal them.
|
||||
if (candidate.closest(ROVING_SELECTOR) !== container) continue;
|
||||
if (candidate.hasAttribute("disabled")) continue;
|
||||
if (candidate.getAttribute("aria-disabled") === "true") continue;
|
||||
// Markers, not measurement: the test DOM reports every element as
|
||||
// zero-sized, which is what left the dialog trap uncovered.
|
||||
if (candidate.hasAttribute("hidden")) continue;
|
||||
if (candidate.closest('[data-show="false"]')) continue;
|
||||
found.push(candidate);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
function rovingActiveIndex(items) {
|
||||
for (var index = 0; index < items.length; index += 1) {
|
||||
var item = items[index];
|
||||
if (item.getAttribute("aria-selected") === "true") return index;
|
||||
var current = item.getAttribute("aria-current");
|
||||
if (current === "page" || current === "step" || current === "true") return index;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function applyRovingTabindex(items, activeIndex) {
|
||||
for (var index = 0; index < items.length; index += 1) {
|
||||
items[index].setAttribute("tabindex", index === activeIndex ? "0" : "-1");
|
||||
}
|
||||
}
|
||||
|
||||
function syncRovingGroup(container) {
|
||||
if (!rovingOrientation(container)) return;
|
||||
var items = rovingItems(container);
|
||||
if (!items.length) return;
|
||||
applyRovingTabindex(items, rovingActiveIndex(items));
|
||||
}
|
||||
|
||||
function syncRovingGroups() {
|
||||
var groups = document.querySelectorAll(ROVING_SELECTOR);
|
||||
for (var index = 0; index < groups.length; index += 1) syncRovingGroup(groups[index]);
|
||||
}
|
||||
|
||||
function handleRovingKeydown(event) {
|
||||
var target = event.target;
|
||||
if (!target || !target.closest) return;
|
||||
var item = target.closest(ROVING_ITEM_SELECTOR);
|
||||
if (!item) return;
|
||||
var container = item.closest(ROVING_SELECTOR);
|
||||
if (!container) return;
|
||||
|
||||
var items = rovingItems(container);
|
||||
var index = items.indexOf(item);
|
||||
if (index === -1) return;
|
||||
|
||||
var orientation = rovingOrientation(container);
|
||||
if (!orientation) return;
|
||||
var horizontal = orientation === "horizontal" || orientation === "both";
|
||||
var vertical = orientation === "vertical" || orientation === "both";
|
||||
var key = event.key;
|
||||
var next = -1;
|
||||
|
||||
if ((horizontal && key === "ArrowRight") || (vertical && key === "ArrowDown")) {
|
||||
next = (index + 1) % items.length;
|
||||
} else if ((horizontal && key === "ArrowLeft") || (vertical && key === "ArrowUp")) {
|
||||
next = (index - 1 + items.length) % items.length;
|
||||
} else if (key === "Home") {
|
||||
next = 0;
|
||||
} else if (key === "End") {
|
||||
next = items.length - 1;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
applyRovingTabindex(items, next);
|
||||
if (items[next].focus) items[next].focus();
|
||||
}
|
||||
|
||||
function setupRovingFocus() {
|
||||
if (window.__wrnexusRovingBound) return;
|
||||
window.__wrnexusRovingBound = true;
|
||||
|
||||
document.addEventListener("keydown", handleRovingKeydown, true);
|
||||
|
||||
if (typeof MutationObserver === "function") {
|
||||
new MutationObserver(function () {
|
||||
window.setTimeout(syncRovingGroups, 0);
|
||||
}).observe(document.documentElement, {
|
||||
subtree: true,
|
||||
childList: true,
|
||||
attributes: true,
|
||||
attributeFilter: ["aria-selected", "aria-current", "disabled", "aria-disabled", "hidden"],
|
||||
});
|
||||
}
|
||||
|
||||
syncRovingGroups();
|
||||
}
|
||||
|
||||
function hydrateScopes(root) {
|
||||
var host = root || document;
|
||||
|
||||
@@ -5410,7 +5264,6 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
window.__wrnexusHydrateAsyncBoundaries = hydrateAsyncBoundaries;
|
||||
setupAnchoredOverlays();
|
||||
setupModalDialogs();
|
||||
setupRovingFocus();
|
||||
window.__wrnexusRepositionAnchored = repositionAnchored;
|
||||
window.__wrnexusHydrateScopes = hydrateScopes;
|
||||
window.__wrnexusInvalidateClientModule = function (url) { clientModuleCache.delete(url); };
|
||||
|
||||
@@ -894,161 +894,3 @@ test("comments are ignored inside interpreted statements", () => {
|
||||
(win.document.querySelector("button") as unknown as HTMLElement).click();
|
||||
expect(win.document.querySelector("#out")?.textContent).toBe("2");
|
||||
});
|
||||
|
||||
/*
|
||||
* happy-dom builds its own KeyboardEvent, which is structurally distinct from
|
||||
* the DOM lib Event that dispatchEvent is typed against. Same cast the window
|
||||
* dispatches above use, kept in one place.
|
||||
*/
|
||||
function keydown(win: Window, key: string): Event {
|
||||
const ctor = (win as unknown as { KeyboardEvent: new (type: string, init: unknown) => unknown })
|
||||
.KeyboardEvent;
|
||||
return new ctor("keydown", { key, bubbles: true }) as unknown as Event;
|
||||
}
|
||||
|
||||
test("roving focus moves with arrow keys and wraps", () => {
|
||||
const win = mount(
|
||||
`<div data-wrn-roving="horizontal">
|
||||
<button data-wrn-roving-item id="a">A</button>
|
||||
<button data-wrn-roving-item id="b">B</button>
|
||||
<button data-wrn-roving-item id="c">C</button>
|
||||
</div>`,
|
||||
);
|
||||
const doc = win.document;
|
||||
const a = doc.querySelector("#a") as unknown as HTMLElement;
|
||||
const c = doc.querySelector("#c") as unknown as HTMLElement;
|
||||
|
||||
expect(a.getAttribute("tabindex")).toBe("0");
|
||||
expect(doc.querySelector("#b")!.getAttribute("tabindex")).toBe("-1");
|
||||
|
||||
a.focus();
|
||||
a.dispatchEvent(keydown(win, "ArrowRight"));
|
||||
expect(doc.activeElement!.id).toBe("b");
|
||||
expect(doc.querySelector("#b")!.getAttribute("tabindex")).toBe("0");
|
||||
expect(a.getAttribute("tabindex")).toBe("-1");
|
||||
|
||||
(doc.querySelector("#b") as unknown as HTMLElement).dispatchEvent(keydown(win, "ArrowLeft"));
|
||||
expect(doc.activeElement!.id).toBe("a");
|
||||
|
||||
a.dispatchEvent(keydown(win, "ArrowLeft"));
|
||||
expect(doc.activeElement!.id).toBe("c");
|
||||
|
||||
c.dispatchEvent(keydown(win, "ArrowRight"));
|
||||
expect(doc.activeElement!.id).toBe("a");
|
||||
});
|
||||
|
||||
test("roving focus honours Home and End and skips disabled items", () => {
|
||||
const win = mount(
|
||||
`<div data-wrn-roving="vertical">
|
||||
<button data-wrn-roving-item id="a">A</button>
|
||||
<button data-wrn-roving-item id="b" disabled>B</button>
|
||||
<button data-wrn-roving-item id="c">C</button>
|
||||
</div>`,
|
||||
);
|
||||
const doc = win.document;
|
||||
const a = doc.querySelector("#a") as unknown as HTMLElement;
|
||||
a.focus();
|
||||
|
||||
a.dispatchEvent(keydown(win, "ArrowDown"));
|
||||
expect(doc.activeElement!.id).toBe("c");
|
||||
|
||||
(doc.querySelector("#c") as unknown as HTMLElement).dispatchEvent(keydown(win, "Home"));
|
||||
expect(doc.activeElement!.id).toBe("a");
|
||||
|
||||
a.dispatchEvent(keydown(win, "End"));
|
||||
expect(doc.activeElement!.id).toBe("c");
|
||||
});
|
||||
|
||||
test("horizontal roving ignores vertical arrows so the page still scrolls", () => {
|
||||
const win = mount(
|
||||
`<div data-wrn-roving="horizontal">
|
||||
<button data-wrn-roving-item id="a">A</button>
|
||||
<button data-wrn-roving-item id="b">B</button>
|
||||
</div>`,
|
||||
);
|
||||
const a = win.document.querySelector("#a") as unknown as HTMLElement;
|
||||
a.focus();
|
||||
a.dispatchEvent(keydown(win, "ArrowDown"));
|
||||
expect(win.document.activeElement!.id).toBe("a");
|
||||
});
|
||||
|
||||
test("roving tabindex starts on the selected item, not the first", () => {
|
||||
const win = mount(
|
||||
`<div data-wrn-roving="horizontal">
|
||||
<button data-wrn-roving-item id="a">A</button>
|
||||
<button data-wrn-roving-item id="b" aria-selected="true">B</button>
|
||||
</div>`,
|
||||
);
|
||||
expect(win.document.querySelector("#b")!.getAttribute("tabindex")).toBe("0");
|
||||
expect(win.document.querySelector("#a")!.getAttribute("tabindex")).toBe("-1");
|
||||
});
|
||||
|
||||
test("nested roving groups do not capture the outer group items", () => {
|
||||
const win = mount(
|
||||
`<div data-wrn-roving="horizontal" id="outer">
|
||||
<button data-wrn-roving-item id="a">A</button>
|
||||
<div data-wrn-roving="vertical" id="inner">
|
||||
<button data-wrn-roving-item id="x">X</button>
|
||||
<button data-wrn-roving-item id="y">Y</button>
|
||||
</div>
|
||||
<button data-wrn-roving-item id="b">B</button>
|
||||
</div>`,
|
||||
);
|
||||
const doc = win.document;
|
||||
const a = doc.querySelector("#a") as unknown as HTMLElement;
|
||||
a.focus();
|
||||
a.dispatchEvent(keydown(win, "ArrowRight"));
|
||||
expect(doc.activeElement!.id).toBe("b");
|
||||
});
|
||||
|
||||
test("opening a modal dialog traps Tab inside it", () => {
|
||||
const win = mount(
|
||||
`<div>
|
||||
<button id="outside">Outside</button>
|
||||
<div data-show="true">
|
||||
<section role="dialog" aria-modal="true" tabindex="-1">
|
||||
<button id="first">First</button>
|
||||
<button id="last">Last</button>
|
||||
</section>
|
||||
</div>
|
||||
</div>`,
|
||||
);
|
||||
const doc = win.document;
|
||||
const last = doc.querySelector("#last") as unknown as HTMLElement;
|
||||
last.focus();
|
||||
last.dispatchEvent(keydown(win, "Tab"));
|
||||
expect(doc.activeElement!.id).toBe("first");
|
||||
});
|
||||
|
||||
test("a hidden dialog does not trap Tab", () => {
|
||||
const win = mount(
|
||||
`<div>
|
||||
<button id="outside">Outside</button>
|
||||
<div data-show="false">
|
||||
<section role="dialog" aria-modal="true" tabindex="-1">
|
||||
<button id="first">First</button>
|
||||
</section>
|
||||
</div>
|
||||
</div>`,
|
||||
);
|
||||
const doc = win.document;
|
||||
const outside = doc.querySelector("#outside") as unknown as HTMLElement;
|
||||
outside.focus();
|
||||
outside.dispatchEvent(keydown(win, "Tab"));
|
||||
expect(doc.activeElement!.id).toBe("outside");
|
||||
});
|
||||
|
||||
test("an empty or false roving attribute opts the group out entirely", () => {
|
||||
const win = mount(
|
||||
`<div data-wrn-roving="">
|
||||
<button data-wrn-roving-item="false" id="a">A</button>
|
||||
<button data-wrn-roving-item="false" id="b">B</button>
|
||||
</div>`,
|
||||
);
|
||||
const doc = win.document;
|
||||
const a = doc.querySelector("#a") as unknown as HTMLElement;
|
||||
expect(a.getAttribute("tabindex")).toBeNull();
|
||||
a.focus();
|
||||
a.dispatchEvent(keydown(win, "ArrowRight"));
|
||||
expect(doc.activeElement!.id).toBe("a");
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/db",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/dev-server",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/dev-toolbar",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/encryption",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/graphql",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/helpers",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/i18n",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/identity",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Enterprise federation, provisioning, machine identity, and privacy governance for WRNexusJS.",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/image",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Responsive image planning, secure remote image policies, and performance auditing for WRNexusJS.",
|
||||
"main": "./src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/jwt",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/language-server",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Editor-neutral Language Server Protocol implementation for WRNexus .wrn files.",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/mcp",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Model Context Protocol server exposing WRNexus application and framework context.",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/mobile",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/native",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/oauth",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/observability",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Metrics, Web Vitals collection, request instrumentation, and exporter adapters for WRNexusJS.",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/playground",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Secure, shareable WRNexus compiler and UI playground.",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/plugin",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/pubsub",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/pwa",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"description": "Service workers, manifests, offline queues, background sync, push, and conflict resolution for WRNexusJS.",
|
||||
"main": "./src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/queue",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/reactive",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/realtime",
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.4",
|
||||
"description": "Typed realtime rooms, message helpers, presence utilities, package UI blocks, and WRNexusJS integration.",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user