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:
@@ -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.",
|
||||
{
|
||||
items: [
|
||||
label: "Products",
|
||||
icon: "icon-[lucide--box]",
|
||||
columns: [
|
||||
{
|
||||
label: "Overview",
|
||||
value: "overview",
|
||||
title: "Overview",
|
||||
description: "What the product does and who it is for.",
|
||||
heading: "Platform",
|
||||
items: [
|
||||
{
|
||||
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.",
|
||||
{
|
||||
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: "Solutions",
|
||||
columns: [
|
||||
{
|
||||
heading: "By team",
|
||||
items: [
|
||||
{ label: "Engineering", href: "/eng", icon: "icon-[lucide--code]" },
|
||||
{ label: "Design", href: "/design", icon: "icon-[lucide--palette]" },
|
||||
{ label: "Support", href: "/support", icon: "icon-[lucide--life-buoy]" },
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "By size",
|
||||
items: [
|
||||
{ label: "Startup", href: "/startup" },
|
||||
{ label: "Enterprise", href: "/enterprise" },
|
||||
],
|
||||
},
|
||||
],
|
||||
active: "account",
|
||||
mode: "url",
|
||||
param: "tab",
|
||||
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: "Archive",
|
||||
value: "archive",
|
||||
items: [
|
||||
{ label: "2025", href: "/a/2025", value: "a2025" },
|
||||
{ label: "2024", href: "/a/2024", value: "a2024" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
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.",
|
||||
heading: "Account",
|
||||
items: [
|
||||
{
|
||||
label: "Settings",
|
||||
href: "/settings",
|
||||
value: "settings",
|
||||
icon: "icon-[lucide--settings]",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
active: "security",
|
||||
orientation: "vertical",
|
||||
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.",
|
||||
|
||||
Reference in New Issue
Block a user