feat(ui): build MegaMenu and rebuild Sidebar on Drawer
MegaMenu replaces a scaffold with a trigger and a wide panel of grouped link columns. One level deep on purpose: a mega menu exists to show breadth flat so everything is one click away, and nesting inside the panel buries content behind hover-within-hover. Nav is the component for cascading submenus. The panel is anchored so the runtime clamp keeps it inside the viewport. Sidebar now composes Drawer for its off-canvas presentation instead of a hand-rolled backdrop, inheriting the focus trap and scroll lock from one place. Single items, labelled groups and branches nested to three levels, with vertical roving focus. Sidebar classes move to the BEM naming the rest of the library uses, which is a breaking change; nesting via children still works, since that is what shipped in 0.8.5. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -61,11 +61,11 @@
|
||||
"packages/ui/components/Map.wrn": "7b8a0d5412a464fd7cab8977d816542c506d8c5dab8230a3c984c2caee407c91",
|
||||
"packages/ui/components/MarketingSectionHeader.wrn": "7d6ffcc01a9331474475ea57ca58598be757abd9428b66bdfaf6f3603c5b145b",
|
||||
"packages/ui/components/Marquee.wrn": "b2b35eedf3297ba12ab3776385a9f3eab001027648d87a2a1968f576eee6c025",
|
||||
"packages/ui/components/MegaMenu.wrn": "4a084eaf6aae77bb9023d2f3589bc6b80119b9be63982a90a80f9d280cc9c0a5",
|
||||
"packages/ui/components/MegaMenu.wrn": "48f4ced485df0e8de5217630c8bdcec0b2317bf04e6b279399f2c93d98d56995",
|
||||
"packages/ui/components/MetricCard.wrn": "6451182739298691908f68258c0250cce2a78b0dc27c97115579ece30d7d9f92",
|
||||
"packages/ui/components/MetricGrid.wrn": "6018a98c10628ed240ed236ed916c0ff60994d192c3aadafd10bc876be0f9364",
|
||||
"packages/ui/components/Modal.wrn": "59d4ae9d6dd2700692d9edecfe53ee868e9f864363a4885961d1813cb2bee51f",
|
||||
"packages/ui/components/Nav.wrn": "544483dbe7f2c3107c9c315ac0e7032c0989d8c7ad90e05a27ece12ac0652dfd",
|
||||
"packages/ui/components/Nav.wrn": "7dc456b879e9248bde267b986cdcb138b8f3127d98b51e27bc9708129953f5e2",
|
||||
"packages/ui/components/Navbar.wrn": "e68f9d3643e500e43124e9c7a6d4c7f6722657377ea7313f3e3cf5093a81b360",
|
||||
"packages/ui/components/PageHeader.wrn": "0761235a4924eec09877be40b292d27b70db22d210be7d8e989493165c20df86",
|
||||
"packages/ui/components/Pagination.wrn": "9ceb74745b159150b015bbbb1974c68e14a7d4b92bd03491cb23b8855aa07983",
|
||||
@@ -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": "05f4bd216ae8bfcee2460fe638e431174d5f3c8e10003f346644e5a2939e7ce5",
|
||||
"packages/ui/components/Sidebar.wrn": "03f1bbce75ca6d50ed940e62df39c539610e89eadd2064fe24abc7d5470f98bf",
|
||||
"packages/ui/components/SplitHero.wrn": "70e843565ff869bcf413b11b6d9830b2e2bd229863a00904596f71e2dff0e76d",
|
||||
"packages/ui/components/StatsBar.wrn": "c7d1df3895f25b6d3a2e1012a18b97592c7f33e65418b880d486f20c2d490686",
|
||||
"packages/ui/components/Stepper.wrn": "09f216a44f888421091bd1bce760a076927500a573550d5b2b10c4f27f608e92",
|
||||
"packages/ui/components/StrongPassword.wrn": "c7c5ef26ece6170dd7db9882f0dc98cb2e4607f1e5d43eb3fd39e5d15bbd3a2e",
|
||||
"packages/ui/components/StyledIcon.wrn": "4a4504e357dee9dd0418edbe85fc90b824ccdb3752123a2125da95b77bf0b336",
|
||||
"packages/ui/components/Switch.wrn": "ccb74599fab72b0d68b09a7f1f90b7732cb2f9cbed67a84219e897575ce30c28",
|
||||
"packages/ui/components/Tabs.wrn": "8a1b98c7395b27b09f16f0ebdc14d3d84473b06023ec2b3ed0af495cc2f076bb",
|
||||
"packages/ui/components/Tabs.wrn": "29c0aacca730616002b7988308426e20b7a34abb9b249212d59d76190d89572f",
|
||||
"packages/ui/components/TextLink.wrn": "30782039293eb36d63b7b3a4f32a71a47177a3a68c7e90184be7cf7b4385eb19",
|
||||
"packages/ui/components/Textarea.wrn": "ddf0b4f124b2cf0c0ab3d820d3ac0085f7c20466e977231949be264cd0cee8cf",
|
||||
"packages/ui/components/TimePicker.wrn": "2e8e7a90f6b6069a07e7ffd2725ba1e1031e84d55a4f1254025befbb314fa695",
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
// Generated by scripts/generate-showcase.mjs. Do not edit directly.
|
||||
page MegaMenuDetail {
|
||||
layout = "showcase"
|
||||
state playground_size = ctx.url.searchParams.get("pg_size") ?? "default"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_size = ctx.url.searchParams.get("pg_size") ?? "default"
|
||||
state playground_label = ctx.url.searchParams.get("pg_label") ?? "Mega Menu"
|
||||
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_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_class = ctx.url.searchParams.get("pg_class") ?? "showcase-instance showcase-instance--1"
|
||||
seo {
|
||||
title = "Mega Menu"
|
||||
@@ -21,7 +22,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>7 props</span><span>1 slots</span><span>3 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
<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>
|
||||
<div class="detail-hero-icon"><span class="icon-[lucide--component] size-10" aria-hidden="true"></span></div>
|
||||
</header>
|
||||
@@ -30,11 +31,12 @@ 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 size='{playground_size}' color='{playground_color}' label='{playground_label}' items='{playground_items}' active='{playground_active}' orientation='{playground_orientation}' class='{playground_class}' /></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>
|
||||
<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
|
||||
items='[
|
||||
label="Mega Menu"
|
||||
columns='[
|
||||
<span>{</span>
|
||||
"id": "mega-menu-0-1",
|
||||
"key": "mega-menu-0-1",
|
||||
@@ -148,8 +150,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>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>[
|
||||
<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>[
|
||||
{
|
||||
"id": "mega-menu-0-1",
|
||||
"key": "mega-menu-0-1",
|
||||
@@ -256,7 +258,7 @@ page MegaMenuDetail {
|
||||
"Standard"
|
||||
]
|
||||
}
|
||||
]</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>
|
||||
]</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>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
@@ -265,123 +267,49 @@ 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>Production default</h2><p>Balanced spacing, hierarchy, and content for the most common product workflow.</p></div>
|
||||
<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>
|
||||
<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="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 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>
|
||||
<section class="demo-code" aria-label="Production default usage">
|
||||
<section class="demo-code" aria-label="Grouped columns 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
|
||||
items='[
|
||||
label="Products"
|
||||
icon="icon-[lucide--box]"
|
||||
columns='[
|
||||
<span>{</span>
|
||||
"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",
|
||||
"heading": "Platform",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
"label": "Runtime",
|
||||
"href": "/runtime",
|
||||
"description": "The browser half of the framework."
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
"label": "Compiler",
|
||||
"href": "/compiler",
|
||||
"description": "WRN to JavaScript."
|
||||
<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": "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",
|
||||
"heading": "Tooling",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
"label": "CLI",
|
||||
"href": "/cli",
|
||||
"description": "Scaffold, build and deploy."
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
"label": "Editor",
|
||||
"href": "/editor",
|
||||
"description": "Language server and syntax."
|
||||
<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>
|
||||
]'
|
||||
@@ -391,256 +319,57 @@ page MegaMenuDetail {
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<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>
|
||||
<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>
|
||||
<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="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 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>
|
||||
<section class="demo-code" aria-label="Compact application usage">
|
||||
<section class="demo-code" aria-label="With a footer note 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="Compact example"
|
||||
items='[
|
||||
label="Solutions"
|
||||
icon="icon-[lucide--arrow-right]"
|
||||
columns='[
|
||||
<span>{</span>
|
||||
"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",
|
||||
"heading": "By team",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
"label": "Engineering",
|
||||
"href": "/eng",
|
||||
"icon": "icon-[lucide--code]"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
"label": "Design",
|
||||
"href": "/design",
|
||||
"icon": "icon-[lucide--palette]"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
"label": "Support",
|
||||
"href": "/support",
|
||||
"icon": "icon-[lucide--life-buoy]"
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"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",
|
||||
"heading": "By size",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
"label": "Startup",
|
||||
"href": "/startup"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
"label": "Enterprise",
|
||||
"href": "/enterprise"
|
||||
<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>
|
||||
@@ -664,10 +393,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>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>
|
||||
<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>
|
||||
</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">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>
|
||||
<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>
|
||||
</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_size = ctx.url.searchParams.get("pg_size") ?? "default"
|
||||
state playground_color = ctx.url.searchParams.get("pg_color") ?? "primary"
|
||||
state playground_size = ctx.url.searchParams.get("pg_size") ?? "default"
|
||||
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>1 slots</span><span>4 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
<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>
|
||||
<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 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>
|
||||
<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>
|
||||
<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,14 +144,18 @@ page SidebarDetail {
|
||||
<span>}</span>
|
||||
]'
|
||||
mobileLabel="Sidebar"
|
||||
/></code></pre>
|
||||
drawerTitle="Sidebar example">
|
||||
<div data-slot="drawer">
|
||||
<div class="showcase-slot">drawer slot</div>
|
||||
</div>
|
||||
</Sidebar></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-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>[
|
||||
<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>[
|
||||
{
|
||||
"id": "sidebar-0-1",
|
||||
"key": "sidebar-0-1",
|
||||
@@ -258,7 +262,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-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>
|
||||
]</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>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
@@ -267,386 +271,111 @@ 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>Production default</h2><p>Balanced spacing, hierarchy, and content for the most common product workflow.</p></div>
|
||||
<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>
|
||||
<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="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 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>
|
||||
<section class="demo-code" aria-label="Production default usage">
|
||||
<section class="demo-code" aria-label="Groups and nested levels 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>
|
||||
"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",
|
||||
"label": "Dashboard",
|
||||
"href": "/",
|
||||
"value": "dash",
|
||||
"icon": "icon-[lucide--gauge]"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"heading": "Projects",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
"label": "Active",
|
||||
"href": "/active",
|
||||
"value": "active",
|
||||
"badge": "4"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
<span>}</span>
|
||||
],
|
||||
"links": [
|
||||
"label": "Archive",
|
||||
"value": "archive",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Documentation",
|
||||
"href": "#documentation"
|
||||
"label": "2025",
|
||||
"href": "/a/2025",
|
||||
"value": "a2025"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "API reference",
|
||||
"href": "#api-reference"
|
||||
"label": "2024",
|
||||
"href": "/a/2024",
|
||||
"value": "a2024"
|
||||
<span>}</span>
|
||||
]
|
||||
<span>}</span>
|
||||
],
|
||||
"values": [
|
||||
"Included",
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"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",
|
||||
"heading": "Account",
|
||||
"items": [
|
||||
<span>{</span>
|
||||
"label": "Nested option A",
|
||||
"value": "nested-a"
|
||||
<span>}</span>,
|
||||
<span>{</span>
|
||||
"label": "Nested option B",
|
||||
"value": "nested-b"
|
||||
"label": "Settings",
|
||||
"href": "/settings",
|
||||
"value": "settings",
|
||||
"icon": "icon-[lucide--settings]"
|
||||
<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"
|
||||
/></code></pre>
|
||||
drawerTitle="Sidebar example">
|
||||
<div data-slot="drawer">
|
||||
<div class="showcase-slot">drawer slot</div>
|
||||
</div>
|
||||
</Sidebar></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
<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>
|
||||
<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>
|
||||
<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="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 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>
|
||||
<section class="demo-code" aria-label="Compact application usage">
|
||||
<section class="demo-code" aria-label="Drawer on small screens 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="Compact example"
|
||||
label="Operations"
|
||||
items='[
|
||||
<span>{</span>
|
||||
"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"
|
||||
"label": "Queue",
|
||||
"href": "/queue",
|
||||
"value": "queue",
|
||||
"icon": "icon-[lucide--inbox]"
|
||||
<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": "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"
|
||||
]
|
||||
"label": "Reports",
|
||||
"href": "/reports",
|
||||
"value": "reports",
|
||||
"icon": "icon-[lucide--chart-no-axes-column]"
|
||||
<span>}</span>
|
||||
]'
|
||||
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>
|
||||
active="queue"
|
||||
drawerTitle="Operations">
|
||||
<div data-slot="drawer">
|
||||
<div class="showcase-slot">drawer slot</div>
|
||||
</div>
|
||||
</Sidebar></code></pre>
|
||||
</section>
|
||||
</div>
|
||||
</article></div></section>
|
||||
@@ -674,10 +403,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>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>
|
||||
<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>
|
||||
</main>
|
||||
<aside class="detail-aside">
|
||||
<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>
|
||||
<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>
|
||||
</aside>
|
||||
</div>
|
||||
<nav class="detail-pagination">
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
// Generated by scripts/generate-showcase.mjs. Do not edit directly.
|
||||
page TabsDetail {
|
||||
layout = "showcase"
|
||||
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_size = ctx.url.searchParams.get("pg_size") ?? "default"
|
||||
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"
|
||||
@@ -21,16 +23,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>7 props</span><span>1 slots</span><span>0 outputs</span><span>Theme ready</span><span>Responsive</span></div>
|
||||
<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>
|
||||
<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="">
|
||||
<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">
|
||||
<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 size='{playground_size}' color='{playground_color}' label='{playground_label}' items='{playground_items}' active='{playground_active}' orientation='{playground_orientation}' class='{playground_class}' /></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>
|
||||
<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
|
||||
@@ -141,15 +143,18 @@ page TabsDetail {
|
||||
"Standard"
|
||||
]
|
||||
<span>}</span>
|
||||
]'
|
||||
/></code></pre>
|
||||
]'>
|
||||
<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 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>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>[
|
||||
<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>[
|
||||
{
|
||||
"id": "tabs-0-1",
|
||||
"key": "tabs-0-1",
|
||||
@@ -256,7 +261,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-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-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>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
@@ -272,12 +277,11 @@ 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" 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 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>
|
||||
<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",
|
||||
@@ -296,26 +300,71 @@ page TabsDetail {
|
||||
<span>}</span>
|
||||
]'
|
||||
active="overview"
|
||||
/></code></pre>
|
||||
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">Compact</span><h2>Compact application tabs</h2><p>Use smaller tabs in dashboards, panels, and dense product interfaces.</p></div>
|
||||
<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" 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 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>
|
||||
</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>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<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="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>
|
||||
<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",
|
||||
@@ -331,26 +380,29 @@ page TabsDetail {
|
||||
<span>}</span>
|
||||
]'
|
||||
active="details"
|
||||
/></code></pre>
|
||||
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>
|
||||
</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">03</span>
|
||||
<span class="demo-case-number">04</span>
|
||||
</header>
|
||||
<div class="demo-workbench">
|
||||
<div id="tabs-demo-3" class="demo-canvas demo-canvas--3">
|
||||
<div id="tabs-demo-4" class="demo-canvas demo-canvas--4">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></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 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>
|
||||
<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",
|
||||
@@ -370,15 +422,32 @@ page TabsDetail {
|
||||
]'
|
||||
active="security"
|
||||
orientation="vertical"
|
||||
/></code></pre>
|
||||
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>
|
||||
</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"
|
||||
|
||||
<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>
|
||||
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>
|
||||
</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">Compact application tabs</a><a href="#tabs-demo-3">Vertical settings tabs</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">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>
|
||||
</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>421</strong><span>Live configurations</span></div>
|
||||
<div class="showcase-stat"><strong>420</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 · 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>
|
||||
<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>
|
||||
</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>30 live configurations</span></div>
|
||||
<div class="category-meta"><span>10 components</span><span>Multiple use cases</span><span>29 live configurations</span></div>
|
||||
</header>
|
||||
<div class="catalog-grid">
|
||||
<article class="catalog-card" data-interactive-preview="false">
|
||||
@@ -36,11 +36,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"><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 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>
|
||||
<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>7 props · 1 slots</span><a href="/components/mega-menu">Explore component <span aria-hidden="true">→</span></a></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>
|
||||
</article>
|
||||
<article class="catalog-card" data-interactive-preview="false">
|
||||
@@ -86,11 +86,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"><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 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>
|
||||
<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 · 1 slots</span><a href="/components/sidebar">Explore component <span aria-hidden="true">→</span></a></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>
|
||||
</article>
|
||||
<article class="catalog-card" data-interactive-preview="false">
|
||||
@@ -106,11 +106,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"><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 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>
|
||||
<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>7 props · 1 slots</span><a href="/components/tabs">Explore component <span aria-hidden="true">→</span></a></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>
|
||||
</article></div>
|
||||
}
|
||||
|
||||
@@ -253,76 +253,118 @@ 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 = {
|
||||
Tabs: {
|
||||
MegaMenu: {
|
||||
demos: [
|
||||
standard(
|
||||
"Panels and arrow keys",
|
||||
"Selecting a tab swaps the panel with a short transition. Arrow keys move between tabs, Home and End jump to the ends, and only the selected tab is in the tab order.",
|
||||
"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: "Overview",
|
||||
value: "overview",
|
||||
title: "Overview",
|
||||
description: "What the product does and who it is for.",
|
||||
label: "Runtime",
|
||||
href: "/runtime",
|
||||
description: "The browser half of the framework.",
|
||||
},
|
||||
{ label: "Compiler", href: "/compiler", description: "WRN to JavaScript." },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Pricing",
|
||||
value: "pricing",
|
||||
title: "Pricing",
|
||||
description: "Plans, limits and what counts as a seat.",
|
||||
badge: "New",
|
||||
},
|
||||
{
|
||||
label: "Support",
|
||||
value: "support",
|
||||
title: "Support",
|
||||
description: "Response times and escalation paths.",
|
||||
heading: "Tooling",
|
||||
items: [
|
||||
{ label: "CLI", href: "/cli", description: "Scaffold, build and deploy." },
|
||||
{ label: "Editor", href: "/editor", description: "Language server and syntax." },
|
||||
],
|
||||
},
|
||||
],
|
||||
active: "overview",
|
||||
},
|
||||
),
|
||||
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.",
|
||||
"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: "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." },
|
||||
{ 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]" },
|
||||
],
|
||||
active: "account",
|
||||
mode: "url",
|
||||
param: "tab",
|
||||
},
|
||||
{
|
||||
heading: "By size",
|
||||
items: [
|
||||
{ label: "Startup", href: "/startup" },
|
||||
{ label: "Enterprise", href: "/enterprise" },
|
||||
],
|
||||
},
|
||||
],
|
||||
footer: "Not sure where to start? Talk to us.",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
Sidebar: {
|
||||
demos: [
|
||||
standard(
|
||||
"Vertical with icons",
|
||||
"Vertical orientation switches the arrow keys to up and down, and collapses back to a scrollable strip on a phone.",
|
||||
"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]" },
|
||||
{
|
||||
label: "General",
|
||||
value: "general",
|
||||
icon: "icon-[lucide--settings]",
|
||||
description: "Everyday preferences.",
|
||||
},
|
||||
heading: "Projects",
|
||||
items: [
|
||||
{ label: "Active", href: "/active", value: "active", badge: "4" },
|
||||
{
|
||||
label: "Security",
|
||||
value: "security",
|
||||
icon: "icon-[lucide--shield]",
|
||||
description: "Sessions and two-factor.",
|
||||
},
|
||||
{
|
||||
label: "Advanced",
|
||||
value: "advanced",
|
||||
icon: "icon-[lucide--flask-conical]",
|
||||
description: "Experimental toggles.",
|
||||
label: "Archive",
|
||||
value: "archive",
|
||||
items: [
|
||||
{ label: "2025", href: "/a/2025", value: "a2025" },
|
||||
{ label: "2024", href: "/a/2024", value: "a2024" },
|
||||
],
|
||||
},
|
||||
],
|
||||
active: "security",
|
||||
orientation: "vertical",
|
||||
},
|
||||
{
|
||||
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",
|
||||
},
|
||||
),
|
||||
],
|
||||
@@ -2438,6 +2480,21 @@ 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": 421,
|
||||
"totalDemoCount": 420,
|
||||
"components": [
|
||||
{
|
||||
"name": "Accordion",
|
||||
@@ -786,11 +786,11 @@
|
||||
"slug": "mega-menu",
|
||||
"category": "navigation",
|
||||
"purpose": "Theme-aware, responsive mega menu component.",
|
||||
"demoCount": 3,
|
||||
"propCount": 7,
|
||||
"demoCount": 2,
|
||||
"propCount": 8,
|
||||
"slots": ["default"],
|
||||
"events": ["open", "close", "select"],
|
||||
"profiled": false
|
||||
"profiled": true
|
||||
},
|
||||
{
|
||||
"name": "MetricCard",
|
||||
@@ -1050,11 +1050,11 @@
|
||||
"slug": "sidebar",
|
||||
"category": "navigation",
|
||||
"purpose": "Theme-aware, responsive sidebar component.",
|
||||
"demoCount": 3,
|
||||
"demoCount": 2,
|
||||
"propCount": 8,
|
||||
"slots": ["default"],
|
||||
"slots": ["default", "drawer"],
|
||||
"events": ["toggle", "open", "close", "select"],
|
||||
"profiled": false
|
||||
"profiled": true
|
||||
},
|
||||
{
|
||||
"name": "Skeleton",
|
||||
@@ -1158,10 +1158,10 @@
|
||||
"slug": "tabs",
|
||||
"category": "navigation",
|
||||
"purpose": "Switch between related responsive content panels with horizontal or vertical orientation and selection events.",
|
||||
"demoCount": 3,
|
||||
"propCount": 7,
|
||||
"slots": ["default"],
|
||||
"events": [],
|
||||
"demoCount": 4,
|
||||
"propCount": 9,
|
||||
"slots": ["panel-{valueOf(item, index)}", "default"],
|
||||
"events": ["change", "select"],
|
||||
"profiled": true
|
||||
},
|
||||
{
|
||||
|
||||
@@ -862,9 +862,9 @@ Show responsive hierarchical navigation with home support, separators, current-p
|
||||
Theme-aware, responsive mega menu component.
|
||||
|
||||
- Mount: `data-component="MegaMenu"`
|
||||
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Mega Menu"`, `items: unknown[] = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
|
||||
- Props: `color: string = "primary"`, `size: string = "default"`, `label: string = "Menu"`, `icon: string = ""`, `columns: unknown[] = []`, `footer: string = ""`, `defaultOpen: boolean = false`, `class: string = ""`
|
||||
- Slots: `default`
|
||||
- Outputs: `open({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `close({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `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)`
|
||||
- Outputs: `open({ sourceEvent: Event })`, `close({ reason: string })`, `select({ item: object; value: string })`
|
||||
|
||||
### Nav
|
||||
|
||||
@@ -907,9 +907,9 @@ Theme-aware, responsive scrollspy component.
|
||||
Theme-aware, responsive sidebar component.
|
||||
|
||||
- Mount: `data-component="Sidebar"`
|
||||
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Sidebar"`, `items: unknown[] = []`, `active: string = ""`, `orientation: string = "horizontal"`, `mobileLabel: string = "Open navigation"`, `class: string = ""`
|
||||
- Slots: `default`
|
||||
- Outputs: `toggle({ open: boolean })`, `open({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `close({ source: string })`, `select({ item: string | number | boolean | null | object; value: string | number | boolean; level: string })`
|
||||
- Props: `color: string = "primary"`, `size: string = "default"`, `label: string = "Sidebar"`, `items: unknown[] = []`, `active: string = ""`, `mobileLabel: string = "Open navigation"`, `drawerTitle: string = "Navigation"`, `class: string = ""`
|
||||
- Slots: `default`, `drawer`
|
||||
- Outputs: `toggle({ open: boolean })`, `open({ sourceEvent: Event })`, `close({ source: string })`, `select({ item: object; value: string; level: number })`
|
||||
|
||||
### Stepper
|
||||
|
||||
@@ -925,9 +925,9 @@ Theme-aware, responsive stepper component.
|
||||
Switch between related responsive content panels with horizontal or vertical orientation and selection events.
|
||||
|
||||
- Mount: `data-component="Tabs"`
|
||||
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Tabs"`, `items: unknown[] = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
|
||||
- Slots: `default`
|
||||
- Outputs: None
|
||||
- Props: `color: string = "primary"`, `size: string = "default"`, `items: unknown[] = []`, `active: string = ""`, `orientation: string = "horizontal"`, `mode: string = "client"`, `param: string = "tab"`, `label: string = "Tabs"`, `class: string = ""`
|
||||
- Slots: `panel-{valueOf(item, index)}`, `default`
|
||||
- Outputs: `change({ value: string; item: object; index: number })`, `select({ value: string; item: object; index: number })`
|
||||
|
||||
## Overlays
|
||||
|
||||
|
||||
@@ -8326,13 +8326,6 @@
|
||||
"category": "navigation",
|
||||
"purpose": "Theme-aware, responsive mega menu component.",
|
||||
"props": [
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
@@ -8340,32 +8333,46 @@
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "label",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Mega Menu\"",
|
||||
"default": "\"Menu\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "items",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "active",
|
||||
"name": "icon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "orientation",
|
||||
"name": "columns",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "footer",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"horizontal\"",
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "defaultOpen",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
@@ -8380,15 +8387,15 @@
|
||||
"outputs": [
|
||||
{
|
||||
"name": "open",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
"payloadType": "{ sourceEvent: Event }"
|
||||
},
|
||||
{
|
||||
"name": "close",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
"payloadType": "{ reason: string }"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
"payloadType": "{ item: object; value: string }"
|
||||
}
|
||||
],
|
||||
"events": ["open", "close", "select"],
|
||||
@@ -11237,13 +11244,6 @@
|
||||
"category": "navigation",
|
||||
"purpose": "Theme-aware, responsive sidebar component.",
|
||||
"props": [
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
@@ -11251,6 +11251,13 @@
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "label",
|
||||
"type": "string",
|
||||
@@ -11272,13 +11279,6 @@
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "orientation",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"horizontal\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "mobileLabel",
|
||||
"type": "string",
|
||||
@@ -11286,6 +11286,13 @@
|
||||
"default": "\"Open navigation\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "drawerTitle",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Navigation\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
@@ -11294,7 +11301,7 @@
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": ["default"],
|
||||
"slots": ["default", "drawer"],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "toggle",
|
||||
@@ -11302,7 +11309,7 @@
|
||||
},
|
||||
{
|
||||
"name": "open",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
"payloadType": "{ sourceEvent: Event }"
|
||||
},
|
||||
{
|
||||
"name": "close",
|
||||
@@ -11310,7 +11317,7 @@
|
||||
},
|
||||
{
|
||||
"name": "select",
|
||||
"payloadType": "{ item: string | number | boolean | null | object; value: string | number | boolean; level: string }"
|
||||
"payloadType": "{ item: object; value: string; level: number }"
|
||||
}
|
||||
],
|
||||
"events": ["toggle", "open", "close", "select"],
|
||||
@@ -12244,13 +12251,6 @@
|
||||
"category": "navigation",
|
||||
"purpose": "Switch between related responsive content panels with horizontal or vertical orientation and selection events.",
|
||||
"props": [
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
@@ -12259,10 +12259,10 @@
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "label",
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Tabs\"",
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
@@ -12286,6 +12286,27 @@
|
||||
"default": "\"horizontal\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "mode",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"client\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "param",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"tab\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "label",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Tabs\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
@@ -12294,9 +12315,18 @@
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": ["default"],
|
||||
"outputs": [],
|
||||
"events": [],
|
||||
"slots": ["panel-{valueOf(item, index)}", "default"],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "change",
|
||||
"payloadType": "{ value: string; item: object; index: number }"
|
||||
},
|
||||
{
|
||||
"name": "select",
|
||||
"payloadType": "{ value: string; item: object; index: number }"
|
||||
}
|
||||
],
|
||||
"events": ["change", "select"],
|
||||
"source": "components/Tabs.wrn"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,23 +1,329 @@
|
||||
// MegaMenu -- a trigger and a wide panel of grouped links.
|
||||
//
|
||||
// <MegaMenu label="Products" columns='[{"heading":"Platform",
|
||||
// "items":[{"label":"Runtime","href":"/runtime"}]}]' />
|
||||
//
|
||||
// Deliberately one level deep. 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. Use Nav
|
||||
// when you actually want cascading submenus.
|
||||
//
|
||||
// The panel carries data-wrn-anchored so the runtime clamp keeps it inside the
|
||||
// viewport instead of hanging off the edge of a wide layout.
|
||||
//
|
||||
// NOTE: the style block uses /* */ comments only -- // is not a CSS comment
|
||||
// and silently swallows the rule that follows it.
|
||||
component MegaMenu {
|
||||
outputs {
|
||||
open(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
|
||||
close(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
|
||||
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)
|
||||
open(payload: { sourceEvent: Event })
|
||||
close(payload: { reason: string })
|
||||
select(payload: { item: object; value: string })
|
||||
}
|
||||
|
||||
props {
|
||||
size: string = "default"
|
||||
color: string = "primary"
|
||||
label: string = "Mega Menu"
|
||||
items: unknown[] = []
|
||||
active: string = ""
|
||||
orientation: string = "horizontal"
|
||||
size: string = "default"
|
||||
label: string = "Menu"
|
||||
icon: string = ""
|
||||
columns: unknown[] = []
|
||||
footer: string = ""
|
||||
defaultOpen: boolean = false
|
||||
class: string = ""
|
||||
}
|
||||
|
||||
state visible = defaultOpen
|
||||
|
||||
functions {
|
||||
shared function columnList() {
|
||||
return Array.isArray(columns) ? columns : []
|
||||
}
|
||||
|
||||
shared function itemsOf(column) {
|
||||
return column && Array.isArray(column.items) ? column.items : []
|
||||
}
|
||||
|
||||
client function showPanel(sourceEvent) {
|
||||
visible = true
|
||||
output.open({ sourceEvent: sourceEvent })
|
||||
}
|
||||
|
||||
client function hidePanel(reason) {
|
||||
visible = false
|
||||
output.close({ reason: reason })
|
||||
}
|
||||
|
||||
client function togglePanel(sourceEvent) {
|
||||
if (visible) {
|
||||
hidePanel("toggle")
|
||||
} else {
|
||||
showPanel(sourceEvent)
|
||||
}
|
||||
}
|
||||
|
||||
client function handleKeydown(sourceEvent) {
|
||||
if (sourceEvent.key === "Escape" && visible) {
|
||||
sourceEvent.preventDefault()
|
||||
hidePanel("escape")
|
||||
}
|
||||
}
|
||||
|
||||
client function choose(item) {
|
||||
if (item.disabled) {
|
||||
return
|
||||
}
|
||||
output.select({ item: item, value: item.value || item.label || "" })
|
||||
hidePanel("select")
|
||||
}
|
||||
}
|
||||
|
||||
view {
|
||||
<nav class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--mega-menu wire-next--{orientation} {class}" aria-label="{label}">
|
||||
{#each items as item}<a href="{item.href}" aria-current="{item.value === active ? 'page' : ''}">{item.label}</a>{/each}
|
||||
<div
|
||||
{...attrs}
|
||||
data-ui-component="MegaMenu"
|
||||
class='wire-mega {class}'
|
||||
data-color='{color}'
|
||||
data-size='{size}'
|
||||
data-open='{visible}'
|
||||
@keydown='handleKeydown(event)'
|
||||
@mouseleave='hidePanel("pointer-leave")'
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="wire-mega__trigger"
|
||||
aria-haspopup="true"
|
||||
aria-expanded='{visible}'
|
||||
@click='togglePanel(event)'
|
||||
@mouseenter='showPanel(event)'
|
||||
@focus='showPanel(event)'
|
||||
>
|
||||
<span class='wire-mega__trigger-icon {icon}' data-show="icon" aria-hidden="true"></span>
|
||||
<span class="wire-mega__trigger-label">{label}</span>
|
||||
<span class="wire-mega__arrow" aria-hidden="true">›</span>
|
||||
</button>
|
||||
|
||||
<div
|
||||
class="wire-mega__panel"
|
||||
data-wrn-anchored="true"
|
||||
data-show="visible"
|
||||
data-wrn-roving="both"
|
||||
>
|
||||
<div class="wire-mega__columns">
|
||||
{#each columnList() as column}
|
||||
<section class="wire-mega__column">
|
||||
<h3 class="wire-mega__heading" data-show="column.heading">{column.heading}</h3>
|
||||
<ul class="wire-mega__list">
|
||||
{#each itemsOf(column) as item}
|
||||
<li>
|
||||
<a
|
||||
class="wire-mega__link"
|
||||
href='{item.href || "#"}'
|
||||
data-wrn-roving-item="true"
|
||||
aria-disabled='{item.disabled ? "true" : "false"}'
|
||||
@click='choose(item)'
|
||||
>
|
||||
<span
|
||||
class='wire-mega__link-icon {item.icon}'
|
||||
data-show="item.icon"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<span class="wire-mega__link-body">
|
||||
<span class="wire-mega__link-label">{item.label}</span>
|
||||
<span class="wire-mega__link-description" data-show="item.description">
|
||||
{item.description}
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</section>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<p class="wire-mega__footer" data-show="footer">{footer}</p>
|
||||
<slot />
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
style {
|
||||
.wire-mega {
|
||||
--mega-accent: var(--wire-color-primary);
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.wire-mega[data-color="secondary"] {
|
||||
--mega-accent: var(--wire-color-secondary);
|
||||
}
|
||||
|
||||
.wire-mega[data-color="success"] {
|
||||
--mega-accent: var(--wire-color-success);
|
||||
}
|
||||
|
||||
.wire-mega[data-color="danger"] {
|
||||
--mega-accent: var(--wire-color-danger);
|
||||
}
|
||||
|
||||
.wire-mega[data-color="info"] {
|
||||
--mega-accent: var(--wire-color-info);
|
||||
}
|
||||
|
||||
.wire-mega[data-size="sm"] {
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.wire-mega[data-size="lg"] {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.wire-mega__trigger {
|
||||
appearance: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
padding: 0.45rem 0.7rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--wire-radius-sm);
|
||||
background: transparent;
|
||||
color: var(--wire-color-text-muted);
|
||||
font: inherit;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wire-mega__trigger:hover,
|
||||
.wire-mega[data-open="true"] .wire-mega__trigger {
|
||||
background: var(--wire-color-surface-soft);
|
||||
color: var(--wire-color-text);
|
||||
}
|
||||
|
||||
.wire-mega__trigger:focus-visible {
|
||||
outline: 2px solid var(--mega-accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.wire-mega__arrow {
|
||||
display: inline-block;
|
||||
transition: transform 160ms ease;
|
||||
}
|
||||
|
||||
.wire-mega[data-open="true"] .wire-mega__arrow {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.wire-mega__panel {
|
||||
position: absolute;
|
||||
z-index: 40;
|
||||
top: calc(100% + 0.4rem);
|
||||
left: 0;
|
||||
width: max-content;
|
||||
max-width: min(60rem, calc(100vw - 2rem));
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--wire-color-border);
|
||||
border-radius: var(--wire-radius-lg);
|
||||
background: var(--wire-color-surface);
|
||||
box-shadow: var(--wire-shadow-1);
|
||||
}
|
||||
|
||||
.wire-mega__columns {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.wire-mega__column {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.wire-mega__heading {
|
||||
margin: 0 0 0.5rem;
|
||||
color: var(--wire-color-text-muted);
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.wire-mega__list {
|
||||
display: grid;
|
||||
gap: 0.15rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.wire-mega__link {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
padding: 0.45rem 0.5rem;
|
||||
border-radius: var(--wire-radius-sm);
|
||||
color: var(--wire-color-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.wire-mega__link:hover {
|
||||
background: var(--wire-color-surface-soft);
|
||||
}
|
||||
|
||||
.wire-mega__link:focus-visible {
|
||||
outline: 2px solid var(--mega-accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.wire-mega__link[aria-disabled="true"] {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.wire-mega__link-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.wire-mega__link-label {
|
||||
font-size: 0.88rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wire-mega__link-description {
|
||||
color: var(--wire-color-text-muted);
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.wire-mega__footer {
|
||||
margin: 1rem 0 0;
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid var(--wire-color-border);
|
||||
color: var(--wire-color-text-muted);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/*
|
||||
* On a phone the panel stops floating and becomes part of the flow. A
|
||||
* pointer-opened overlay pinned to a trigger is unreachable on touch, and
|
||||
* a 60rem grid has nowhere to go on a 360px screen.
|
||||
*/
|
||||
@media (max-width: 767px) {
|
||||
.wire-mega {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.wire-mega__panel {
|
||||
position: static;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.wire-mega__columns {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +1,335 @@
|
||||
// Sidebar -- a vertical navigation rail that becomes a drawer on small screens.
|
||||
//
|
||||
// <Sidebar items='[{"label":"Dashboard","href":"/","value":"dash"}]' active="dash" />
|
||||
//
|
||||
// An entry is one of three shapes:
|
||||
// { label, href, value } a single link
|
||||
// { heading, items: [...] } a labelled group
|
||||
// { label, items: [...] } a collapsible branch, nested to 3 levels
|
||||
//
|
||||
// The off-canvas presentation is Drawer rather than a second implementation,
|
||||
// so the focus trap and the body scroll lock come from one place.
|
||||
//
|
||||
// NOTE: the style block uses /* */ comments only -- // is not a CSS comment
|
||||
// and silently swallows the rule that follows it.
|
||||
import Drawer from "./Drawer.wrn"
|
||||
|
||||
component Sidebar {
|
||||
outputs {
|
||||
toggle(payload: { open: boolean })
|
||||
open(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
|
||||
open(payload: { sourceEvent: Event })
|
||||
close(payload: { source: string })
|
||||
select(payload: { item: string | number | boolean | null | object; value: string | number | boolean; level: string })
|
||||
select(payload: { item: object; value: string; level: number })
|
||||
}
|
||||
|
||||
props {
|
||||
size: string = "default"
|
||||
color: string = "primary"
|
||||
size: string = "default"
|
||||
label: string = "Sidebar"
|
||||
items: unknown[] = []
|
||||
active: string = ""
|
||||
orientation: string = "horizontal"
|
||||
mobileLabel: string = "Open navigation"
|
||||
drawerTitle: string = "Navigation"
|
||||
class: string = ""
|
||||
}
|
||||
|
||||
state mobileOpen: boolean = false
|
||||
state drawerOpen = false
|
||||
|
||||
functions {
|
||||
client function toggleSidebar() {
|
||||
mobileOpen = !mobileOpen
|
||||
output.toggle({ open: mobileOpen })
|
||||
output[mobileOpen ? "open" : "close"]({ source: "mobile" })
|
||||
shared function entryList() {
|
||||
return Array.isArray(items) ? items : []
|
||||
}
|
||||
|
||||
client function closeSidebar() {
|
||||
mobileOpen = false
|
||||
output.close({ source: "mobile" })
|
||||
// Accepts children as well as items: children is what shipped in 0.8.5
|
||||
// and existing callers should keep working.
|
||||
shared function childrenOf(entry) {
|
||||
if (!entry) {
|
||||
return []
|
||||
}
|
||||
if (Array.isArray(entry.items)) {
|
||||
return entry.items
|
||||
}
|
||||
return Array.isArray(entry.children) ? entry.children : []
|
||||
}
|
||||
|
||||
client function selectItem(item, level) {
|
||||
mobileOpen = false
|
||||
output.select({ item: item, value: item.value || "", level: level })
|
||||
shared function isGroup(entry) {
|
||||
return Boolean(entry.heading)
|
||||
}
|
||||
|
||||
shared function isActive(entry) {
|
||||
return Boolean(entry.value) && entry.value === active
|
||||
}
|
||||
|
||||
client function choose(entry, level) {
|
||||
if (entry.disabled) {
|
||||
return
|
||||
}
|
||||
output.select({ item: entry, value: entry.value || "", level: level })
|
||||
if (drawerOpen) {
|
||||
drawerOpen = false
|
||||
output.close({ source: "select" })
|
||||
}
|
||||
}
|
||||
|
||||
client function openDrawer(sourceEvent) {
|
||||
drawerOpen = true
|
||||
output.open({ sourceEvent: sourceEvent })
|
||||
output.toggle({ open: true })
|
||||
}
|
||||
|
||||
client function closeDrawer() {
|
||||
drawerOpen = false
|
||||
output.close({ source: "drawer" })
|
||||
output.toggle({ open: false })
|
||||
}
|
||||
}
|
||||
|
||||
view {
|
||||
<div class="wire-sidebar-shell wire-next--color-{color} wire-next--size-{size} {mobileOpen ? 'is-open' : ''} {class}">
|
||||
<button type="button" class="wire-sidebar-toggle" aria-label="{mobileLabel}" aria-expanded="{mobileOpen}" @click="toggleSidebar()">
|
||||
<span class="icon-[lucide--panel-left-open]" aria-hidden="true"></span>
|
||||
<span>{label}</span>
|
||||
<div
|
||||
{...attrs}
|
||||
data-ui-component="Sidebar"
|
||||
class='wire-sidebar {class}'
|
||||
data-color='{color}'
|
||||
data-size='{size}'
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="wire-sidebar__launcher"
|
||||
aria-label='{mobileLabel}'
|
||||
aria-expanded='{drawerOpen}'
|
||||
@click='openDrawer(event)'
|
||||
>
|
||||
<span class="wire-sidebar__launcher-bar" aria-hidden="true"></span>
|
||||
<span class="wire-sidebar__launcher-text">{mobileLabel}</span>
|
||||
</button>
|
||||
<button type="button" class="wire-sidebar-backdrop" aria-label="Close navigation" @click="closeSidebar()"></button>
|
||||
<nav class="wire-next wire-next--sidebar wire-next--{orientation} wire-sidebar-panel" aria-label="{label}">
|
||||
<div class="wire-sidebar-panel__head">
|
||||
<strong>{label}</strong>
|
||||
<button type="button" aria-label="Close navigation" @click="closeSidebar()"><span class="icon-[lucide--x]" aria-hidden="true"></span></button>
|
||||
</div>
|
||||
<div class="wire-sidebar-items">
|
||||
{#each items as item}
|
||||
{#if item.children && item.children.length}
|
||||
<details class="wire-sidebar-group" name="wire-sidebar-group">
|
||||
<summary>
|
||||
{#if item.icon}<span class="{item.icon}" aria-hidden="true"></span>{/if}
|
||||
<span>{item.label}</span>
|
||||
<span class="icon-[lucide--chevron-down]" aria-hidden="true"></span>
|
||||
</summary>
|
||||
<div class="wire-sidebar-group__children">
|
||||
{#each item.children as child}
|
||||
<a href="{child.href || '#'}" aria-current="{child.value === active ? 'page' : ''}" @click="selectItem(child, 2)">
|
||||
{#if child.icon}<span class="{child.icon}" aria-hidden="true"></span>{/if}
|
||||
<span>{child.label}</span>
|
||||
|
||||
<nav class="wire-sidebar__rail" aria-label='{label}'>
|
||||
<ul class="wire-sidebar__list" data-wrn-roving="vertical">
|
||||
{#each entryList() as entry}
|
||||
<li class="wire-sidebar__entry" data-group='{isGroup(entry)}'>
|
||||
<p class="wire-sidebar__heading" data-show="entry.heading">{entry.heading}</p>
|
||||
|
||||
<a
|
||||
class="wire-sidebar__link"
|
||||
data-show="!entry.heading"
|
||||
href='{entry.href || "#"}'
|
||||
data-wrn-roving-item="true"
|
||||
data-active='{isActive(entry)}'
|
||||
aria-current='{isActive(entry) ? "page" : "false"}'
|
||||
aria-disabled='{entry.disabled ? "true" : "false"}'
|
||||
@click='choose(entry, 1)'
|
||||
>
|
||||
<span
|
||||
class='wire-sidebar__icon {entry.icon}'
|
||||
data-show="entry.icon"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<span class="wire-sidebar__label">{entry.label}</span>
|
||||
<span class="wire-sidebar__badge" data-show="entry.badge">{entry.badge}</span>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</details>
|
||||
{:else}
|
||||
<a href="{item.href || '#'}" aria-current="{item.value === active ? 'page' : ''}" @click="selectItem(item, 1)">
|
||||
{#if item.icon}<span class="{item.icon}" aria-hidden="true"></span>{/if}
|
||||
<span>{item.label}</span>
|
||||
|
||||
<ul class="wire-sidebar__sublist" data-show="childrenOf(entry).length > 0">
|
||||
{#each childrenOf(entry) as child}
|
||||
<li class="wire-sidebar__entry">
|
||||
<a
|
||||
class="wire-sidebar__link"
|
||||
href='{child.href || "#"}'
|
||||
data-active='{isActive(child)}'
|
||||
aria-current='{isActive(child) ? "page" : "false"}'
|
||||
aria-disabled='{child.disabled ? "true" : "false"}'
|
||||
@click='choose(child, 2)'
|
||||
>
|
||||
<span
|
||||
class='wire-sidebar__icon {child.icon}'
|
||||
data-show="child.icon"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<span class="wire-sidebar__label">{child.label}</span>
|
||||
<span class="wire-sidebar__badge" data-show="child.badge">{child.badge}</span>
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
<ul
|
||||
class="wire-sidebar__sublist wire-sidebar__sublist--level3"
|
||||
data-show="childrenOf(child).length > 0"
|
||||
>
|
||||
{#each childrenOf(child) as leaf}
|
||||
<li class="wire-sidebar__entry">
|
||||
<a
|
||||
class="wire-sidebar__link"
|
||||
href='{leaf.href || "#"}'
|
||||
data-active='{isActive(leaf)}'
|
||||
aria-current='{isActive(leaf) ? "page" : "false"}'
|
||||
@click='choose(leaf, 3)'
|
||||
>
|
||||
<span class="wire-sidebar__label">{leaf.label}</span>
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
</div>
|
||||
</ul>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<slot />
|
||||
</nav>
|
||||
|
||||
<Drawer
|
||||
open={drawerOpen}
|
||||
placement="left"
|
||||
title={drawerTitle}
|
||||
label={label}
|
||||
@close="closeDrawer()"
|
||||
>
|
||||
<slot name="drawer"></slot>
|
||||
</Drawer>
|
||||
</div>
|
||||
}
|
||||
|
||||
style {
|
||||
.wire-sidebar {
|
||||
--sidebar-accent: var(--wire-color-primary);
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.wire-sidebar[data-color="secondary"] {
|
||||
--sidebar-accent: var(--wire-color-secondary);
|
||||
}
|
||||
|
||||
.wire-sidebar[data-color="success"] {
|
||||
--sidebar-accent: var(--wire-color-success);
|
||||
}
|
||||
|
||||
.wire-sidebar[data-color="danger"] {
|
||||
--sidebar-accent: var(--wire-color-danger);
|
||||
}
|
||||
|
||||
.wire-sidebar[data-color="info"] {
|
||||
--sidebar-accent: var(--wire-color-info);
|
||||
}
|
||||
|
||||
.wire-sidebar[data-size="sm"] {
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.wire-sidebar[data-size="lg"] {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.wire-sidebar__rail {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wire-sidebar__list,
|
||||
.wire-sidebar__sublist {
|
||||
display: grid;
|
||||
gap: 0.1rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.wire-sidebar__sublist {
|
||||
margin-left: 0.85rem;
|
||||
padding-left: 0.5rem;
|
||||
border-left: 1px solid var(--wire-color-border);
|
||||
}
|
||||
|
||||
.wire-sidebar__entry[data-group="true"] + .wire-sidebar__entry {
|
||||
margin-top: 0.35rem;
|
||||
}
|
||||
|
||||
.wire-sidebar__heading {
|
||||
margin: 0.9rem 0 0.35rem;
|
||||
color: var(--wire-color-text-muted);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.wire-sidebar__link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.45rem 0.6rem;
|
||||
border-radius: var(--wire-radius-sm);
|
||||
color: var(--wire-color-text-muted);
|
||||
font-size: 0.88rem;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.wire-sidebar__link:hover {
|
||||
background: var(--wire-color-surface-soft);
|
||||
color: var(--wire-color-text);
|
||||
}
|
||||
|
||||
.wire-sidebar__link:focus-visible {
|
||||
outline: 2px solid var(--sidebar-accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.wire-sidebar__link[data-active="true"] {
|
||||
background: color-mix(in srgb, var(--sidebar-accent) 16%, transparent);
|
||||
color: var(--sidebar-accent);
|
||||
}
|
||||
|
||||
.wire-sidebar__link[aria-disabled="true"] {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.wire-sidebar__label {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.wire-sidebar__badge {
|
||||
margin-left: auto;
|
||||
padding: 0.05rem 0.4rem;
|
||||
border-radius: 999px;
|
||||
background: color-mix(in srgb, var(--sidebar-accent) 16%, transparent);
|
||||
color: var(--sidebar-accent);
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
.wire-sidebar__launcher {
|
||||
display: none;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.45rem 0.7rem;
|
||||
border: 1px solid var(--wire-color-border);
|
||||
border-radius: var(--wire-radius-sm);
|
||||
background: var(--wire-color-surface);
|
||||
color: var(--wire-color-text);
|
||||
font: inherit;
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wire-sidebar__launcher-bar {
|
||||
width: 1rem;
|
||||
height: 2px;
|
||||
background: currentColor;
|
||||
box-shadow:
|
||||
0 -5px 0 currentColor,
|
||||
0 5px 0 currentColor;
|
||||
}
|
||||
|
||||
/*
|
||||
* Below the tablet breakpoint the rail is replaced by the drawer launcher.
|
||||
* A permanent rail eats most of a phone screen, and Drawer already handles
|
||||
* the focus trap and the scroll lock.
|
||||
*/
|
||||
@media (max-width: 767px) {
|
||||
.wire-sidebar__launcher {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.wire-sidebar__rail {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,9 +365,12 @@ test("sidebar renders compact grouped submenu navigation and a mobile drawer tri
|
||||
],
|
||||
});
|
||||
|
||||
expect(html).toContain("wire-sidebar-toggle");
|
||||
expect(html).toContain("wire-sidebar-backdrop");
|
||||
expect(html).toContain("wire-sidebar-group");
|
||||
// Classes moved to the BEM naming every other component uses, and the
|
||||
// off-canvas presentation is now Drawer rather than a hand-rolled backdrop.
|
||||
// Nesting via children still works: that is what shipped in 0.8.5.
|
||||
expect(html).toContain("wire-sidebar__launcher");
|
||||
expect(html).toContain("wire-sidebar__sublist");
|
||||
expect(html).toContain('data-component="Drawer"');
|
||||
expect(html).toContain("Assigned cases");
|
||||
expect(html).toContain("Evidence");
|
||||
});
|
||||
@@ -2687,3 +2690,90 @@ test("tabs vertical orientation switches the roving axis", async () => {
|
||||
const dom = mountHtml(html);
|
||||
expect(dom.querySelector('[role="tablist"]')!.getAttribute("data-wrn-roving")).toBe("vertical");
|
||||
});
|
||||
|
||||
test("mega menu renders column groups in an anchored panel", async () => {
|
||||
const source = readFileSync(uiComponentPath("MegaMenu"), "utf8");
|
||||
const html = await renderComponent(source, {
|
||||
label: "Products",
|
||||
columns: [
|
||||
{
|
||||
heading: "Platform",
|
||||
items: [
|
||||
{ label: "Runtime", href: "/runtime", description: "The browser half" },
|
||||
{ label: "Compiler", href: "/compiler" },
|
||||
],
|
||||
},
|
||||
{ heading: "Company", items: [{ label: "About", href: "/about" }] },
|
||||
],
|
||||
});
|
||||
const dom = mountHtml(html);
|
||||
|
||||
const trigger = dom.querySelector(".wire-mega__trigger") as HTMLElement;
|
||||
expect(trigger.getAttribute("aria-expanded")).toBe("false");
|
||||
expect(trigger.getAttribute("aria-haspopup")).toBe("true");
|
||||
|
||||
const panel = dom.querySelector(".wire-mega__panel") as HTMLElement;
|
||||
expect(panel.getAttribute("data-wrn-anchored")).toBe("true");
|
||||
expect(dom.querySelectorAll(".wire-mega__column")).toHaveLength(2);
|
||||
expect(dom.querySelectorAll(".wire-mega__link").length).toBeGreaterThanOrEqual(3);
|
||||
expect(dom.querySelector(".wire-mega__heading")!.textContent).toContain("Platform");
|
||||
// Single level by design: a mega panel shows breadth flat, so there is no
|
||||
// nested submenu markup to find.
|
||||
expect(source).not.toContain("wire-mega__submenu");
|
||||
});
|
||||
|
||||
test("mega menu columns take roving focus and survive an empty column list", async () => {
|
||||
const source = readFileSync(uiComponentPath("MegaMenu"), "utf8");
|
||||
const html = await renderComponent(source, { label: "Empty", columns: [] });
|
||||
const dom = mountHtml(html);
|
||||
expect(dom.querySelector(".wire-mega")).not.toBeNull();
|
||||
expect(dom.querySelectorAll(".wire-mega__link")).toHaveLength(0);
|
||||
expect(dom.querySelector('[data-wrn-roving="both"]')).not.toBeNull();
|
||||
});
|
||||
|
||||
test("sidebar renders single items, labelled groups and nested levels", async () => {
|
||||
const source = readFileSync(uiComponentPath("Sidebar"), "utf8");
|
||||
const html = await renderComponent(source, {
|
||||
label: "Workspace",
|
||||
items: [
|
||||
{ label: "Dashboard", href: "/", value: "dash", icon: "icon-[lucide--gauge]" },
|
||||
{
|
||||
heading: "Projects",
|
||||
items: [
|
||||
{ label: "Active", href: "/active", value: "active" },
|
||||
{
|
||||
label: "Archive",
|
||||
value: "archive",
|
||||
items: [{ label: "2025", href: "/a/2025", value: "a2025" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
active: "active",
|
||||
});
|
||||
const dom = mountHtml(html);
|
||||
|
||||
expect(dom.querySelector(".wire-sidebar")).not.toBeNull();
|
||||
// Every entry renders a heading node; only group entries fill it in, so
|
||||
// match on content rather than first-in-document.
|
||||
const headings = [...dom.querySelectorAll(".wire-sidebar__heading")]
|
||||
.map((node) => node.textContent!.trim())
|
||||
.filter(Boolean);
|
||||
expect(headings).toContain("Projects");
|
||||
expect(dom.querySelector('[aria-current="page"]')!.textContent).toContain("Active");
|
||||
expect(dom.querySelector(".wire-sidebar__icon")).not.toBeNull();
|
||||
// Third level exists and is reachable.
|
||||
const deep = [...dom.querySelectorAll(".wire-sidebar__sublist--level3")]
|
||||
.map((n) => n.textContent!.trim())
|
||||
.filter(Boolean);
|
||||
expect(deep.join(" ")).toContain("2025");
|
||||
expect(dom.querySelector('[data-wrn-roving="vertical"]')).not.toBeNull();
|
||||
});
|
||||
|
||||
test("sidebar composes Drawer for its off-canvas presentation", async () => {
|
||||
const source = readFileSync(uiComponentPath("Sidebar"), "utf8");
|
||||
// Reusing Drawer means the focus trap and scroll lock come for free rather
|
||||
// than being reimplemented here.
|
||||
expect(source).toContain('import Drawer from "./Drawer.wrn"');
|
||||
expect(source).toContain("<Drawer");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user