entasis 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/components/AIAskUserQuestion/aiAskUserQuestion.theme.js +1 -1
  2. package/dist/components/AIChat/aiChat.theme.js +2 -2
  3. package/dist/components/AIComposer/aiComposer.theme.js +2 -2
  4. package/dist/components/AIContext/aiContext.theme.js +2 -2
  5. package/dist/components/AIFilePreview/aiFilePreview.theme.js +1 -1
  6. package/dist/components/AIMarker/aiMarker.theme.js +2 -2
  7. package/dist/components/AIMessage/aiMessage.theme.js +2 -2
  8. package/dist/components/AIMessageActions/aiMessageActions.theme.js +1 -1
  9. package/dist/components/AIModelSelector/aiModelSelector.theme.js +1 -1
  10. package/dist/components/AIReasoning/aiReasoning.theme.js +1 -1
  11. package/dist/components/AISuggestion/aiSuggestion.theme.js +1 -1
  12. package/dist/components/AIThread/aiThread.theme.js +2 -2
  13. package/dist/components/AIThreadToc/aiThreadToc.theme.js +1 -1
  14. package/dist/components/AITool/aiTool.theme.js +2 -2
  15. package/dist/components/AudioPlayer/audioPlayer.theme.js +2 -2
  16. package/dist/components/Avatar/avatarGroup.theme.js +1 -1
  17. package/dist/components/Button/button.mcp.d.ts +1 -1
  18. package/dist/components/Button/button.mcp.js +2 -2
  19. package/dist/components/ButtonGroup/buttonGroup.theme.js +1 -1
  20. package/dist/components/DocumentViewer/documentViewer.theme.js +1 -1
  21. package/dist/components/EventCalendar/eventCalendar.theme.js +1 -1
  22. package/dist/components/Form/ColorInput/colorInput.theme.js +2 -2
  23. package/dist/components/Form/ColorPicker/colorPicker.theme.js +2 -2
  24. package/dist/components/Form/DateInput/dateInput.theme.js +2 -2
  25. package/dist/components/Form/DateSelector/dateSelector.theme.js +1 -1
  26. package/dist/components/Form/File/fileInput.theme.js +2 -2
  27. package/dist/components/Form/KeyValueInput/keyValueInput.theme.js +2 -2
  28. package/dist/components/Form/MultiStepForm/multiStepForm.theme.js +1 -1
  29. package/dist/components/Form/NumberInput/numberInput.theme.js +2 -2
  30. package/dist/components/Form/PasswordInput/passwordInput.theme.js +2 -2
  31. package/dist/components/Form/PhoneInput/phoneInput.theme.js +2 -2
  32. package/dist/components/Form/PinInput/pinInput.theme.js +2 -2
  33. package/dist/components/Form/TagsInput/tagsInput.theme.js +2 -2
  34. package/dist/components/Form/TextArea/textArea.theme.js +2 -2
  35. package/dist/components/Form/TextInput/textInput.theme.js +2 -2
  36. package/dist/components/Form/TimeInput/timeInput.theme.js +2 -2
  37. package/dist/components/Form/VoiceInput/voiceInput.theme.js +2 -2
  38. package/dist/components/GanttChart/ganttChart.theme.js +2 -2
  39. package/dist/components/Grid/gridSpan.theme.js +2 -2
  40. package/dist/components/MediaVolume/mediaVolumeControl.theme.js +1 -1
  41. package/dist/components/MenuBar/menuBar.theme.js +2 -2
  42. package/dist/components/MenuOption/menuOption.theme.js +2 -2
  43. package/dist/components/MetadataList/metadataList.theme.js +2 -2
  44. package/dist/components/MiniCalendar/miniCalendar.theme.js +2 -2
  45. package/dist/components/NetworkIndicator/networkIndicator.mcp.d.ts +1 -1
  46. package/dist/components/NetworkIndicator/networkIndicator.mcp.js +1 -1
  47. package/dist/components/NetworkIndicator/networkIndicator.theme.js +2 -2
  48. package/dist/components/QRCode/qrCode.theme.js +2 -2
  49. package/dist/components/RichTextInput/richTextInput.theme.js +2 -2
  50. package/dist/components/ScrollArea/scrollArea.theme.js +2 -2
  51. package/dist/components/SegmentedControl/segmentedControl.theme.js +1 -1
  52. package/dist/components/SelectionMenu/selectionMenu.theme.js +1 -1
  53. package/dist/components/Sidebar/sidebar.mcp.d.ts +1 -1
  54. package/dist/components/Sidebar/sidebar.mcp.js +23 -1
  55. package/dist/components/Sidebar/sidebar.theme.js +42 -43
  56. package/dist/components/SortableList/sortableList.theme.js +2 -2
  57. package/dist/components/SpinnerText/spinnerText.mcp.d.ts +1 -1
  58. package/dist/components/SpinnerText/spinnerText.mcp.js +1 -1
  59. package/dist/components/SpinnerText/spinnerText.theme.js +2 -2
  60. package/dist/components/ToggleButton/toggleButton.theme.js +1 -1
  61. package/dist/components/ToggleButtonGroup/toggleButtonGroup.theme.js +1 -1
  62. package/dist/components/ToggleMenu/toggleMenu.theme.js +2 -2
  63. package/dist/components/VideoPlayer/videoPlayer.theme.js +2 -2
  64. package/dist/generated/componentMcpRegistry.d.ts +4 -4
  65. package/package.json +1 -1
@@ -25,8 +25,8 @@ export declare const componentMcpRegistry: {
25
25
  readonly stack: "\n# Stack\n\nStack arranges arbitrary content along one flex axis. Use the `orientation` prop to switch\nbetween horizontal and vertical layout, and `align` / `justify` for cross-axis and main-axis\nalignment.\n\n## Import\n\n```svelte\n<script lang=\"ts\">\n import { Stack } from '../components/Stack/index.ts';\n</script>\n```\n\n## Usage\n\n```svelte\n<Stack gap=\"xl\" padding=\"xl\">\n <h2>Account</h2>\n <Stack orientation=\"horizontal\" align=\"center\" gap=\"md\" wrap=\"wrap\">\n <span>Profile</span>\n <span>Security</span>\n </Stack>\n</Stack>\n```\n\n## Responsive props\n\n`orientation`, `gap`, `align`, `justify` and `wrap` each take a plain value or a\nper-breakpoint record:\n\n```svelte\n<Stack orientation={{ md: 'horizontal' }} gap={{ xs: 'sm', lg: 'xl' }} align=\"center\">\n <span>Filters</span>\n <span>Results</span>\n</Stack>\n```\n\nThe breakpoints measure the stack's OWN width — `xs` base, `sm` 36rem, `md` 42rem,\n`lg` 56rem, `xl` 72rem — not the viewport's, so the same stack is `xs` in a narrow sidebar\nand `lg` full-bleed on the same page. The nearest defined key at or below the stack's width\nwins, and below the narrowest key the prop's default applies: `{ md: 'horizontal' }` is\nvertical at `xs` and `sm`. A prop falls back to its default only when it is `undefined`\nor `null`. A function form must be deterministic in its argument — it is called once per\nbreakpoint. There is no measurement and no JS: the five values ship as custom\nproperties and container queries pick one, so server-rendered markup is already laid out.\n\n## Props\n\n- `orientation`: `'horizontal' | 'vertical'` — flex direction (default: `'vertical'`).\n- `align`: cross-axis alignment — `start | center | end | stretch` (default: `'stretch'`).\n- `justify`: main-axis alignment — `start | center | end | between | around | evenly` (default: `'start'`).\n- `gap`, `padding`, `paddingInline`, and `paddingBlock` accept\n `none | xs | sm | md | lg | xl`.\n- `paddingInline` and `paddingBlock` override `padding` on their axis.\n- `width`, `height`, `maxWidth`, and `minHeight` accept CSS strings or pixel numbers.\n- `wrap` accepts `nowrap | wrap | wrap-reverse`.\n- `scrollable` enables native `overflow: auto`.\n- `as` changes the semantic HTML element without changing layout behavior:\n `div | span | section | article | aside | main | nav | header | footer | form | fieldset`.\n Lists are not among them — the root always wraps its children in one layout `<div>`, which\n `<ul>` and `<ol>` do not admit. Write the list yourself and put a stack inside an `<li>`.\n\n## Structure\n\nStack renders two elements: the root (`data-slot=\"stack\"`) is the box the host sizes and the\ncontainer the breakpoints are measured against — it takes `as`, `class`, `style`, the size\nprops, the padding and `scrollable` — and a single layout child (`data-slot=\"stack-layout\"`)\ncarries the flex line. The `inner` theme slot styles that child.\n\nStack forwards common semantic HTML attributes and Svelte attachments to the root element.\nPrefer parent-owned `gap` over child margins. The internal `micro` and `layout-*` tokens are\nreserved for component recipes and must not be used in generated interfaces.\n";
26
26
  readonly 'app-shell': "\n# AppShell Component\n\nConvenience wrapper for the common application layout: Sidebar owns navigation,\nresponsive drawer behavior, the application wall, and variant surfaces, while PageShell\nowns the page header, document-flow content, footer, and route-level injection. AppShell\nforwards one shared variant to Sidebar and composes PageShell inside it.\nAppShell establishes a dynamic viewport-height minimum while letting the document own\nvertical scrolling. The desktop sidebar remains sticky independently of page content.\n\nUse AppShell when every route follows the same sidebar + page shell structure. Use\nSidebar and PageShell directly when the frame needs custom composition.\n\n## Basic Usage\n\n```svelte\n<script lang=\"ts\">\n\timport { AppShell, type AppShellSidebarProps } from 'entasis/app-shell';\n\timport { houseIcon } from 'entasis/icons/house';\n\n\tconst sidebar: AppShellSidebarProps = {\n\t\tcollapsible: 'icon',\n\t\trail: true,\n\t\titems: [\n\t\t\t{\n\t\t\t\tlabel: 'Workspace',\n\t\t\t\titems: [{ label: 'Home', href: '/', icon: houseIcon, isActive: true }]\n\t\t\t}\n\t\t]\n\t};\n</script>\n\n<AppShell variant=\"framed\" {sidebar} title=\"Dashboard\" subtitle=\"Operational overview\">\n\t{#snippet children({ sidebar })}\n\t\t<button type=\"button\" onclick={sidebar.toggle}>Toggle sidebar</button>\n\t{/snippet}\n</AppShell>\n```\n\n## Route-Level Injection\n\nAppShell renders PageShell internally, so child pages can use the PageShell context API:\n\n```svelte\n<script lang=\"ts\">\n\timport { setPageShell } from 'entasis/page-shell';\n\n\tsetPageShell({\n\t\ttitle: 'Insights',\n\t\tsubtitle: 'Revenue and retention',\n\t\tfooter: pageFooter\n\t});\n</script>\n\n{#snippet pageFooter()}\n\t<span>Synced just now</span>\n{/snippet}\n```\n\n## Props\n\n- **variant**: 'admin' | 'floating' | 'inset' | 'split' | 'framed' - Shared shell treatment forwarded to Sidebar and PageShell chrome. Admin chrome uses the Sidebar canvas surface; floating chrome uses detached raised, rounded surfaces. `framed` draws one rounded card (`rounded-xl` + `raised-1`, so the border and elevation come from the elevation engine) around both the sidebar and the page; the Sidebar's own `framed` variant paints its navigation well as `surface-recessed`, an inset of that card, and the page header sits on the page surface.\n- **sidebar**: AppShellSidebarProps - Sidebar props except `children`, `mode`, `frame`, and `variant`.\n Configure Sidebar `size` and `density` independently inside this object.\n- **eyebrow**: string | Snippet<[PageShellApi]> - Small metadata above the PageShell title.\n- **breadcrumbs**: BreadcrumbItem[] | Snippet<[AppShellApi]> - PageShell breadcrumbs.\n- **breadcrumbsMaxItems**: number - Maximum visible breadcrumb items before ellipsis. Defaults to 4.\n- **back**: PageShellAction | Snippet<[AppShellApi]> - Back affordance before breadcrumbs or eyebrow.\n- **title**: string | Snippet<[PageShellApi]> - Default PageShell title.\n- **subtitle**: string | Snippet<[PageShellApi]> - Default PageShell subtitle.\n- **header**: Snippet<[PageShellApi]> - Custom PageShell header.\n- **headerActions**: Snippet<[AppShellApi]> | PageShellAction[] - Actions in the default PageShell header. Use an array for standard Button props, or a snippet when the action needs sidebar/page-shell API access.\n- **footer**: Snippet<[PageShellApi]> - PageShell footer.\n- **footerActions**: Snippet<[AppShellApi]> | PageShellAction[] - PageShell footer actions.\n- **children**: Snippet<[AppShellApi]> - Main content, with `pageShell` and `sidebar` APIs.\n- **contentPadding**: 'none' | 'small' | 'normal' | 'large' - PageShell content padding preset.\n- **contentWidth**: 'full' | 'narrow' | 'normal' | 'wide' | 'prose' - PageShell content width preset.\n- **pageShellTheme**: PageShellThemeProps - PageShell theme overrides.\n- **theme**: AppShellThemeProps - AppShell `root`, `frame` and `page` surface-token overrides. Sidebar owns the wall and shell geometry.\n\n## Accessibility\n\nAppShell delegates navigation semantics to Sidebar and page landmarks to PageShell.\nUse string `title` for the default `h1`, or preserve heading semantics when replacing\nthe PageShell header with a custom snippet.\n";
27
27
  readonly 'page-shell': "\n# PageShell Component\n\nContent shell for pages rendered inside an application frame. PageShell provides a\nsticky header and footer, document-flow content, title/subtitle props, and a context\nAPI for child routes to inject shell content. Scrolling stays on the document by default,\nso browser navigation and scroll restoration keep their native behavior.\n\nUse PageShell inside `Sidebar.children` when Sidebar owns navigation and responsive\ndrawer behavior.\n\n## Basic Usage\n\n```svelte\n<script lang=\"ts\">\n\timport { PageShell, type PageShellAction } from 'entasis/page-shell';\n\timport { downloadSimpleIcon } from 'entasis/icons/downloadSimple';\n\n\tconst headerActions = [\n\t\t{\n\t\t\tcontent: 'Export',\n\t\t\tcolor: 'primary',\n\t\t\tprefix: downloadSimpleIcon\n\t\t}\n\t] satisfies PageShellAction[];\n</script>\n\n<PageShell title=\"Insights\" subtitle=\"Live account health\" {headerActions}>\n\t{#snippet footer()}\n\t\t<span>Updated just now</span>\n\t{/snippet}\n\n\t{#snippet children()}\n\t\t<section class=\"p-6\">Page content</section>\n\t{/snippet}\n</PageShell>\n```\n\n## Route-Level Injection\n\nChild pages can set header and footer content through context. Use `setPageShell`\nduring component initialization for automatic cleanup.\n\n```svelte\n<script lang=\"ts\">\n\timport { setPageShell } from 'entasis/page-shell';\n\n\tsetPageShell({\n\t\ttitle: 'Revenue',\n\t\tsubtitle: 'Segment breakdown',\n\t\theaderActions: revenueActions,\n\t\tfooter: revenueFooter\n\t});\n</script>\n\n{#snippet revenueActions()}\n\t<button type=\"button\">Refresh</button>\n{/snippet}\n\n{#snippet revenueFooter()}\n\t<span>Synced 2 minutes ago</span>\n{/snippet}\n```\n\n## Props\n\n- **eyebrow**: string | Snippet<[PageShellApi]> - Small metadata above the title. Ignored when breadcrumbs are set.\n- **breadcrumbs**: BreadcrumbItem[] | Snippet<[PageShellApi]> - Default-header breadcrumbs.\n- **breadcrumbsMaxItems**: number - Maximum visible breadcrumb items before ellipsis. Defaults to 4.\n- **back**: PageShellAction | Snippet<[PageShellApi]> - Back affordance before breadcrumbs or eyebrow.\n- **title**: string | Snippet<[PageShellApi]> - Default header title.\n- **subtitle**: string | Snippet<[PageShellApi]> - Default header subtitle.\n- **header**: Snippet<[PageShellApi]> - Custom sticky header content.\n- **headerActions**: Snippet<[PageShellApi]> | PageShellAction[] - Actions on the right side of the default header. Use an array for standard Button props, or a snippet when the action needs shell API access.\n- **footer**: Snippet<[PageShellApi]> - Custom sticky footer content.\n- **footerActions**: Snippet<[PageShellApi]> | PageShellAction[] - Actions on the right side of the sticky footer.\n\t- **children**: Snippet<[PageShellApi]> - Page content rendered in normal document flow.\n\t- **contentPadding**: 'none' | 'small' | 'normal' | 'large' - Padding applied to the content inner wrapper.\n\t- **contentWidth**: 'full' | 'narrow' | 'normal' | 'wide' | 'prose' - Max-width preset for the content inner wrapper.\n\t- **actionOverflow**: 'auto' | 'never' - Mobile overflow behavior for action arrays.\n\t- **mobileActionCount**: 0 | 1 | 2 - Number of action-array buttons kept inline on mobile.\n\t- **label**: string - Accessible name for the page's `main` landmark, applied as aria-label.\n\t- **theme**: PageShellThemeProps - Per-instance theme overrides.\n\n## API\n\n- **usePageShell()** returns the current PageShell API and throws when no PageShell exists.\n- **setPageShell(config)** registers a scoped config override and removes it on component destroy.\n- **api.set(config)** pushes a manual override and returns a cleanup function.\n- **api.setFooterActions(actions)** pushes scoped page footer actions.\n- **api.reset()** clears all scoped overrides.\n\n## Header Action Arrays\n\n```svelte\n<script lang=\"ts\">\n\timport { PageShell, type PageShellAction } from 'entasis/page-shell';\n\timport { arrowClockwiseIcon } from 'entasis/icons/arrowClockwise';\n\n\tconst headerActions = [\n\t\t{\n\t\t\tlabel: 'Refresh',\n\t\t\tsquared: true,\n\t\t\tvariant: 'outline',\n\t\t\tprefix: arrowClockwiseIcon\n\t\t},\n\t\t{\n\t\t\tcontent: 'Create report',\n\t\t\tcolor: 'primary'\n\t\t}\n\t] satisfies PageShellAction[];\n</script>\n\n<PageShell title=\"Reports\" {headerActions}>\n\t{#snippet children()}\n\t\tPage content\n\t{/snippet}\n</PageShell>\n```\n\n## Content Presets And Footer Actions\n\n```svelte\n<PageShell\n\teyebrow=\"Settings\"\n\ttitle=\"Billing profile\"\n\tcontentPadding=\"normal\"\n\tcontentWidth=\"narrow\"\n\tfooterActions={[\n\t\t{ content: 'Cancel', variant: 'outline' },\n\t\t{ content: 'Save changes', color: 'primary' }\n\t]}\n>\n\t{#snippet footer()}\n\t\t<span>2 unsaved changes</span>\n\t{/snippet}\n\n\t{#snippet children()}\n\t\t<form>...</form>\n\t{/snippet}\n</PageShell>\n```\n\n## Accessibility\n\nPageShell renders semantic `header`, `main`, and `footer` regions. The title is an\n`h1` when provided as a string. Custom snippets are responsible for preserving\nequivalent semantics when replacing the default header.\n";
28
- readonly sidebar: "\n# Sidebar Component\n\nSidebar navigation with data-driven groups, icon collapse, mobile drawer behavior,\nrecursive tree groups, header/footer rows, search, actions, and snippet escape hatches.\n\n## Import\n\n```svelte\n<script lang=\"ts\">\n\timport { Sidebar, type SidebarGroup } from 'entasis/sidebar';\n</script>\n```\n\n## Basic Usage\n\n```svelte\n<script lang=\"ts\">\n\timport { Sidebar, type SidebarGroup } from 'entasis/sidebar';\n\timport { houseIcon } from 'entasis/icons/house';\n\timport { gearIcon } from 'entasis/icons/gear';\n\n\tconst items: SidebarGroup[] = [\n\t\t{\n\t\t\tlabel: 'Workspace',\n\t\t\titems: [\n\t\t\t\t{ label: 'Dashboard', href: '/', icon: houseIcon, isActive: true },\n\t\t\t\t{ label: 'Settings', href: '/settings', icon: gearIcon }\n\t\t\t]\n\t\t}\n\t];\n</script>\n\n<Sidebar items={items}>\n\t{#snippet children({ toggle })}\n\t\t<header>\n\t\t\t<button type=\"button\" onclick={toggle}>Toggle</button>\n\t\t</header>\n\t\t<main>Page content</main>\n\t{/snippet}\n</Sidebar>\n```\n\n## AI-Safe Usage Contract\n\n1. Use `items` for normal navigation. Use `content` only when data-driven rows cannot express the layout.\n2. Use local Entasis icon snippets such as `houseIcon`, not Lucide component constructors.\n3. Use `MenuItem[]` from `entasis/menu` for `menu` and action dropdowns.\n4. Do not combine `menu` with `href` or `onclick` on the same row; use `action` for a trailing row menu.\n5. Keep `children`, `header`, `content`, `footer`, `banner`, and action snippets pure; they receive `SidebarApi`.\n6. Use `collapsible=\"icon\"` for icon rail behavior, `collapsible=\"offcanvas\"` for hidden desktop panels, and `collapsible=\"none\"` for fixed sidebars. Icon collapse automatically falls back to offcanvas when any data-driven row lacks an icon.\n7. Offcanvas sidebars reveal over the content from the screen edge by default when hidden; set `edgeReveal={false}` to disable that. A revealed hidden sidebar keeps its resize handle and dismisses through a small rectangular pointer tolerance.\n8. Set `keyboardShortcut={false}` when embedding Sidebar inside another shortcut-heavy surface.\n9. Sidebar owns navigation, resize mechanics, the lower application wall, and variant surface geometry. AppShell forwards its variant and composes PageShell inside that surface.\n10. Use `size` for typography, icon scale, and item height. Use `density` independently for section padding, gaps, and submenu spacing.\n11. Use `activityBar` for a persistent icon rail outside the panel (section switching, workspaces). Every item needs an `icon` and a `label`; the label is the accessible name and the tooltip. It is layout mode only: `mode=\"panel\"` renders the navigation panel alone.\n12. Use `expandOnHover` only with `collapsible=\"icon\"`. It is a temporary peek, not a toggle: the persisted collapsed state never changes, while the peeked panel renders with expanded semantics.\n\n## Data Model\n\n### SidebarGroup\n- **label**: string - Group label, hidden in icon-collapsed mode.\n- **items**: SidebarMenuEntry[] - Menu rows.\n- **tree**: SidebarTreeNode[] - Recursive tree rows instead of menu items.\n- **action**: SidebarMenuActionDescriptor | SidebarMenuActionDescriptor[] | Snippet<[SidebarApi]> - Top-right group actions. Pass an array to pin several affordances (a `+` and a drag handle) to one group header; each renders as its own icon-only ghost button.\n- **collapsible**: boolean - Makes the group label a toggle.\n- **defaultOpen**: boolean - Initial collapsible group state.\n- **separator**: boolean - Divider before the group.\n\n### SidebarMenuEntry\n- **label**: string - Visible row label.\n- **icon**: SidebarIcon - Entasis icon snippet or string.\n- **iconColor**: Colors - Role tint for the leading icon, applied through `data-color`.\n- **iconVariant**: 'bare' | 'tile' - Leading icon treatment. `tile` paints a rounded square (`bg-color-muted text-color-muted-readable`) around the glyph, so per-project colour chips come from the role scale instead of hand-built markup.\n- **href**: string - Render as an anchor. Mutually exclusive with menu.\n- **onclick**: (event: MouseEvent) => void - Native click handler for button or anchor rows. Mutually exclusive with menu.\n- **isActive**: boolean - Adds active styling and `aria-current=\"page\"`.\n- **disabled**: boolean - Disables button rows and marks anchor rows disabled.\n- **badge**: string | number - Trailing count/status, hidden in icon mode.\n- **tooltip**: string - Entasis Tooltip content in icon mode. Defaults to label.\n- **items**: SidebarMenuSubEntry[] - Inline nested menu.\n- **collapsible**: boolean - Set false for an always-open submenu.\n- **defaultOpen**: boolean - Initial nested menu state.\n- **menu**: MenuItem[] - Popup menu opened from the full row. Mutually exclusive with href/onclick.\n- **action**: SidebarMenuActionDescriptor | Snippet<[SidebarApi]> - Hover/focus trailing action.\n\n### SidebarActivityBar\nIcon rail pinned to the outer edge of the sidebar, visible in every display state.\n- **items**: SidebarActivityBarItem[] - Items rendered from the top.\n- **footerItems**: SidebarActivityBarItem[] - Items pinned to the end of the column.\n- **header** / **footer**: Snippet - Custom content before the first item and after the pinned ones.\n- **width**: string (default '3rem') - Column thickness, published as `--sidebar-width-activity`.\n- **label**: string - Accessible name for the column landmark. Set it whenever the panel also renders navigation.\n- **onSelect**: ({ item, index }) => void - Fires after an item is activated. `index` counts `items` then `footerItems`.\n\n### SidebarActivityBarItem\n- **icon**: SidebarIcon (required) - Icon rendered in the square.\n- **label**: string (required) - Accessible name and default tooltip; the square shows no text.\n- **id**: string - Stable render key.\n- **href** / **target** / **rel** - Render an anchor instead of a button.\n- **onclick**: (event: MouseEvent) => void - Native click handler.\n- **isActive**: boolean - Adds active styling and `aria-current=\"page\"`.\n- **badge**: string | number | Snippet - Corner badge pinned to the outer top corner. An empty string renders a bare dot. A string or number badge joins the accessible name (`\"Alerts, 3\"`); a dot and a Snippet badge are decorative, so put their meaning in `label`.\n- **disabled**: boolean - Blocks activation and skips the item during keyboard navigation.\n- **tooltip**: string | false - Tooltip override; `false` suppresses it.\n\n### SidebarMenuButtonItem\nUse for `headerButton`, `footerButton`, or direct `<SidebarMenuButton />` rows.\n- **icon**: SidebarIcon - Leading logo/icon.\n- **avatar**: { src?: string; alt?: string; fallback?: string } - Leading avatar.\n- **variant**: 'default' | 'brand' | 'compact'.\n- **title**: string - Primary text.\n- **subtitle**: string - Secondary text.\n- **trailing**: SidebarIcon | false | SidebarMenuActionDescriptor - Trailing content. An icon is decorative; an action descriptor (`{ icon, label, onclick }`, the same shape as a group action) renders its own icon-only ghost button beside the row, so a workspace card can carry its own collapse control without a custom `header` snippet. Descriptor handlers are `onclick(event, api)`, so `api.toggle()` is reachable.\n- **href** / **onclick** / **menu** - Choose link, button, or popup behavior. `onclick(event, api)` receives the SidebarApi beside the event, so `api.toggle()` is reachable from the row itself.\n- **menuIconClass**: string - Class override for option icons inside the popup menu.\n\n## Props\n\n### State\n- **open**: boolean (bindable, default true) - Desktop expanded state.\n- **defaultOpen**: boolean (default true) - Initial desktop state when `open` is omitted.\n- **onOpenChange**: (open: boolean) => void - Called once for a library-originated desktop state change. Repeated requests and parent prop updates stay silent.\n- **onDisplayStateChange**: (state: SidebarDisplayState) => void - Called once for a library-originated semantic display-state change.\n- **api.displayState**: 'expanded' | 'collapsed' | 'hidden' - Semantic desktop state; hidden means closed offcanvas. A hover peek does not change it.\n- **api.isPeeking**: boolean - True while a hover peek renders the collapsed panel at full width. Read it alongside `displayState` when a snippet hides content in icon mode.\n- **keyboardShortcut**: string | false (default 'b') - Ctrl/Cmd shortcut key.\n\n### Layout\n- **side**: 'left' | 'right' - Desktop and mobile side.\n- **variant**: 'admin' | 'floating' | 'inset' | 'split' | 'framed' - Sidebar geometry. `framed` is the admin geometry for a sidebar hosted inside a raised card (AppShell variant framed), with a `surface-recessed` well. `admin` renders the conventional full-height navigation column; `inset` integrates navigation into the lower wall with an inset content surface; `split` renders detached sidebar and content surfaces.\n- **size**: 'small' | 'normal' | 'large' (default 'normal') - Typography, icon, avatar, badge, leading-media, item-height, and search-height scale.\n- **iconSize**: 'small' | 'normal' | 'large' - Icon and leading-media scale inside the panel on its own; defaults to `size`. Menu rows, sub rows, group labels and the header button follow it; the activity bar keeps `size`.\n- **activeVariant**: 'soft' | 'outline' | 'solid' (default 'soft') - How active rows are painted. `soft` is the shared selected recipe (`selectedSoft`: `bg-selected-muted text-selected-muted-readable`), `solid` its loud counterpart (`selectedSolid`: `bg-selected text-selected-contrast`), `outline` a bordered surface card (`bg-surface border border-neutral-muted text-neutral`) that reads as a raised card on a tinted well. Each row carries the choice as `data-active-variant`, so no descendant selector is needed to restyle selection.\n- **density**: 'compact' | 'normal' | 'comfortable' (default 'normal') - Section padding, group padding, gaps, horizontal inset, and submenu spacing.\n- **collapsible**: 'offcanvas' | 'icon' | 'none' - Collapse behavior. Icon mode requires icons on every data-driven row and otherwise resolves to offcanvas.\n- **collapseIcon**: DisclosureIndicator — 'chevron' | 'plus-minus' | 'none' (default 'chevron') - Disclosure indicator drawn on collapsible menu rows. 'none' renders no indicator.\n- **mode**: 'layout' | 'panel' - Full resizing layout or only the visible navigation panel.\n- **frame**: 'viewport' | 'contained' - Standalone Sidebar positioning. Viewport mode uses Theme's dynamic window-height token; contained mode fills a positioned parent.\n- **width**: string - Expanded width.\n- **widthIcon**: string - Icon-collapsed width.\n- **widthMobile**: string - Mobile drawer width.\n- **rail**: boolean | 'line' | 'thumb' - Edge toggle rail. `true` keeps the thin line style; `thumb` renders a short visible handle with the same full-height hitbox. The appearance is preserved when the rail shares the resize control.\n- **activityBar**: SidebarActivityBar - Icon rail pinned outside the panel, in layout mode only (`mode=\"panel\"` renders the panel alone and ignores it). It never slides off screen: only the panel takes the offcanvas offset, and the reserved layout column is the panel width plus the rail width. On mobile it renders as a horizontal row at the top of the drawer.\n- **expandOnHover**: boolean (default false) - With `collapsible=\"icon\"`, hovering or focusing into the collapsed panel expands it to `width` over the page (`data-peek=\"true\"`) while the reserved column stays at `widthIcon`, so page content does not reflow. The persisted collapsed state is untouched, and the peeked panel renders exactly like an expanded one: group headers, badges, search, inline submenus, and inline tree branches all come back, and the rail or resize handle travels to its inner edge.\n- **edgeReveal**: boolean (default true) - Pointer/focus edge preview for hidden offcanvas sidebars. Hover reveal overlays content, remains resizable when configured, and re-hides after the pointer leaves its small rectangular tolerance. Dragging the sidebar closed suppresses immediate hover reopening until the pointer leaves the edge trigger; toggle/click opens persistently.\n- **resizable**: boolean | SidebarResizableOptions - Enables pointer and keyboard resizing while expanded, icon-collapsed, or temporarily edge-revealed. By default, collapse requires dragging 75% of `minWidth` beyond the minimum; override `collapseThreshold` for a custom boundary. Use `storageKey` to restore and persist the expanded width across sessions.\n - `onWidthChange({ width, isUserInteraction })` reports every expanded-width change with one named payload: continuously while the user resizes (`isUserInteraction: true`) and once when a stored width is restored (`isUserInteraction: false`).\n\n### Content\n- **items**: SidebarGroup[] - Data-driven body navigation.\n- **headerButton** / **footerButton**: SidebarMenuButtonItem - Sticky large rows.\n- **search**: SidebarSearch - Header search input; use its native `oninput` handler.\n- **headerMenu** / **footerMenu**: SidebarMenuEntry[] - Sticky quick menus.\n- Menu entries and nested entries accept `size: 'small' | 'normal' | 'large'` for row geometry.\n- **header**, **content**, **footer**, **children**, **banner**: Snippet<[SidebarApi]> - Escape hatches. The `header` snippet renders **first** in the header region, above `headerButton`, `search` and `headerMenu`.\n\n### Styling\n- **class**: string - Classes applied to the Sidebar root.\n- **theme**: SidebarThemeProps - Semantic part overrides such as `panel`, `header`, `nav`, `footer`, menu, search, rail, and mobile drawer parts.\n\n## Motion\n\n- **motion** theme slot: the y-axis slide shared by collapsible groups, inline submenus, and\n tree branches. Takes `in` / `out` slide params plus a `duration` / `easing` motion token.\n- Ladder: `<Theme components={{ sidebar: { motion } }}>` → `setSidebarTheme({ motion })` →\n `theme.motion`. Reduced motion collapses it to 0.\n\n## Accessibility\n\n- The body navigation renders inside a named `<nav>` landmark (`data-sidebar=\"nav\"`), so assistive tech can jump straight to it and tell it apart from the activity bar's own landmark.\n- Active links set `aria-current=\"page\"`.\n- Collapsible rows and groups set `aria-expanded`.\n- Disabled buttons use `disabled`; disabled links omit `href`, use `aria-disabled` and `tabindex=-1`, and block activation.\n- Mobile drawer includes a backdrop button labelled \"Close Sidebar\".\n- Icon-collapsed rows keep their labels mounted and visually fade them, preserving accessible names and stable icon geometry.\n- Search, group controls, actions, and nested rows become inert before collapse can remove or hide them; focus returns to the owning visible row.\n- Nested groups, tree branches, and inline submenus use reversible height transitions for open, close, and sidebar-collapse changes.\n- Tree roots use menu-row styling and nested tree nodes use submenu-row styling. In desktop icon mode, root folders open a PopupMenu and descendants remain navigable through recursive Menu submenu popovers; root leaves retain direct navigation and tooltips.\n- When `rail` and `resizable` are both enabled, one edge control owns click-to-toggle, drag resize, and keyboard resize without overlapping hitboxes.\n- Hidden offcanvas sidebars keep that combined edge control while temporarily revealed. Resizing does not pin the sidebar open; leaving the panel, trigger, and handle tolerance re-hides it without discarding the configured width.\n- Both peeks (edge reveal and `expandOnHover`) stay open while focus is inside the panel or while an overlay opened from inside it is open, including nested submenus. They release about 120ms after the pointer, focus, and every such overlay are gone.\n- The activity bar is its own `<nav>` landmark with a `<ul>` of items, a roving tabindex, and ArrowUp/ArrowDown/Home/End navigation that loops and skips disabled items. Tab lands on the `isActive` item. Each square takes its accessible name from `label`, with a string or number `badge` appended to it, and shows `label` as a tooltip on hover and focus.\n- A hidden offcanvas panel is `inert`, so Tab never lands in a panel parked off screen; a peek makes it interactive again.\n\n## Notes\n\n- Dropdown menus use Entasis `PopupMenu` and `MenuItem[]`.\n- The component uses semantic Entasis tokens. Do not add shadcn `sidebar-*` color tokens.\n- Snippet icons from `entasis/icons/*` are the preferred icon format.\n";
29
- readonly button: "\n# Button Component\n\nThe Button component is a flexible and customizable button element that supports various variants, sizes, colors, and interactive states.\n\n## Basic Usage\n\n```svelte\n<Button>Click me</Button>\n<Button variant=\"outline\">Outline Button</Button>\n<Button color=\"primary\" size=\"large\">Large Primary Button</Button>\n```\n\n## Props\n\n### Core Props\n- **variant**: 'solid' | 'outline' | 'soft' | 'ghost' | 'link' (default: 'solid')\n - solid: Filled background with color\n - outline: Transparent background with colored border\n - soft: Muted color background\n - ghost: Transparent background with a transient state layer on hover and press\n - link: Text-only styling with underline on hover\n\n- **color**: 'primary' | 'secondary' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' (default: 'neutral')\n - Determines the color scheme of the button\n\n- **size**: 'small' | 'normal' | 'large' (default: 'normal')\n - small: 24px height, smaller padding and text\n - normal: 32px height, standard padding\n - large: 36px height, larger padding and text\n\n### Layout Props\n- **fullWidth**: boolean (default: false) - Makes button take full width of container\n- **squared**: boolean - Makes button square (aspect-ratio 1:1), auto-determined if only prefix/suffix is provided\n- **disabled**: boolean (default: false) - Disables button interaction\n- **loading**: boolean (default: false) - Shows the Theme-configured loading spinner and disables interaction\n\n### State Props\nDescribe the meaning; the Button writes the ARIA. Never pass an aria-* attribute to a Button.\n- **pressed**: boolean - Toggle state of a button that stays on or off (a bold button in a toolbar, a \"show password\" eye). Rendered as aria-pressed\n- **selected**: boolean - Chosen state of a button acting as one option among several (a tab, a listbox option). Rendered as aria-selected\n- **expanded**: boolean - Whether the surface this button opens is showing. Rendered as aria-expanded. A entasis surface (Popover, PopupMenu, Select, Combobox) sets this on its own trigger, so pass it only for a surface you open yourself\n- **haspopup**: 'dialog' | 'menu' | 'listbox' | 'tree' | 'grid' | true - What the surface this button opens contains. Rendered as aria-haspopup, and likewise set by a entasis surface on its own trigger\n\n### Link Props\n- **href**: string - Makes button render as anchor tag\n- **target**: string - Link target (e.g., \"_blank\")\n- **rel**: string - Link relationship\n\n### Event Props\n- **onclick**: (event: MouseEvent) => void - Native click event handler\n- **onpointerenter**: (event: PointerEvent) => void - Native pointer enter event handler\n- **onpointerleave**: (event: PointerEvent) => void - Native pointer leave event handler\n\n### Content Props (Slots)\n- **children**: Snippet - Main button content\n- **prefix**: Snippet - Content before main text (typically icons)\n- **suffix**: Snippet - Content after main text (typically icons)\n\n### Advanced Props\n- **label**: string - Accessible label applied as aria-label on the root element (required for icon-only buttons)\n- **ref**: HTMLElement - Reference to the button element\n- **class**: string - Additional CSS classes\n- **theme**: ComponentTheme - Custom theme overrides\n\n## Structure\n\nThe button follows this DOM structure:\n```\n<Button>\n\t<Prefix /> <!-- Optional prefix content -->\n\t<Children /> <!-- Main button content -->\n\t<Suffix /> <!-- Optional suffix content -->\n</Button>\n```\n\n## Examples\n\n### Basic Buttons\n```svelte\n<Button>Default Button</Button>\n<Button variant=\"outline\" color=\"primary\">Primary Outline</Button>\n<Button variant=\"soft\" color=\"danger\">Soft Danger</Button>\n<Button variant=\"ghost\">Ghost Button</Button>\n<Button variant=\"link\">Link Button</Button>\n```\n\n### With Icons\n```svelte\n<Button>\n\t{#snippet prefix()}\n\t\t{@render icon()}\n\t{/snippet}\n\tAdd Item\n</Button>\n\n<Button squared>\n\t{#snippet prefix()}\n\t\t{@render icon()}\n\t{/snippet}\n</Button>\n```\n\n### Interactive States\n```svelte\n<Button loading>Loading...</Button>\n<Button disabled>Disabled</Button>\n<Button fullWidth>Full Width Button</Button>\n```\n\n### As Link\n```svelte\n<Button href=\"/dashboard\" target=\"_blank\">Go to Dashboard</Button>\n```\n\n### With Event Handlers\n```svelte\n<script lang=\"ts\">\n\tfunction handleClick(event: MouseEvent) {\n\t\tconsole.log('Clicked:', event.currentTarget);\n\t}\n</script>\n\n<Button onclick={handleClick}>\n\tClick\n</Button>\n```\n\n### Custom Styling\n```svelte\n<Button class=\"lift-4 border-2\" color=\"primary\" variant=\"outline\">\n\tCustom Styled\n</Button>\n```\n\n## Accessibility\n\n- Automatically sets appropriate ARIA roles (button/link)\n- Supports keyboard navigation\n- Disabled state prevents interaction\n- Loading state provides visual feedback\n\n## Notes\n\n- When `href` is provided, renders as `<a>` tag, otherwise `<button>`\n- `squared` is automatically determined when only prefix or suffix is provided without children\n- All event handlers respect disabled state\n- Icon sizing is automatically adjusted based on button size\n\n## Theme Customization\n\nThe Button component uses a theme object that can be customized using the `theme` prop or by setting a global theme.\n\n### Theme Structure\n\nThe theme object contains the following parts:\n- **root**: Main button container styles\n- **prefix**: Styles for prefix content (icons before text)\n- **suffix**: Styles for suffix content (icons after text)\n\n### Theme Type Definition\n\n```typescript\nimport type { ButtonThemeProps } from 'entasis/button';\n\n// Example theme customization\nconst customTheme: ButtonThemeProps = {\n root: {\n base: 'custom-base-classes',\n size: {\n small: 'custom-small-classes',\n normal: 'custom-normal-classes',\n large: 'custom-large-classes'\n },\n color: {\n primary: 'bg-blue-500 text-white',\n danger: 'bg-red-500 text-white'\n },\n variant: {\n solid: 'bg-color text-color-contrast',\n outline: 'border-2 border-color'\n }\n },\n prefix: {\n size: {\n small: 'w-3 h-3',\n normal: 'w-4 h-4',\n large: 'w-5 h-5'\n }\n }\n};\n```\n\n### Available Variants\n\n**root**:\n- base: Base classes applied to all buttons\n- Variants:\n - size: 'small' | 'normal' | 'large' - Controls padding, text size, and height\n - color: 'primary' | 'secondary' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' - Color scheme\n - variant: 'solid' | 'outline' | 'soft' | 'ghost' | 'link' - Visual style variant\n - loading: boolean - Loading state styling\n - disabled: boolean - Disabled state styling\n - squared: boolean - Square button styling\n - fullWidth: boolean - Full width styling\n\n**prefix**:\n- base: Base classes for prefix content\n- Variants:\n - size: 'small' | 'normal' | 'large' - Icon size based on button size\n\n**suffix**:\n- base: Base classes for suffix content\n- Variants:\n - size: 'small' | 'normal' | 'large' - Icon size based on button size\n\n### Usage Examples\n\n**Basic Theme Override**:\n```svelte\n<Button \n theme={{\n root: {\n base: 'rounded-full lift-4',\n size: {\n large: 'px-8 py-4 text-xl'\n }\n }\n }}\n>\n Custom Styled Button\n</Button>\n```\n\n**Color Variant Customization**:\n```svelte\n<Button \n color=\"primary\"\n theme={{\n root: {\n color: {\n primary: 'state-layer bg-gradient-to-r from-blue-500 to-purple-500'\n }\n }\n }}\n>\n Gradient Button\n</Button>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setButtonTheme } from '../components/Button/index.ts';\n \n setButtonTheme({\n root: {\n variant: {\n solid: 'state-layer bg-color text-color-contrast lift-3 hover:lift-4 transition-shadow',\n outline: 'state-layer border-2 border-color'\n }\n },\n prefix: {\n size: {\n normal: 'w-5 h-5'\n }\n }\n });\n</script>\n```\n";
28
+ readonly sidebar: "\n# Sidebar Component\n\nSidebar navigation with data-driven groups, icon collapse, mobile drawer behavior,\nrecursive tree groups, header/footer rows, search, actions, and snippet escape hatches.\n\n## Import\n\n```svelte\n<script lang=\"ts\">\n\timport { Sidebar, type SidebarGroup } from 'entasis/sidebar';\n</script>\n```\n\n## Basic Usage\n\n```svelte\n<script lang=\"ts\">\n\timport { Sidebar, type SidebarGroup } from 'entasis/sidebar';\n\timport { houseIcon } from 'entasis/icons/house';\n\timport { gearIcon } from 'entasis/icons/gear';\n\n\tconst items: SidebarGroup[] = [\n\t\t{\n\t\t\tlabel: 'Workspace',\n\t\t\titems: [\n\t\t\t\t{ label: 'Dashboard', href: '/', icon: houseIcon, isActive: true },\n\t\t\t\t{ label: 'Settings', href: '/settings', icon: gearIcon }\n\t\t\t]\n\t\t}\n\t];\n</script>\n\n<Sidebar items={items}>\n\t{#snippet children({ toggle })}\n\t\t<header>\n\t\t\t<button type=\"button\" onclick={toggle}>Toggle</button>\n\t\t</header>\n\t\t<main>Page content</main>\n\t{/snippet}\n</Sidebar>\n```\n\n## AI-Safe Usage Contract\n\n1. Use `items` for normal navigation. Use `content` only when data-driven rows cannot express the layout.\n2. Use local Entasis icon snippets such as `houseIcon`, not Lucide component constructors.\n3. Use `MenuItem[]` from `entasis/menu` for `menu` and action dropdowns.\n4. Do not combine `menu` with `href` or `onclick` on the same row; use `action` for a trailing row menu.\n5. Keep `children`, `header`, `content`, `footer`, `banner`, and action snippets pure; they receive `SidebarApi`.\n6. Use `collapsible=\"icon\"` for icon rail behavior, `collapsible=\"offcanvas\"` for hidden desktop panels, and `collapsible=\"none\"` for fixed sidebars. Icon collapse automatically falls back to offcanvas when any data-driven row lacks an icon.\n7. Offcanvas sidebars reveal over the content from the screen edge by default when hidden; set `edgeReveal={false}` to disable that. A revealed hidden sidebar keeps its resize handle and dismisses through a small rectangular pointer tolerance.\n8. Set `keyboardShortcut={false}` when embedding Sidebar inside another shortcut-heavy surface.\n9. Sidebar owns navigation, resize mechanics, the lower application wall, and variant surface geometry. AppShell forwards its variant and composes PageShell inside that surface.\n10. Use `size` for typography, icon scale, and item height. Use `density` independently for section padding, gaps, and submenu spacing.\n11. Use `activityBar` for a persistent icon rail outside the panel (section switching, workspaces). Every item needs an `icon` and a `label`; the label is the accessible name and the tooltip. It is layout mode only: `mode=\"panel\"` renders the navigation panel alone.\n12. Use `expandOnHover` only with `collapsible=\"icon\"`. It is a temporary peek, not a toggle: the persisted collapsed state never changes, while the peeked panel renders with expanded semantics.\n\n## Data Model\n\n### SidebarGroup\n- **label**: string - Group label, hidden in icon-collapsed mode.\n- **items**: SidebarMenuEntry[] - Menu rows.\n- **tree**: SidebarTreeNode[] - Recursive tree rows instead of menu items.\n- **action**: SidebarMenuActionDescriptor | SidebarMenuActionDescriptor[] | Snippet<[SidebarApi]> - Top-right group actions. Pass an array to pin several affordances (a `+` and a drag handle) to one group header; each renders as its own icon-only ghost button.\n- **collapsible**: boolean - Makes the group label a toggle.\n- **defaultOpen**: boolean - Initial collapsible group state.\n- **separator**: boolean - Divider before the group.\n\n### SidebarMenuEntry\n- **label**: string - Visible row label.\n- **icon**: SidebarIcon - Entasis icon snippet or string.\n- **iconColor**: Colors - Role tint for the leading icon, applied through `data-color`.\n- **iconVariant**: 'bare' | 'tile' - Leading icon treatment. `tile` paints a rounded square (`bg-color-muted text-color-muted-readable`) around the glyph, so per-project colour chips come from the role scale instead of hand-built markup.\n- **href**: string - Render as an anchor. Mutually exclusive with menu.\n- **onclick**: (event: MouseEvent) => void - Native click handler for button or anchor rows. Mutually exclusive with menu.\n- **isActive**: boolean - Adds active styling and `aria-current=\"page\"`.\n- **disabled**: boolean - Disables button rows and marks anchor rows disabled.\n- **badge**: string | number - Trailing count/status, hidden in icon mode.\n- **tooltip**: string - Entasis Tooltip content in icon mode. Defaults to label.\n- **items**: SidebarMenuSubEntry[] - Inline nested menu.\n- **collapsible**: boolean - Set false for an always-open submenu.\n- **defaultOpen**: boolean - Initial nested menu state.\n- **menu**: MenuItem[] - Popup menu opened from the full row. Mutually exclusive with href/onclick.\n- **action**: SidebarMenuActionDescriptor | Snippet<[SidebarApi]> - Hover/focus trailing action.\n\n### SidebarActivityBar\nIcon rail pinned to the outer edge of the sidebar, visible in every display state.\n- **items**: SidebarActivityBarItem[] - Items rendered from the top.\n- **footerItems**: SidebarActivityBarItem[] - Items pinned to the end of the column.\n- **header** / **footer**: Snippet - Custom content before the first item and after the pinned ones.\n- **width**: string (default '3rem') - Column thickness, published as `--sidebar-width-activity`.\n- **label**: string - Accessible name for the column landmark. Set it whenever the panel also renders navigation.\n- **onSelect**: ({ item, index }) => void - Fires after an item is activated. `index` counts `items` then `footerItems`.\n\n### SidebarActivityBarItem\n- **icon**: SidebarIcon (required) - Icon rendered in the square.\n- **label**: string (required) - Accessible name and default tooltip; the square shows no text.\n- **id**: string - Stable render key.\n- **href** / **target** / **rel** - Render an anchor instead of a button.\n- **onclick**: (event: MouseEvent) => void - Native click handler.\n- **isActive**: boolean - Adds active styling and `aria-current=\"page\"`.\n- **badge**: string | number | Snippet - Corner badge pinned to the outer top corner. An empty string renders a bare dot. A string or number badge joins the accessible name (`\"Alerts, 3\"`); a dot and a Snippet badge are decorative, so put their meaning in `label`.\n- **disabled**: boolean - Blocks activation and skips the item during keyboard navigation.\n- **tooltip**: string | false - Tooltip override; `false` suppresses it.\n\n### SidebarMenuButtonItem\nUse for `headerButton`, `footerButton`, or direct `<SidebarMenuButton />` rows.\n- **icon**: SidebarIcon - Leading logo/icon.\n- **avatar**: { src?: string; alt?: string; fallback?: string } - Leading avatar.\n- **variant**: 'default' | 'brand' | 'compact'.\n- **title**: string - Primary text.\n- **subtitle**: string - Secondary text.\n- **trailing**: SidebarIcon | false | SidebarMenuActionDescriptor - Trailing content. An icon is decorative; an action descriptor (`{ icon, label, onclick }`, the same shape as a group action) renders its own icon-only ghost button beside the row, so a workspace card can carry its own collapse control without a custom `header` snippet. Descriptor handlers are `onclick(event, api)`, so `api.toggle()` is reachable.\n- **href** / **onclick** / **menu** - Choose link, button, or popup behavior. `onclick(event, api)` receives the SidebarApi beside the event, so `api.toggle()` is reachable from the row itself.\n- **menuIconClass**: string - Class override for option icons inside the popup menu.\n\n## Props\n\n### State\n- **open**: boolean (bindable, default true) - Desktop expanded state.\n- **defaultOpen**: boolean (default true) - Initial desktop state when `open` is omitted.\n- **onOpenChange**: (open: boolean) => void - Called once for a library-originated desktop state change. Repeated requests and parent prop updates stay silent.\n- **onDisplayStateChange**: (state: SidebarDisplayState) => void - Called once for a library-originated semantic display-state change.\n- **api.displayState**: 'expanded' | 'collapsed' | 'hidden' - Semantic desktop state; hidden means closed offcanvas. A hover peek does not change it.\n- **api.isPeeking**: boolean - True while a hover peek renders the collapsed panel at full width. Read it alongside `displayState` when a snippet hides content in icon mode.\n- **keyboardShortcut**: string | false (default 'b') - Ctrl/Cmd shortcut key.\n\n### Layout\n- **side**: 'left' | 'right' - Desktop and mobile side.\n- **variant**: 'admin' | 'floating' | 'inset' | 'split' | 'framed' - Sidebar geometry. `framed` is the admin geometry for a sidebar hosted inside a raised card (AppShell variant framed), with a `surface-recessed` well. `admin` renders the conventional full-height navigation column; `inset` integrates navigation into the lower wall with an inset content surface; `split` renders detached sidebar and content surfaces.\n- **size**: 'small' | 'normal' | 'large' (default 'normal') - Typography, icon, avatar, badge, leading-media, item-height, and search-height scale.\n- **iconSize**: 'small' | 'normal' | 'large' - Icon and leading-media scale inside the panel on its own; defaults to `size`. Menu rows, sub rows, group labels and the header button follow it; the activity bar keeps `size`.\n- **activeVariant**: 'soft' | 'outline' | 'solid' (default 'soft') - How active rows are painted. `soft` is the shared selected recipe (`selectedSoft`: `bg-selected-muted text-selected-muted-readable`), `solid` its loud counterpart (`selectedSolid`: `bg-selected text-selected-contrast`), `outline` a bordered surface card (`bg-surface border border-neutral-muted text-neutral`) that reads as a raised card on a tinted well. Each row carries the choice as `data-active-variant`, so no descendant selector is needed to restyle selection.\n- **density**: 'compact' | 'normal' | 'comfortable' (default 'normal') - Section padding, group padding, gaps, horizontal inset, and submenu spacing.\n- **collapsible**: 'offcanvas' | 'icon' | 'none' - Collapse behavior. Icon mode requires icons on every data-driven row and otherwise resolves to offcanvas.\n- **collapseIcon**: DisclosureIndicator — 'chevron' | 'plus-minus' | 'none' (default 'chevron') - Disclosure indicator drawn on collapsible menu rows. 'none' renders no indicator.\n- **mode**: 'layout' | 'panel' - Full resizing layout or only the visible navigation panel.\n- **frame**: 'viewport' | 'contained' - Standalone Sidebar positioning. Viewport mode uses Theme's dynamic window-height token; contained mode fills a positioned parent.\n- **width**: string - Expanded width.\n- **widthIcon**: string - Icon-collapsed width.\n- **widthMobile**: string - Mobile drawer width.\n- **rail**: boolean | 'line' | 'thumb' - Edge toggle rail. `true` keeps the thin line style; `thumb` renders a short visible handle with the same full-height hitbox. The appearance is preserved when the rail shares the resize control.\n- **activityBar**: SidebarActivityBar - Icon rail pinned outside the panel, in layout mode only (`mode=\"panel\"` renders the panel alone and ignores it). It never slides off screen: only the panel takes the offcanvas offset, and the reserved layout column is the panel width plus the rail width. On mobile it renders as a horizontal row at the top of the drawer.\n- **expandOnHover**: boolean (default false) - With `collapsible=\"icon\"`, hovering or focusing into the collapsed panel expands it to `width` over the page (`data-peek=\"true\"`) while the reserved column stays at `widthIcon`, so page content does not reflow. The persisted collapsed state is untouched, and the peeked panel renders exactly like an expanded one: group headers, badges, search, inline submenus, and inline tree branches all come back, and the rail or resize handle travels to its inner edge.\n- **edgeReveal**: boolean (default true) - Pointer/focus edge preview for hidden offcanvas sidebars. Hover reveal overlays content, remains resizable when configured, and re-hides after the pointer leaves its small rectangular tolerance. Dragging the sidebar closed suppresses immediate hover reopening until the pointer leaves the edge trigger; toggle/click opens persistently.\n- **resizable**: boolean | SidebarResizableOptions - Enables pointer and keyboard resizing while expanded, icon-collapsed, or temporarily edge-revealed. By default, collapse requires dragging 75% of `minWidth` beyond the minimum; override `collapseThreshold` for a custom boundary. Use `storageKey` to restore and persist the expanded width across sessions.\n - `onWidthChange({ width, isUserInteraction })` reports every expanded-width change with one named payload: continuously while the user resizes (`isUserInteraction: true`) and once when a stored width is restored (`isUserInteraction: false`).\n\n### Content\n- **items**: SidebarGroup[] - Data-driven body navigation.\n- **headerButton** / **footerButton**: SidebarMenuButtonItem - Sticky large rows.\n- **search**: SidebarSearch - Header search input; use its native `oninput` handler.\n- **headerMenu** / **footerMenu**: SidebarMenuEntry[] - Sticky quick menus.\n- Menu entries and nested entries accept `size: 'small' | 'normal' | 'large'` for row geometry.\n- **header**, **content**, **footer**, **children**, **banner**: Snippet<[SidebarApi]> - Escape hatches. The `header` snippet renders **first** in the header region, above `headerButton`, `search` and `headerMenu`.\n\n### Styling\n- **class**: string - Classes applied to the Sidebar root.\n- **theme**: SidebarThemeProps - Semantic part overrides such as `panel`, `header`, `nav`, `footer`, menu, search, rail, and mobile drawer parts. Every part, with the element it lands on, its variants and their default classes, is listed in the entasis skill's `theme-parts/sidebar.md`; the registry key is `sidebar`.\n\n## Motion\n\n- **motion** theme slot: the y-axis slide shared by collapsible groups, inline submenus, and\n tree branches. Takes `in` / `out` slide params plus a `duration` / `easing` motion token.\n- Ladder: `<Theme components={{ sidebar: { motion } }}>` → `setSidebarTheme({ motion })` →\n `theme.motion`. Reduced motion collapses it to 0.\n\n## Restyle recipes\n\nThe five asks that come up first, as the override to copy. Each one is rendered and asserted by\n`sidebar-recipes.svelte.test.ts`, so it cannot drift from the component. One rule behind them: a\ndefault written under a variant prefix (`data-[active-variant=solid]:data-active:bg-selected`,\n`data-[side=left]:border-r`) is only replaced by an override carrying the same prefixes; an\nunprefixed class coexists with it and loses on specificity. `theme-parts/sidebar.md` shows every\ndefault verbatim, prefixes included.\n\n- **Dark panel.** `dark` scopes the dark theme's variables to the panel, so every neutral ink inside\n flips with it (every theme also emits its variables on `.<name>`, so the class scopes the dark theme to one subtree); needs a theme named `dark`, which the documented setup declares.\n `theme={{ panel: { base: 'dark bg-slate-900' }, mobilePanel: { base: 'dark bg-slate-900' } }}`\n- **Active row in your colour.** `activeVariant=\"solid\"` plus the same prefix chain as the default:\n `theme={{ menuButton: { base: 'rounded-full', activeVariant: { solid: 'data-[active-variant=solid]:data-active:bg-indigo-600 data-[active-variant=solid]:data-active:text-white' } } }}`\n- **No hover change.** The overlay is a `::before` and the default also brightens the ink on hover:\n `theme={{ menuButton: { base: 'state-layer-none hover:text-inherit' }, subButton: { base: 'state-layer-none hover:text-neutral/70' } }}`\n- **Flat panel.** The edge is a prefixed `border-r` / `border-l` on the admin variant, the shadow a\n `raised-*` on the floating ones:\n `theme={{ panel: { base: 'raised-none', variant: { admin: 'data-[side=left]:border-r-0 data-[side=right]:border-l-0' } } }}`\n- **Row height.** A plain height beats the compound `h-control-*`: `theme={{ menuButton: { base: 'h-11' } }}`\n- **Bigger icons.** A prop, not a theme: `iconSize=\"large\"`.\n\n## Accessibility\n\n- The body navigation renders inside a named `<nav>` landmark (`data-sidebar=\"nav\"`), so assistive tech can jump straight to it and tell it apart from the activity bar's own landmark.\n- Active links set `aria-current=\"page\"`.\n- Collapsible rows and groups set `aria-expanded`.\n- Disabled buttons use `disabled`; disabled links omit `href`, use `aria-disabled` and `tabindex=-1`, and block activation.\n- Mobile drawer includes a backdrop button labelled \"Close Sidebar\".\n- Icon-collapsed rows keep their labels mounted and visually fade them, preserving accessible names and stable icon geometry.\n- Search, group controls, actions, and nested rows become inert before collapse can remove or hide them; focus returns to the owning visible row.\n- Nested groups, tree branches, and inline submenus use reversible height transitions for open, close, and sidebar-collapse changes.\n- Tree roots use menu-row styling and nested tree nodes use submenu-row styling. In desktop icon mode, root folders open a PopupMenu and descendants remain navigable through recursive Menu submenu popovers; root leaves retain direct navigation and tooltips.\n- When `rail` and `resizable` are both enabled, one edge control owns click-to-toggle, drag resize, and keyboard resize without overlapping hitboxes.\n- Hidden offcanvas sidebars keep that combined edge control while temporarily revealed. Resizing does not pin the sidebar open; leaving the panel, trigger, and handle tolerance re-hides it without discarding the configured width.\n- Both peeks (edge reveal and `expandOnHover`) stay open while focus is inside the panel or while an overlay opened from inside it is open, including nested submenus. They release about 120ms after the pointer, focus, and every such overlay are gone.\n- The activity bar is its own `<nav>` landmark with a `<ul>` of items, a roving tabindex, and ArrowUp/ArrowDown/Home/End navigation that loops and skips disabled items. Tab lands on the `isActive` item. Each square takes its accessible name from `label`, with a string or number `badge` appended to it, and shows `label` as a tooltip on hover and focus.\n- A hidden offcanvas panel is `inert`, so Tab never lands in a panel parked off screen; a peek makes it interactive again.\n\n## Notes\n\n- Dropdown menus use Entasis `PopupMenu` and `MenuItem[]`.\n- The component uses semantic Entasis tokens. Do not add shadcn `sidebar-*` color tokens.\n- Snippet icons from `entasis/icons/*` are the preferred icon format.\n";
29
+ readonly button: "\n# Button Component\n\nThe Button component is a flexible and customizable button element that supports various variants, sizes, colors, and interactive states.\n\n## Basic Usage\n\n```svelte\n<Button>Click me</Button>\n<Button variant=\"outline\">Outline Button</Button>\n<Button color=\"primary\" size=\"large\">Large Primary Button</Button>\n```\n\n## Props\n\n### Core Props\n- **variant**: 'solid' | 'outline' | 'soft' | 'ghost' | 'link' (default: 'solid')\n - solid: Filled background with color\n - outline: Transparent background with colored border\n - soft: Muted color background\n - ghost: Transparent background with a transient state layer on hover and press\n - link: Text-only styling with underline on hover\n\n- **color**: 'primary' | 'secondary' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' (default: 'neutral')\n - Determines the color scheme of the button\n\n- **size**: 'small' | 'normal' | 'large' (default: 'normal')\n - small: 28px height, smaller padding and text\n - normal: 32px height, standard padding\n - large: 36px height, larger padding and text\n\n### Layout Props\n- **fullWidth**: boolean (default: false) - Makes button take full width of container\n- **squared**: boolean - Makes button square (aspect-ratio 1:1), auto-determined if only prefix/suffix is provided\n- **disabled**: boolean (default: false) - Disables button interaction\n- **loading**: boolean (default: false) - Shows the Theme-configured loading spinner and disables interaction\n\n### State Props\nDescribe the meaning; the Button writes the ARIA. Never pass an aria-* attribute to a Button.\n- **pressed**: boolean - Toggle state of a button that stays on or off (a bold button in a toolbar, a \"show password\" eye). Rendered as aria-pressed\n- **selected**: boolean - Chosen state of a button acting as one option among several (a tab, a listbox option). Rendered as aria-selected\n- **expanded**: boolean - Whether the surface this button opens is showing. Rendered as aria-expanded. A entasis surface (Popover, PopupMenu, Select, Combobox) sets this on its own trigger, so pass it only for a surface you open yourself\n- **haspopup**: 'dialog' | 'menu' | 'listbox' | 'tree' | 'grid' | true - What the surface this button opens contains. Rendered as aria-haspopup, and likewise set by a entasis surface on its own trigger\n\n### Link Props\n- **href**: string - Makes button render as anchor tag\n- **target**: string - Link target (e.g., \"_blank\")\n- **rel**: string - Link relationship\n\n### Event Props\n- **onclick**: (event: MouseEvent) => void - Native click event handler\n- **onpointerenter**: (event: PointerEvent) => void - Native pointer enter event handler\n- **onpointerleave**: (event: PointerEvent) => void - Native pointer leave event handler\n\n### Content Props (Slots)\n- **children**: Snippet - Main button content\n- **prefix**: Snippet - Content before main text (typically icons)\n- **suffix**: Snippet - Content after main text (typically icons)\n\n### Advanced Props\n- **label**: string - Accessible label applied as aria-label on the root element (required for icon-only buttons)\n- **ref**: HTMLElement - Reference to the button element\n- **class**: string - Additional CSS classes\n- **theme**: ComponentTheme - Custom theme overrides\n\n## Structure\n\nThe button follows this DOM structure:\n```\n<Button>\n\t<Prefix /> <!-- Optional prefix content -->\n\t<Children /> <!-- Main button content -->\n\t<Suffix /> <!-- Optional suffix content -->\n</Button>\n```\n\n## Examples\n\n### Basic Buttons\n```svelte\n<Button>Default Button</Button>\n<Button variant=\"outline\" color=\"primary\">Primary Outline</Button>\n<Button variant=\"soft\" color=\"danger\">Soft Danger</Button>\n<Button variant=\"ghost\">Ghost Button</Button>\n<Button variant=\"link\">Link Button</Button>\n```\n\n### With Icons\n```svelte\n<Button>\n\t{#snippet prefix()}\n\t\t{@render icon()}\n\t{/snippet}\n\tAdd Item\n</Button>\n\n<Button squared>\n\t{#snippet prefix()}\n\t\t{@render icon()}\n\t{/snippet}\n</Button>\n```\n\n### Interactive States\n```svelte\n<Button loading>Loading...</Button>\n<Button disabled>Disabled</Button>\n<Button fullWidth>Full Width Button</Button>\n```\n\n### As Link\n```svelte\n<Button href=\"/dashboard\" target=\"_blank\">Go to Dashboard</Button>\n```\n\n### With Event Handlers\n```svelte\n<script lang=\"ts\">\n\tfunction handleClick(event: MouseEvent) {\n\t\tconsole.log('Clicked:', event.currentTarget);\n\t}\n</script>\n\n<Button onclick={handleClick}>\n\tClick\n</Button>\n```\n\n### Custom Styling\n```svelte\n<Button class=\"lift-4 border-2\" color=\"primary\" variant=\"outline\">\n\tCustom Styled\n</Button>\n```\n\n## Accessibility\n\n- Automatically sets appropriate ARIA roles (button/link)\n- Supports keyboard navigation\n- Disabled state prevents interaction\n- Loading state provides visual feedback\n\n## Notes\n\n- When `href` is provided, renders as `<a>` tag, otherwise `<button>`\n- `squared` is automatically determined when only prefix or suffix is provided without children\n- All event handlers respect disabled state\n- Icon sizing is automatically adjusted based on button size\n\n## Theme Customization\n\nThe Button component uses a theme object that can be customized using the `theme` prop or by setting a global theme.\n\n### Theme Structure\n\nThe theme object contains the following parts:\n- **root**: Main button container styles\n- **prefix**: Styles for prefix content (icons before text)\n- **suffix**: Styles for suffix content (icons after text)\n\n### Theme Type Definition\n\n```typescript\nimport type { ButtonThemeProps } from 'entasis/button';\n\n// Example theme customization\nconst customTheme: ButtonThemeProps = {\n root: {\n base: 'custom-base-classes',\n size: {\n small: 'custom-small-classes',\n normal: 'custom-normal-classes',\n large: 'custom-large-classes'\n },\n color: {\n primary: 'bg-blue-500 text-white',\n danger: 'bg-red-500 text-white'\n },\n variant: {\n solid: 'bg-color text-color-contrast',\n outline: 'border-2 border-color'\n }\n },\n prefix: {\n size: {\n small: 'w-3 h-3',\n normal: 'w-4 h-4',\n large: 'w-5 h-5'\n }\n }\n};\n```\n\n### Available Variants\n\n**root**:\n- base: Base classes applied to all buttons\n- Variants:\n - size: 'small' | 'normal' | 'large' - Controls padding, text size, and height\n - color: 'primary' | 'secondary' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' - Color scheme\n - variant: 'solid' | 'outline' | 'soft' | 'ghost' | 'link' - Visual style variant\n - loading: boolean - Loading state styling\n - disabled: boolean - Disabled state styling\n - squared: boolean - Square button styling\n - fullWidth: boolean - Full width styling\n\n**prefix**:\n- base: Base classes for prefix content\n- Variants:\n - size: 'small' | 'normal' | 'large' - Icon size based on button size\n\n**suffix**:\n- base: Base classes for suffix content\n- Variants:\n - size: 'small' | 'normal' | 'large' - Icon size based on button size\n\n### Usage Examples\n\n**Basic Theme Override**:\n```svelte\n<Button \n theme={{\n root: {\n base: 'rounded-full lift-4',\n size: {\n large: 'px-8 py-4 text-xl'\n }\n }\n }}\n>\n Custom Styled Button\n</Button>\n```\n\n**Color Variant Customization**:\n```svelte\n<Button \n color=\"primary\"\n theme={{\n root: {\n color: {\n primary: 'state-layer bg-linear-to-r from-blue-500 to-purple-500'\n }\n }\n }}\n>\n Gradient Button\n</Button>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setButtonTheme } from '../components/Button/index.ts';\n \n setButtonTheme({\n root: {\n variant: {\n solid: 'state-layer bg-color text-color-contrast lift-3 hover:lift-4 transition-shadow',\n outline: 'state-layer border-2 border-color'\n }\n },\n prefix: {\n size: {\n normal: 'w-5 h-5'\n }\n }\n });\n</script>\n```\n";
30
30
  readonly 'button-group': "\n# ButtonGroup Component\n\nThe ButtonGroup component displays a collection of related buttons as a cohesive group with shared styling properties.\n\n## Basic Usage\n\n```svelte\n<ButtonGroup \n\titems={[\n\t\t{ children: 'First' },\n\t\t{ children: 'Second' },\n\t\t{ children: 'Third' }\n\t]}\n/>\n```\n\n## Props\n\n### Core Props\n- **items**: Array<ButtonProps> (required) - Array of button configurations\n - Each button can have all standard Button component props\n\n### Shared Button Props\n- **size**: 'small' | 'normal' | 'large' - Applied to all buttons in the group\n- **color**: 'primary' | 'secondary' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' - Shared color for all buttons\n- **variant**: 'solid' | 'outline' | 'soft' | 'ghost' | 'link' - Shared variant for all buttons\n- **disabled**: boolean - Disables all buttons in the group\n\n### Styling Props\n- **class**: string - Additional CSS classes for the group container\n- **theme**: ComponentTheme - Custom theme overrides\n\n## Structure\n\n```\n<ButtonGroup>\n\t<Button />\n\t<Button />\n\t<Button />\n</ButtonGroup>\n```\n\n## Examples\n\n### Basic Button Group\n```svelte\n<ButtonGroup \n\titems={[\n\t\t{ children: 'Left' },\n\t\t{ children: 'Center' },\n\t\t{ children: 'Right' }\n\t]}\n/>\n```\n\n### With Shared Styling\n```svelte\n<ButtonGroup \n\tsize=\"large\"\n\tcolor=\"primary\"\n\tvariant=\"outline\"\n\titems={[\n\t\t{ children: 'Option 1' },\n\t\t{ children: 'Option 2' },\n\t\t{ children: 'Option 3' }\n\t]}\n/>\n```\n\n### With Icons\n```svelte\n<script lang=\"ts\">\n\timport { ButtonGroup } from 'entasis/button-group';\n\timport { textAlignLeftIcon } from 'entasis/icons/textAlignLeft';\n\timport { textAlignCenterIcon } from 'entasis/icons/textAlignCenter';\n\timport { textAlignRightIcon } from 'entasis/icons/textAlignRight';\n</script>\n\n<ButtonGroup \n\titems={[\n\t\t{ \n\t\t\tprefix: textAlignLeftIcon,\n\t\t\tchildren: 'Left' \n\t\t},\n\t\t{ \n\t\t\tprefix: textAlignCenterIcon,\n\t\t\tchildren: 'Center' \n\t\t},\n\t\t{ \n\t\t\tprefix: textAlignRightIcon,\n\t\t\tchildren: 'Right' \n\t\t}\n\t]}\n/>\n```\n\n### With Individual Click Handlers\n```svelte\n<script>\n\tfunction handleOption(option) {\n\t\tconsole.log(`Selected: ${option}`);\n\t}\n</script>\n\n<ButtonGroup \n\titems={[\n\t\t{ \n\t\t\tchildren: 'Save',\n\t\t\tonclick: () => handleOption('save')\n\t\t},\n\t\t{ \n\t\t\tchildren: 'Cancel',\n\t\t\tonclick: () => handleOption('cancel')\n\t\t}\n\t]}\n/>\n```\n\n### Disabled Group\n```svelte\n<ButtonGroup \n\tdisabled\n\titems={[\n\t\t{ children: 'Option 1' },\n\t\t{ children: 'Option 2' }\n\t]}\n/>\n```\n\n### Icon Only Buttons\n```svelte\n<script lang=\"ts\">\n\timport { ButtonGroup } from 'entasis/button-group';\n\timport { textBIcon } from 'entasis/icons/textB';\n\timport { textItalicIcon } from 'entasis/icons/textItalic';\n\timport { textUnderlineIcon } from 'entasis/icons/textUnderline';\n</script>\n\n<ButtonGroup \n\titems={[\n\t\t{ \n\t\t\tsquared: true,\n\t\t\tprefix: textBIcon\n\t\t},\n\t\t{ \n\t\t\tsquared: true,\n\t\t\tprefix: textItalicIcon\n\t\t},\n\t\t{ \n\t\t\tsquared: true,\n\t\t\tprefix: textUnderlineIcon\n\t\t}\n\t]}\n/>\n```\n\n### Mixed Button States\n```svelte\n<ButtonGroup \n\tvariant=\"outline\"\n\titems={[\n\t\t{ children: 'Active', color: 'primary' },\n\t\t{ children: 'Default', color: 'neutral' },\n\t\t{ children: 'Disabled', disabled: true }\n\t]}\n/>\n```\n\n### Segmented Control\n```svelte\n<script>\n\tlet selected = $state('week');\n</script>\n\n<ButtonGroup \n\titems={[\n\t\t{ \n\t\t\tchildren: 'Day',\n\t\t\tvariant: selected === 'day' ? 'solid' : 'ghost',\n\t\t\tonclick: () => selected = 'day'\n\t\t},\n\t\t{ \n\t\t\tchildren: 'Week',\n\t\t\tvariant: selected === 'week' ? 'solid' : 'ghost',\n\t\t\tonclick: () => selected = 'week'\n\t\t},\n\t\t{ \n\t\t\tchildren: 'Month',\n\t\t\tvariant: selected === 'month' ? 'solid' : 'ghost',\n\t\t\tonclick: () => selected = 'month'\n\t\t}\n\t]}\n/>\n```\n\n## Styling\n\nButtonGroup automatically:\n- Removes border-radius from middle buttons\n- Adjusts borders to prevent double borders\n- Creates a cohesive, connected appearance\n- Maintains consistent spacing\n\n## Accessibility\n\n- Each button maintains full keyboard accessibility\n- Focus styles are preserved\n- Disabled state cascades properly\n- Screen readers announce each button individually\n\n## Notes\n\n- Individual button props override shared props\n- Buttons are rendered in the order provided\n- The group container can be styled with the `class` prop\n- All Button component features are supported for individual buttons\n\n## Theme Customization\n\nThe ButtonGroup component uses a theme object that can be customized using the `theme` prop or by setting a global theme.\n\n### Theme Structure\n\nThe theme object contains the following parts:\n- **root**: Main button group container styles\n\n### Available Variants\n\n**root**:\n- base: Base classes for button group container (handles border radius and border connections between buttons)\n\n### Usage Examples\n\n**Basic Theme Override**:\n```svelte\n<ButtonGroup \n items={buttons}\n theme={{\n root: {\n base: 'flex items-center rounded-lg overflow-hidden'\n }\n }}\n/>\n```\n\n**Custom Group Styling**:\n```svelte\n<ButtonGroup \n items={buttons}\n theme={{\n root: {\n base: 'flex items-center gap-0 border-2 border-primary rounded-lg overflow-hidden'\n }\n }}\n/>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setButtonGroupTheme } from '../components/ButtonGroup/index.ts';\n \n setButtonGroupTheme({\n root: {\n base: 'flex items-center first-child:rounded-r-none last-child:rounded-l-none'\n }\n });\n</script>\n```\n";
31
31
  readonly 'segmented-control': "\n# SegmentedControl\n\nA compact single-selection input for switching between a small set of mutually exclusive modes. It uses radiogroup/radio semantics and an animated indicator that slides and resizes to the selected item.\n\n## Basic usage\n\n```svelte\n<script lang=\"ts\">\n import { SegmentedControl } from '../components/SegmentedControl/index.ts';\n import { gridFourIcon } from 'entasis/icons/gridFour';\n import { listIcon } from 'entasis/icons/list';\n\n const items = [\n { value: 'grid', label: 'Grid', icon: gridFourIcon },\n { value: 'list', label: 'List', icon: listIcon }\n ] as const;\n\n let value = $state<(typeof items)[number]['value']>('grid');\n</script>\n\n<SegmentedControl {items} bind:value />\n```\n\n## Props\n\n- **items**: `readonly SegmentedControlItem[]` — required options with unique `value` fields.\n- **value**: `string` — bindable selected value; defaults to the first enabled item.\n- **defaultValue**: `string` — initial selected value when value is omitted.\n- **onValueChange**: `(value: string) => void` — called once after user interaction changes the value.\n- **item**: `Snippet<[SegmentedControlItem]>` — replaces the default item renderer.\n- **size**: `'small' | 'normal' | 'large'` — defaults to `'normal'`.\n- **color**: semantic color — controls the selected pill and focus ring; defaults to `'neutral'`.\n- **variant**: `'normal' | 'pill'` — controls corner radius; defaults to the moderately rounded `'normal'` shape.\n- **disabled**: `boolean` — disables the full control.\n- **label**: `string` — accessible name for the radiogroup; defaults to the catalog's \"Segmented control\".\n- **class**: additional root classes.\n- **theme**: component theme overrides.\n\n## Item shape\n\n```ts\ntype SegmentedControlItem<Value extends string = string> = {\n value: Value;\n label?: string | Snippet;\n icon?: string | Snippet;\n disabled?: boolean;\n};\n```\n\nThe default renderer displays `icon`, then `label`. `label` is also the segment's accessible name: a string is painted and spoken, a snippet names the segment through its own content, and an icon-only segment (no `label`) falls back to its `value`.\n\n## Custom item renderer\n\n```svelte\n<SegmentedControl {items} bind:value>\n {#snippet item(option)}\n <span>{option.label}</span>\n <span>{option.count}</span>\n {/snippet}\n</SegmentedControl>\n```\n\nExtra fields on item objects remain available to the snippet through generic inference.\n\n## Shapes\n\n`variant=\"normal\"` uses a moderately rounded track and segments. Use `variant=\"pill\"` for the fully rounded stadium shape.\n\n```svelte\n<SegmentedControl {items} bind:value />\n<SegmentedControl {items} bind:value variant=\"pill\" />\n```\n\n## Keyboard behavior\n\n- Tab enters on the selected item, or the first enabled item when no value matches.\n- Arrow Left/Right moves and selects, wrapping at the ends.\n- Home/End selects the first/last enabled item.\n- Disabled items are skipped.\n\nEach item has an invisible, size-aware pointer target that extends beyond the visual track: 36px for small, 44px for normal, and 48px for large. Adjacent targets meet at the midpoint of the configured gap instead of overlapping.\n\nUse SegmentedControl for mode or value selection. Use Tabbar when changing navigational views with tab semantics.\n";
32
32
  readonly 'toggle-button': "\n# ToggleButton Component\n\nThe ToggleButton component is a two-state button that can be toggled on and off, useful for binary settings and selections.\n\n## Basic Usage\n\n```svelte\n<script>\n\tlet isActive = $state(false);\n</script>\n\n<ToggleButton bind:value={isActive}>\n\tToggle Me\n</ToggleButton>\n```\n\n## Props\n\n### Core Props\n- **value**: boolean (bindable) - Toggle state\n- **defaultValue**: boolean (default: false) - Initial state when value is omitted\n- **label**: string - Accessible name for icon-only buttons\n- **type**: 'button' | 'submit' | 'reset' (default: 'button') - Native button type. The default prevents accidental form submission.\n- **role**: 'radio' - Exposes the pressed state as `aria-checked` instead of `aria-pressed`. Set by ToggleButtonGroup in `type=\"single\"` mode; rarely needed on a standalone button\n\n### Visual Props\n- **color**: 'primary' | 'secondary' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' (default: 'neutral')\n- **variant**: 'outline' | 'ghost' (default: 'ghost') — a Button subset. Resting outline uses the same border and surface recipe as Button; the pressed state adds a muted fill.\n- **size**: 'small' | 'normal' | 'large' (default: 'normal')\n\n### State Props\n- **disabled**: boolean (default: false) - Disables interaction\n\n### Event Props\n- **onValueChange**: (value: boolean) => void - Called once when toggle state changes\n\n### Content Slots\n- **children**: Snippet - Button content\n- **prefix**: Snippet - Content before text (typically icons)\n- **suffix**: Snippet - Content after text (typically icons)\n\n### Styling Props\n- **class**: string - Additional CSS classes\n- **theme**: ComponentTheme - Custom theme overrides\n\n## Examples\n\n### Basic Toggle\n```svelte\n<script>\n\tlet value = $state(false);\n</script>\n\n<ToggleButton bind:value>\n\t{value ? 'On' : 'Off'}\n</ToggleButton>\n```\n\n### With Icon\n```svelte\n<script lang=\"ts\">\n\timport { textBIcon } from 'entasis/icons/textB';\n\n\tlet isBold = $state(false);\n</script>\n\n<ToggleButton bind:value={isBold}>\n\t{#snippet prefix()}\n\t\t{@render textBIcon()}\n\t{/snippet}\n\tBold\n</ToggleButton>\n```\n\n### Different Variants\n```svelte\n<ToggleButton variant=\"ghost\" bind:value>Ghost</ToggleButton>\n<ToggleButton variant=\"outline\" bind:value>Outline</ToggleButton>\n```\n\n### Different Colors\n```svelte\n<ToggleButton color=\"primary\" bind:value>Primary</ToggleButton>\n<ToggleButton color=\"danger\" bind:value>Danger</ToggleButton>\n<ToggleButton color=\"success\" bind:value>Success</ToggleButton>\n```\n\n### Toolbar Buttons\n```svelte\n<script lang=\"ts\">\n\timport { textBIcon } from 'entasis/icons/textB';\n\timport { textItalicIcon } from 'entasis/icons/textItalic';\n\timport { textUnderlineIcon } from 'entasis/icons/textUnderline';\n\n\tlet format = $state({ bold: false, italic: false, underline: false });\n</script>\n\n<div class=\"flex gap-1\">\n\t<ToggleButton bind:value={format.bold}>\n\t\t{#snippet prefix()}\n\t\t\t{@render textBIcon()}\n\t\t{/snippet}\n\t</ToggleButton>\n\t<ToggleButton bind:value={format.italic}>\n\t\t{#snippet prefix()}\n\t\t\t{@render textItalicIcon()}\n\t\t{/snippet}\n\t</ToggleButton>\n\t<ToggleButton bind:value={format.underline}>\n\t\t{#snippet prefix()}\n\t\t\t{@render textUnderlineIcon()}\n\t\t{/snippet}\n\t</ToggleButton>\n</div>\n```\n\n### With Change Handler\n```svelte\n<script>\n\tfunction handleChange(value) {\n\t\tconsole.log('Toggled:', value);\n\t}\n</script>\n\n<ToggleButton onValueChange={handleChange}>\n\tNotify Me\n</ToggleButton>\n```\n\n### Disabled State\n```svelte\n<ToggleButton disabled value>Disabled On</ToggleButton>\n<ToggleButton disabled>Disabled Off</ToggleButton>\n```\n\n## Accessibility\n\n- Exposes the checked state through `aria-pressed` (or `aria-checked` when `role=\"radio\"`)\n- Renders `type=\"button\"` unless explicitly overridden\n- Keyboard accessible (Space/Enter to toggle)\n- Focus states for keyboard navigation\n- Screen reader friendly\n\n## Notes\n\n- Maintains toggle state between interactions\n- Visual feedback for checked/unchecked states\n- Can be used standalone or in ToggleButtonGroup\n- Supports all standard button features\n\n## Theme Customization\n\nThe ToggleButton component uses a theme object that can be customized using the `theme` prop or by setting a global theme.\n\n### Theme Structure\n\nThe theme object contains the following parts:\n- **root**: Main button element styles\n- **prefix**: Prefix icon/content styles\n- **suffix**: Suffix icon/content styles\n\n### Available Variants\n\n**root**:\n- base: Base classes for button element\n- Variants:\n - checked: boolean - Checked/toggled state styling\n - disabled: boolean - Disabled state styling\n - color: Color variants\n - variant: 'outline' | 'ghost' - Button variant\n - squared: boolean - Square button styling\n - size: 'small' | 'normal' | 'large' - Button size\n\n**prefix**:\n- base: Base classes for prefix content\n- Variants:\n - size: 'small' | 'normal' | 'large' - Icon size\n - checked: boolean - Checked state styling\n\n**suffix**:\n- base: Base classes for suffix content\n- Variants:\n - size: 'small' | 'normal' | 'large' - Icon size\n - checked: boolean - Checked state styling\n\n### Usage Examples\n\n**Basic Theme Override**:\n```svelte\n<ToggleButton \n bind:value\n theme={{\n root: {\n base: 'rounded-md transition-all',\n checked: {\n true: 'bg-primary text-white',\n false: 'bg-gray-200'\n },\n size: {\n normal: 'px-4 py-2'\n }\n }\n }}\n>\n Toggle\n</ToggleButton>\n```\n\n**Custom Checked State**:\n```svelte\n<script lang=\"ts\">\n import { checkIcon } from 'entasis/icons/check';\n</script>\n\n<ToggleButton \n bind:value\n variant=\"outline\"\n theme={{\n root: {\n variant: {\n outline: 'border-2'\n },\n checked: {\n true: 'border-primary bg-primary/10 text-primary',\n false: 'border-gray-300'\n }\n },\n prefix: {\n checked: {\n true: 'text-primary'\n }\n }\n }}\n>\n {#snippet prefix()}\n {@render checkIcon()}\n {/snippet}\n Toggle\n</ToggleButton>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setToggleButtonTheme } from '../components/ToggleButton/index.ts';\n \n setToggleButtonTheme({\n root: {\n base: 'transition-all duration-100',\n checked: {\n true: 'bg-primary text-white',\n false: 'bg-gray-200'\n },\n size: {\n normal: 'px-4 py-2 h-8'\n }\n },\n prefix: {\n size: {\n normal: 'max-w-6 max-h-6'\n }\n }\n });\n</script>\n```\n";
@@ -84,11 +84,11 @@ export declare const componentMcpRegistry: {
84
84
  readonly confirmation: "\nThe confirmation function displays a modal dialog that asks the user to confirm or cancel an action. It returns a Promise that resolves with an object indicating whether the user confirmed or cancelled.\n\n**Usage:**\n```typescript\nimport { confirmation } from 'entasis/confirmation';\n\nconst { confirmed, result } = await confirmation({\n title: 'Delete Item',\n description: 'Are you sure you want to delete this item? This action cannot be undone.',\n confirm: 'Delete',\n cancel: 'Cancel',\n onConfirm: async () => {\n // Optional: Async function that runs when user confirms\n await deleteItem();\n return 'Item deleted successfully';\n }\n});\n\nif (confirmed) {\n console.log('User confirmed:', result); // result is the return value of onConfirm, or undefined\n} else {\n console.log('User cancelled');\n}\n```\n\n**Parameters:**\n- `title` (string, required): The title displayed in the confirmation dialog\n- `description` (string, required): The description/message shown in the dialog\n- `confirm` (string | object, required): The confirm button text, or an object with `text` and Button props\n- `cancel` (string | object, required): The cancel button text, or an object with `text` and Button props\n- `onConfirm` (function, optional): An async function that runs when the user clicks confirm. Its return value is passed as `result` in the resolved promise\n\n**Returns:**\nA Promise that resolves to:\n- `{ confirmed: true, result: R }` if the user confirmed (where R is the return type of onConfirm, or void)\n- `{ confirmed: false, result: undefined }` if the user cancelled\n\n**Notes:**\n- The dialog is modal and prevents interaction with the rest of the page until the user responds\n- If `onConfirm` is provided, the confirm button shows a loading state while the function executes\n- The dialog cannot be closed by clicking outside or pressing Escape (user must click a button)\n- Requests made before any `<Confirmation />` is mounted are queued and served by the first one that mounts\n- With several mounted, the most recently mounted one serves; when it unmounts the previous one takes over again\n";
85
85
  readonly empty: "\n# Empty Component\n\nThe Empty component displays an empty state: a centered composition of media (icon or illustration), title, description, action area, and optional note/footer. Use it for empty lists, no-results screens, first-run states, or error placeholders.\n\n## Basic Usage\n\n```svelte\n<script>\n\timport { Empty } from 'entasis/empty';\n\timport { folderIcon } from 'entasis/icons/folder';\n</script>\n\n<Empty\n\tmediaVariant=\"icon\"\n\tmedia={folderIcon}\n\ttitle=\"No projects yet\"\n\tdescription=\"Get started by creating your first project.\"\n/>\n```\n\n## Props\n\n### Core Props\n- **mediaVariant**: 'default' | 'icon' (default: 'default')\n - default: Renders the media bare (transparent background), for illustrations or custom visuals\n - icon: Wraps the media in a small muted rounded square, sized to the empty state size\n\n- **mode**: 'normal' | 'card' (default: 'normal')\n - normal: Transparent placeholder (current behavior)\n - card: Renders on a raised surface (bg-surface + raised-sm), matching the Card component\n\n- **bordered**: boolean (default: false)\n - Wraps the whole empty state in a dashed border (rounded-xl)\n\n- **size**: 'small' | 'normal' | 'large' (default: 'normal')\n - Scales paddings, gaps, media box, and typography\n\n### Actions\n- **actions**: array of (ButtonProps + content) - Buttons rendered as a centered, wrapping row below the description. Each entry is Button props plus a \"content\" string for the label. Convenience alternative to the content slot.\n\n### Content Props (Slots)\nAll slots accept a string or a snippet.\n- **media**: Slot - Icon, image, or illustration shown above the title\n- **title**: Slot - Main heading of the empty state\n- **description**: Slot - Muted supporting text; anchor tags inside get underline styling and primary hover color\n- **content**: Slot - Action area, typically buttons; rendered below the header\n- **note**: Slot - Description-styled note rendered after the content (e.g. a help link)\n- **footer**: Slot - Trailing content rendered as a sibling of header/content, unwrapped\n\n### Advanced Props\n- **children**: Snippet - Custom content that replaces the default composition entirely when set\n- **class**: string - Additional CSS classes on the root\n- **theme**: EmptyThemeProps - Theme overrides\n\n## Structure\n\n```\n<Empty> <!-- root: centered flex column -->\n\t<header> <!-- only when media/title/description is set -->\n\t\t<media />\n\t\t<title />\n\t\t<description />\n\t</header>\n\t<content> <!-- only when content/note is set -->\n\t\t<content />\n\t\t<note />\n\t</content>\n\t<footer /> <!-- unwrapped trailing slot -->\n</Empty>\n```\n\n## Examples\n\n### Icon empty state with action\n```svelte\n<Empty\n\tbordered\n\tmediaVariant=\"icon\"\n\tmedia={folderIcon}\n\ttitle=\"No projects yet\"\n\tdescription=\"You haven't created any projects yet.\"\n>\n\t{#snippet content()}\n\t\t<Button size=\"small\">Create project</Button>\n\t{/snippet}\n</Empty>\n```\n\n### Custom media snippet (default variant)\n```svelte\n<Empty title=\"No results\" description=\"Try adjusting your search filters.\">\n\t{#snippet media()}\n\t\t{@render magnifyingGlassIcon({ class: 'size-10 text-neutral/70' })}\n\t{/snippet}\n</Empty>\n```\n\n### With a note and footer\n```svelte\n<Empty mediaVariant=\"icon\" media={trayIcon} title=\"Inbox empty\">\n\t{#snippet content()}\n\t\t<Button size=\"small\" variant=\"outline\">Refresh</Button>\n\t{/snippet}\n\t{#snippet note()}\n\t\tNeed help? <a href=\"/support\">Contact support</a>\n\t{/snippet}\n</Empty>\n```\n\n### Fully custom composition\n```svelte\n<Empty bordered>\n\t<p>Anything goes here — children replaces the default layout.</p>\n</Empty>\n```\n\n## Accessibility\n\n- The component renders plain, semantically neutral divs; provide meaningful text in title/description\n- Action buttons placed in the content slot keep their own focus and keyboard behavior\n- Links inside the description are visually distinguished by an underline\n\n## Notes\n\n- The header wrapper only renders when media, title, or description is provided; the content wrapper only renders when content or note is provided\n- The note slot reuses the description styling\n- The media sizing selector `[&_svg:not([class*=size-])]:size-*` only applies in the icon variant; pass your own size class on the svg to override it\n\n## Theme Customization\n\nThe Empty component uses a theme object that can be customized using the `theme` prop or by setting a global theme.\n\n### Theme Structure\n\n- **root**: Root container (layout, padding, gap, dashed border)\n- **header**: Header wrapper around media/title/description\n- **media**: Media box (mediaVariant + size variants)\n- **title**: Title text\n- **description**: Description and note text\n- **content**: Action area wrapper\n\n### Available Variants\n\n**root**: size ('small' | 'normal' | 'large'), bordered (boolean)\n**header**: size\n**media**: size, mediaVariant ('default' | 'icon')\n**title**: size\n**description**: size\n**content**: size\n\n### Usage Examples\n\n**Local override**:\n```svelte\n<Empty\n\ttheme={{\n\t\troot: { base: 'min-h-64' },\n\t\tmedia: { mediaVariant: { icon: 'bg-primary-muted text-primary rounded-full' } }\n\t}}\n\tmediaVariant=\"icon\"\n\tmedia={folderIcon}\n\ttitle=\"Themed empty state\"\n/>\n```\n\n**Global theme setting**:\n```svelte\n<script>\n\timport { setEmptyTheme } from 'entasis/empty';\n\n\tsetEmptyTheme({\n\t\ttitle: { base: 'font-semibold' },\n\t\troot: { bordered: { true: 'border-2 border-dotted' } }\n\t});\n</script>\n```\n";
86
86
  readonly meter: "\n# Meter Component\n\nThe Meter component visualizes a measurement or progress along a known scale, with support for multiple values, steps, labels, and animations.\n\n## Basic Usage\n\n```svelte\n<Meter value={75} label=\"Progress\" />\n```\n\n## Props\n\n### Core Props\n- **value**: number | MeterStep<T> | Array<MeterStep<T>> (required) - A plain number, one segment, or a stacked set of segments\n - A number renders a single segment coloured by `color`; its legend label defaults to the number itself\n - Each segment object: { value: number, label?: string, color?: Colors, icon?: Snippet, position?: 'top' | 'bottom', data?: T }\n- **color**: Colors (default: 'primary') - Color used for a numeric value and as the fallback for segments with no color of their own\n\n- **min**: number (default: 0) - Minimum value\n- **max**: number (default: 100) - Maximum value\n- **size**: 'small' | 'normal' | 'large' - Visual size of the meter\n\n### Display Props\n- **showIndicatorAs**: 'value' | 'percentage' - How to display the indicator label\n\n### Steps\n- **steps**: Array<Step<S>> - Predefined steps/milestones on the meter\n - Each step: { start: number, end?: number, label: Slot, color: Colors, position?: 'top' | 'bottom', class?: string, labelClass?: string, data?: S }\n\n### Content Slots\n- **label**: Snippet - Custom label\n- **description**: Snippet - Description text\n- **helper**: Snippet - Helper text\n- **header**: Snippet - Custom header\n- **indicator**: string | Snippet - Custom indicator content (no payload); combine with `showIndicatorAs` for the built-in value/percentage text\n\n### Animation Props\n- **stiffness**: number - Spring animation stiffness\n- **damping**: number - Spring animation damping\n- **soft**: number - Softness of animation\n- **precision**: number - Precision of animated values\n\n### Styling Props\n- **class**: string - Additional CSS classes\n- **theme**: ComponentTheme - Custom theme overrides\n\n## Structure\n\n```\n<Meter>\n\t<Header>\n\t\t<Label />\n\t\t<Description />\n\t</Header>\n\t<Track>\n\t\t<Progress />\n\t\t<Indicator />\n\t\t<Steps />\n\t</Track>\n\t<Helper />\n</Meter>\n```\n\n## Examples\n\n### Simple Progress Bar\n```svelte\n<Meter value={65} />\n```\n\n### Basic Meter\n```svelte\n<Meter value={60} label=\"Completion\" />\n```\n\n### With Label and Description\n```svelte\n<Meter \n\tvalue={75}\n>\n\t{#snippet label()}\n\t\t<span>Progress</span>\n\t{/snippet}\n\t{#snippet description()}\n\t\t<span>75% complete</span>\n\t{/snippet}\n</Meter>\n```\n\n### Different Colors\n```svelte\n<Meter value={30} color=\"danger\" label=\"Low\" />\n<Meter value={60} color=\"warning\" label=\"Medium\" />\n<Meter value={90} color=\"success\" label=\"High\" />\n```\n\n### Multiple Values (Stacked)\n```svelte\n<Meter \n\tvalue={[\n\t\t{ value: 40, color: 'primary', label: 'Used' },\n\t\t{ value: 30, color: 'secondary', label: 'Reserved' }\n\t]}\n\tmax={100}\n/>\n```\n\n### With Steps\n```svelte\n<Meter \n\tvalue={65}\n\tsteps={[\n\t\t{ start: 0, end: 25, label: 'Low', color: 'danger' },\n\t\t{ start: 25, end: 75, label: 'Medium', color: 'warning' },\n\t\t{ start: 75, end: 100, label: 'High', color: 'success' }\n\t]}\n/>\n```\n\n### Show as Percentage\n```svelte\n<Meter \n\tvalue={45}\n\tshowIndicatorAs=\"percentage\"\n/>\n```\n\n### Different Sizes\n```svelte\n<Meter size=\"small\" value={50} />\n<Meter size=\"normal\" value={50} />\n<Meter size=\"large\" value={50} />\n```\n\n### Custom Range\n```svelte\n<Meter \n\tmin={0}\n\tmax={1000}\n\tvalue={350}\n\tlabel=\"Score\"\n/>\n```\n\n### Storage Usage Example\n```svelte\n<script>\n\tlet storage = {\n\t\tused: 45,\n\t\tcached: 20,\n\t\tavailable: 35\n\t};\n</script>\n\n<Meter \n\tvalue={[\n\t\t{ value: storage.used, color: 'primary', label: 'Used' },\n\t\t{ value: storage.cached, color: 'info', label: 'Cached' }\n\t]}\n\tmax={100}\n>\n\t{#snippet header()}\n\t\t<div class=\"flex justify-between\">\n\t\t\t<span>Storage</span>\n\t\t\t<span>{storage.used + storage.cached}GB / 100GB</span>\n\t\t</div>\n\t{/snippet}\n\t{#snippet helper()}\n\t\t{storage.available}GB available\n\t{/snippet}\n</Meter>\n```\n\n### Task Progress\n```svelte\n<script>\n\tlet tasks = {\n\t\tcompleted: 12,\n\t\ttotal: 20\n\t};\n\tlet progress = (tasks.completed / tasks.total) * 100;\n</script>\n\n<Meter \n\tvalue={progress}\n\tcolor=\"success\"\n>\n\t{#snippet label()}\n\t\tTask Progress\n\t{/snippet}\n\t{#snippet description()}\n\t\t{tasks.completed} of {tasks.total} tasks completed\n\t{/snippet}\n</Meter>\n```\n\n### With Custom Indicator\n```svelte\n<!-- indicator is a payload-less slot; use showIndicatorAs for the built-in value/percentage text -->\n<Meter value={75}>\n\t{#snippet indicator()}\n\t\t<div class=\"custom-indicator\">75 / 100</div>\n\t{/snippet}\n</Meter>\n```\n\n### Skill Level Meter\n```svelte\n<Meter \n\tvalue={85}\n\tcolor=\"info\"\n\tsteps={[\n\t\t{ start: 0, end: 30, label: 'Beginner', color: 'danger', position: 'bottom' },\n\t\t{ start: 30, end: 70, label: 'Intermediate', color: 'warning', position: 'bottom' },\n\t\t{ start: 70, end: 100, label: 'Expert', color: 'success', position: 'bottom' }\n\t]}\n>\n\t{#snippet label()}\n\t\tJavaScript Proficiency\n\t{/snippet}\n</Meter>\n```\n\n## Accessibility\n\n- Uses semantic HTML meter/progress elements\n- Labels provide context for screen readers\n- ARIA attributes for current value and range\n- Visual indicators have text alternatives\n\n## Notes\n\n- Values are animated with spring physics for smooth transitions\n- Multiple values stack horizontally\n- Steps provide visual milestones and labels\n- Indicator position can be top or bottom\n- Progress bar fills from left to right\n- The root `color` prop colors the whole meter; a segment's own `color` overrides it\n\n## Theme Customization\n\nThe Meter component uses a theme object that can be customized using the `theme` prop or by setting a global theme.\n\n### Theme Structure\n\nThe theme object contains the following parts:\n- **root**: Main meter container styles\n- **header**: Header section styles\n- **container**: Progress container styles\n- **label**: Label text styles\n- **helper**: Helper text styles\n- **description**: Description text styles\n- **progress**: Progress bar element styles\n- **track**: Track/background styles\n- **indicator**: Value indicator styles\n- **legend**: Legend container styles\n- **legendItem**: Legend item styles\n- **legendIcon**: Legend icon styles\n- **legendLabel**: Legend label text styles\n- **legendPercentage**: Legend percentage text styles\n\n### Available Variants\n\n**root**:\n- base: Base classes for main container\n- Variants:\n - size: 'small' | 'normal' | 'large' - Container gap size\n\n**header**:\n- base: Base classes for header section\n- Variants:\n - size: 'small' | 'normal' | 'large' - Gap between elements\n\n**container**:\n- base: Base classes for progress container\n- Variants:\n - first: boolean - First segment styling (rounded left)\n - last: boolean - Last segment styling (rounded right)\n\n**label**:\n- base: Base classes for label text\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n\n**helper**:\n- base: Base classes for helper text\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n\n**description**:\n- base: Base classes for description text\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n\n**progress**:\n- base: Base classes for progress bar\n- Variants:\n - size: 'small' | 'normal' | 'large' - Bar height\n\n**track**:\n- base: Base classes for track/background\n- Variants:\n - size: 'small' | 'normal' | 'large' - Track height\n - labelsPosition: 'top' | 'bottom' | 'both' - Margin based on label position\n\n**indicator**:\n- base: Base classes for value indicator\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n - position: 'top' | 'bottom' - Indicator position\n\n**legend**:\n- base: Base classes for legend container\n- Variants:\n - size: 'small' | 'normal' | 'large' - Legend size\n\n**legendItem**:\n- base: Base classes for legend items\n- Variants:\n - size: 'small' | 'normal' | 'large' - Gap between elements\n\n**legendIcon**:\n- base: Base classes for legend icons\n- Variants:\n - size: 'small' | 'normal' | 'large' - Icon size\n\n**legendLabel**:\n- base: Base classes for legend labels\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n\n**legendPercentage**:\n- base: Base classes for legend percentages\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n\n### Usage Examples\n\n**Basic Theme Override**:\n```svelte\n<Meter \n value={75}\n theme={{\n root: {\n base: 'flex flex-col',\n size: {\n normal: 'gap-2'\n }\n },\n track: {\n base: 'rounded-full bg-gray-200',\n size: {\n normal: 'h-2'\n }\n }\n }}\n/>\n```\n\n**Custom Progress Bar**:\n```svelte\n<Meter \n value={60}\n theme={{\n progress: {\n base: 'bg-gradient-to-r from-primary to-secondary',\n size: {\n large: 'h-4'\n }\n },\n track: {\n base: 'bg-gray-100 rounded-full',\n size: {\n large: 'h-4'\n }\n },\n indicator: {\n base: 'text-sm font-semibold',\n position: {\n top: 'bottom-full mb-2'\n }\n }\n }}\n/>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setMeterTheme } from '../components/Meter/index.ts';\n \n setMeterTheme({\n root: {\n base: 'flex flex-col',\n size: {\n normal: 'gap-2'\n }\n },\n track: {\n base: 'rounded-full bg-gray-200',\n size: {\n normal: 'h-2'\n }\n },\n progress: {\n base: 'bg-primary rounded-full'\n }\n });\n</script>\n```\n";
87
- readonly 'network-indicator': "\n# NetworkIndicator Component\n\nNetworkIndicator is a fixed top loading bar for SvelteKit navigation and explicit async work. Mount one instance near the root layout. It shows automatically during SvelteKit route transitions, can be driven by a controlled `loading` prop, and exposes imperative helpers for request lifecycles.\n\n## Import\n\n```svelte\n<script lang=\"ts\">\n\timport { NetworkIndicator } from 'entasis/network-indicator';\n</script>\n```\n\n## Basic Usage\n\n```svelte\n<!-- +layout.svelte -->\n<script lang=\"ts\">\n\timport { NetworkIndicator } from 'entasis/network-indicator';\n</script>\n\n<NetworkIndicator />\n\n{@render children()}\n```\n\n## Props\n\n- **loading**: boolean = false\n - Controlled visibility. Use this when the owner already has request state or when rendering examples/previews.\n- **variant**: 'bar' | 'trail' | 'trail-bounce' = 'bar'\n - `bar` progressively grows one indicator. `trail` renders one randomly sized moving segment at a time. `trail-bounce` sends that random trail fully off one edge, then returns from the opposite edge.\n- **trailGap**: number = 0\n - Pause between trail passes in milliseconds. Only applies to `variant=\"trail\"`.\n- **color**: 'primary' | 'secondary' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' = 'neutral'\n - Applies the semantic color token to the bar.\n- **height**: number = 3\n - Height in pixels. Keep most navigation indicators between 2 and 6.\n- Animation duration and easing come from the `motion` theme slot — `theme={{ motion: { duration: 450, easing: 'expoOut' } }}` — not from props; see Motion below.\n- **label**: string = 'Loading'\n - Accessible label for the indeterminate `role=\"progressbar\"`.\n- **ref**: HTMLDivElement | null\n - Bindable root element reference while the indicator is visible.\n- **class**: string\n - Additional classes for the root bar.\n- **theme**: NetworkIndicatorThemeProps\n - Theme override for the root bar.\n\n## Helper API\n\n```ts\nimport {\n\thideNetworkIndicator,\n\tshowNetworkIndicator,\n\ttoggleNetworkIndicator\n} from 'entasis/network-indicator';\n```\n\nPrefer `showNetworkIndicator()` and `hideNetworkIndicator()` for async work. `toggleNetworkIndicator()` is available for simple demos or manual toggles, but it is easier to desynchronize in request lifecycles.\n\n## Patterns\n\n### Controlled Loading\n\n```svelte\n<script lang=\"ts\">\n\timport { NetworkIndicator } from 'entasis/network-indicator';\n\n\tlet loading = $state(false);\n</script>\n\n<NetworkIndicator {loading} color=\"primary\" label=\"Saving changes\" />\n```\n\n### Async Request\n\n```svelte\n<script lang=\"ts\">\n\timport { Button } from 'entasis/button';\n\timport {\n\t\thideNetworkIndicator,\n\t\tshowNetworkIndicator\n\t} from 'entasis/network-indicator';\n\n\tasync function save() {\n\t\tshowNetworkIndicator();\n\t\ttry {\n\t\t\tawait fetch('/api/save', { method: 'POST' });\n\t\t} finally {\n\t\t\thideNetworkIndicator();\n\t\t}\n\t}\n</script>\n\n<Button onclick={save}>Save</Button>\n```\n\n### Color Variations\n\n```svelte\n<NetworkIndicator loading color=\"primary\" />\n<NetworkIndicator loading color=\"success\" />\n<NetworkIndicator loading color=\"warning\" />\n<NetworkIndicator loading color=\"danger\" />\n```\n\n### Trail Variant\n\n```svelte\n<NetworkIndicator loading variant=\"trail\" color=\"primary\" theme={{ motion: { duration: 650 } }} trailGap={0} />\n<NetworkIndicator loading variant=\"trail\" color=\"success\" height={5} theme={{ motion: { duration: 450 } }} trailGap={120} />\n<NetworkIndicator loading variant=\"trail-bounce\" color=\"info\" theme={{ motion: { duration: 700 } }} trailGap={80} />\n```\n\n### Height Variations\n\n```svelte\n<NetworkIndicator loading height={2} />\n<NetworkIndicator loading height={4} color=\"primary\" />\n<NetworkIndicator loading height={6} color=\"info\" />\n```\n\n### Motion Variations\n\n```svelte\n<NetworkIndicator loading theme={{ motion: { duration: 300, easing: 'cubicInOut' } }} />\n<NetworkIndicator loading theme={{ motion: { duration: 450, easing: 'expoOut' } }} />\n<NetworkIndicator loading theme={{ motion: { duration: 500, easing: 'backOut' } }} />\n```\n\n### Theme Override\n\n```svelte\n<NetworkIndicator\n\tloading\n\tcolor=\"success\"\n\theight={5}\n\ttheme={{\n\t\troot: {\n\t\t\tbase: 'ui-network-indicator fixed top-0 left-0 w-full z-[9999] origin-left rounded-none lift-4'\n\t\t}\n\t}}\n/>\n```\n\n## Theme\n\nThe theme has two parts:\n\n- **root**: the fixed top bar.\n - `base`: positioning, origin, radius, z-index, and shared bar classes.\n - `variant`: `bar`, `trail`, or `trail-bounce` container styling.\n - `color`: semantic color variants.\n- **segment**: trail segment styling.\n - `base`: segment positioning, radius, opacity, shadow, and transform hints.\n - `color`: semantic color variants for each trail segment.\n\nThe default root base includes `ui-network-indicator`; keep that class if overriding the base because `toggleNetworkIndicator()` uses it to read current state.\n\n## Accessibility\n\nThe visible bar renders `role=\"progressbar\"` without a value because progress is indeterminate. Use a specific `label` when the loading context matters, such as \"Uploading files\" or \"Saving changes\". If screen readers need richer lifecycle announcements, pair the indicator with app-level live region text.\n\n## Motion\n\n- **motion** theme slot, keyed by `variant`: one growth step of the `bar` loop (`slow`), or\n one pass of the `trail` / `trail-bounce` variants (the `slower` token, 500ms). Only `duration` / `easing` are read.\n- Ladder: `<Theme components={{ networkIndicator: { motion } }}>` →\n `setNetworkIndicatorTheme({ motion })` → `theme={{ motion: { duration, easing } }}`.\n- A resolved duration of 0 (reduced motion) holds the indicator still instead of looping.\n";
87
+ readonly 'network-indicator': "\n# NetworkIndicator Component\n\nNetworkIndicator is a fixed top loading bar for SvelteKit navigation and explicit async work. Mount one instance near the root layout. It shows automatically during SvelteKit route transitions, can be driven by a controlled `loading` prop, and exposes imperative helpers for request lifecycles.\n\n## Import\n\n```svelte\n<script lang=\"ts\">\n\timport { NetworkIndicator } from 'entasis/network-indicator';\n</script>\n```\n\n## Basic Usage\n\n```svelte\n<!-- +layout.svelte -->\n<script lang=\"ts\">\n\timport { NetworkIndicator } from 'entasis/network-indicator';\n</script>\n\n<NetworkIndicator />\n\n{@render children()}\n```\n\n## Props\n\n- **loading**: boolean = false\n - Controlled visibility. Use this when the owner already has request state or when rendering examples/previews.\n- **variant**: 'bar' | 'trail' | 'trail-bounce' = 'bar'\n - `bar` progressively grows one indicator. `trail` renders one randomly sized moving segment at a time. `trail-bounce` sends that random trail fully off one edge, then returns from the opposite edge.\n- **trailGap**: number = 0\n - Pause between trail passes in milliseconds. Only applies to `variant=\"trail\"`.\n- **color**: 'primary' | 'secondary' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' = 'neutral'\n - Applies the semantic color token to the bar.\n- **height**: number = 3\n - Height in pixels. Keep most navigation indicators between 2 and 6.\n- Animation duration and easing come from the `motion` theme slot — `theme={{ motion: { duration: 450, easing: 'expoOut' } }}` — not from props; see Motion below.\n- **label**: string = 'Loading'\n - Accessible label for the indeterminate `role=\"progressbar\"`.\n- **ref**: HTMLDivElement | null\n - Bindable root element reference while the indicator is visible.\n- **class**: string\n - Additional classes for the root bar.\n- **theme**: NetworkIndicatorThemeProps\n - Theme override for the root bar.\n\n## Helper API\n\n```ts\nimport {\n\thideNetworkIndicator,\n\tshowNetworkIndicator,\n\ttoggleNetworkIndicator\n} from 'entasis/network-indicator';\n```\n\nPrefer `showNetworkIndicator()` and `hideNetworkIndicator()` for async work. `toggleNetworkIndicator()` is available for simple demos or manual toggles, but it is easier to desynchronize in request lifecycles.\n\n## Patterns\n\n### Controlled Loading\n\n```svelte\n<script lang=\"ts\">\n\timport { NetworkIndicator } from 'entasis/network-indicator';\n\n\tlet loading = $state(false);\n</script>\n\n<NetworkIndicator {loading} color=\"primary\" label=\"Saving changes\" />\n```\n\n### Async Request\n\n```svelte\n<script lang=\"ts\">\n\timport { Button } from 'entasis/button';\n\timport {\n\t\thideNetworkIndicator,\n\t\tshowNetworkIndicator\n\t} from 'entasis/network-indicator';\n\n\tasync function save() {\n\t\tshowNetworkIndicator();\n\t\ttry {\n\t\t\tawait fetch('/api/save', { method: 'POST' });\n\t\t} finally {\n\t\t\thideNetworkIndicator();\n\t\t}\n\t}\n</script>\n\n<Button onclick={save}>Save</Button>\n```\n\n### Color Variations\n\n```svelte\n<NetworkIndicator loading color=\"primary\" />\n<NetworkIndicator loading color=\"success\" />\n<NetworkIndicator loading color=\"warning\" />\n<NetworkIndicator loading color=\"danger\" />\n```\n\n### Trail Variant\n\n```svelte\n<NetworkIndicator loading variant=\"trail\" color=\"primary\" theme={{ motion: { duration: 650 } }} trailGap={0} />\n<NetworkIndicator loading variant=\"trail\" color=\"success\" height={5} theme={{ motion: { duration: 450 } }} trailGap={120} />\n<NetworkIndicator loading variant=\"trail-bounce\" color=\"info\" theme={{ motion: { duration: 700 } }} trailGap={80} />\n```\n\n### Height Variations\n\n```svelte\n<NetworkIndicator loading height={2} />\n<NetworkIndicator loading height={4} color=\"primary\" />\n<NetworkIndicator loading height={6} color=\"info\" />\n```\n\n### Motion Variations\n\n```svelte\n<NetworkIndicator loading theme={{ motion: { duration: 300, easing: 'cubicInOut' } }} />\n<NetworkIndicator loading theme={{ motion: { duration: 450, easing: 'expoOut' } }} />\n<NetworkIndicator loading theme={{ motion: { duration: 500, easing: 'backOut' } }} />\n```\n\n### Theme Override\n\n```svelte\n<NetworkIndicator\n\tloading\n\tcolor=\"success\"\n\theight={5}\n\ttheme={{\n\t\troot: {\n\t\t\tbase: 'ui-network-indicator fixed top-0 left-0 w-full z-[9999] origin-left rounded-none lift-4'\n\t\t}\n\t}}\n/>\n```\n\n## Theme\n\nThe theme has two parts:\n\n- **root**: the fixed top bar.\n - `base`: positioning, origin, radius, z-index, and shared bar classes.\n - `variant`: `bar`, `trail`, or `trail-bounce` container styling.\n - `color`: semantic color variants.\n- **segment**: trail segment styling.\n - `base`: segment positioning, radius, opacity, shadow, and transform hints.\n - `color`: semantic color variants for each trail segment.\n\nThe default root base includes `ui-network-indicator`; keep that class if overriding the base because `toggleNetworkIndicator()` uses it to read current state.\n\n## Accessibility\n\nThe visible bar renders `role=\"progressbar\"` without a value because progress is indeterminate. Use a specific `label` when the loading context matters, such as \"Uploading files\" or \"Saving changes\". If screen readers need richer lifecycle announcements, pair the indicator with app-level live region text.\n\n## Motion\n\n- **motion** theme slot, keyed by `variant`: one growth step of the `bar` loop (`slow`), or\n one pass of the `trail` / `trail-bounce` variants (the `slower` token, 500ms). Only `duration` / `easing` are read.\n- Ladder: `<Theme components={{ 'network-indicator': { motion } }}>` →\n `setNetworkIndicatorTheme({ motion })` → `theme={{ motion: { duration, easing } }}`.\n- A resolved duration of 0 (reduced motion) holds the indicator still instead of looping.\n";
88
88
  readonly 'progress-circle': "\n# ProgressCircle Component\n\nProgressCircle is a compact determinate circular progress indicator with a visible track and an arc that animates when the value changes.\n\n## Basic Usage\n\n```svelte\n<ProgressCircle />\n```\n\n## Props\n\n- **value**: number (default: 0)\n - Progress value from 0 to 100. Values outside the range are clamped.\n- **size**: 'small' | 'normal' | 'large' (default: 'normal')\n - Selects semantic component geometry.\n- **diameter**: number\n - Optional explicit circle diameter in pixels.\n- **color**: 'primary' | 'secondary' | 'danger' | 'success' | 'warning' | 'info' | 'neutral' (default: 'primary')\n - Applies a theme color token to the animated arc.\n- **label**: string (default: 'Progress')\n - Accessible label used when the component is not decorative.\n- **decorative**: boolean (default: false)\n - Removes progress semantics and hides the element from assistive technology.\n- **class**: string\n - Additional classes for the root element.\n- **theme**: ProgressCircleThemeProps\n - Per-instance theme overrides.\n\n## Examples\n\n```svelte\n<ProgressCircle size=\"small\" />\n<ProgressCircle value={45} color=\"danger\" />\n<ProgressCircle value={72} diameter={56} color=\"success\" />\n```\n\n## Accessibility\n\n- The component renders `role=\"progressbar\"` with `aria-valuenow`, `aria-valuemin`, and `aria-valuemax` by default.\n- Use `label` to provide a specific accessible name.\n- Use `decorative` when nearby UI already announces the loading state.\n\n## Theme Parts\n\n- **root**: inline wrapper and color/size token host\n- **svg**: animated SVG element\n- **track**: background circle\n- **indicator**: active arc\n";
89
89
  readonly skeleton: "\n# Skeleton Component\n\nThe Skeleton component is a loading placeholder element that displays a pulsing animation to indicate that content is being loaded. It provides a visual feedback mechanism while data is being fetched or processed.\n\n## Basic Usage\n\n```svelte\n<Skeleton />\n```\n\n## Props\n\n### Core Props\n- **color**: 'primary' | 'secondary' | 'danger' | 'success' | 'warning' | 'info' | 'neutral' (default: 'neutral')\n - Determines the color scheme of the skeleton\n - neutral: Subtle achromatic fill (default)\n - primary, secondary, danger, success, warning, info: Semantic colors\n\n### Styling Props\n- **class**: string - Additional CSS classes for the skeleton container\n- **theme**: ComponentTheme - Custom theme overrides\n\n### Content Props\n- **children**: Snippet - Optional content to display inside the skeleton\n\n## Structure\n\n```\n<Skeleton>\n\t<Children /> <!-- Optional content -->\n</Skeleton>\n```\n\n## Examples\n\n### Basic Skeleton\n```svelte\n<Skeleton />\n```\n\n### Skeleton with Different Colors\n```svelte\n<div class=\"space-y-2\">\n\t<Skeleton color=\"primary\" class=\"h-4 w-full\" />\n\t<Skeleton color=\"danger\" class=\"h-4 w-full\" />\n\t<Skeleton color=\"success\" class=\"h-4 w-full\" />\n\t<Skeleton color=\"warning\" class=\"h-4 w-full\" />\n\t<Skeleton color=\"info\" class=\"h-4 w-full\" />\n</div>\n```\n\n### Skeleton with Custom Size\n```svelte\n<Skeleton class=\"h-12 w-full\" />\n```\n\n### Skeleton with Custom Width\n```svelte\n<Skeleton class=\"h-4 w-3/4\" />\n```\n\n### Circular Skeleton (for avatars)\n```svelte\n<Skeleton class=\"h-12 w-12 rounded-full\" />\n```\n\n### Text Line Skeletons\n```svelte\n<div class=\"space-y-2\">\n\t<Skeleton class=\"h-4 w-full\" />\n\t<Skeleton class=\"h-4 w-5/6\" />\n\t<Skeleton class=\"h-4 w-4/6\" />\n</div>\n```\n\n### Card Skeleton\n```svelte\n<div class=\"space-y-4\">\n\t<Skeleton class=\"h-48 w-full rounded-lg\" />\n\t<div class=\"space-y-2\">\n\t\t<Skeleton class=\"h-4 w-full\" />\n\t\t<Skeleton class=\"h-4 w-3/4\" />\n\t</div>\n</div>\n```\n\n### Table Row Skeleton\n```svelte\n<div class=\"flex gap-4\">\n\t<Skeleton class=\"h-10 w-10 rounded\" />\n\t<Skeleton class=\"h-10 flex-1\" />\n\t<Skeleton class=\"h-10 w-24\" />\n</div>\n```\n\n## Styling\n\nThe skeleton uses `animate-pulse` for the pulsing animation and supports color variants. You can customize the appearance by:\n\n1. Using the `color` prop to change the background color (default: 'neutral')\n2. Adding custom classes via the `class` prop\n3. Overriding the theme via the `theme` prop\n4. Using Tailwind utility classes for size, shape, and spacing\n\n## Common Patterns\n\n### Loading State Pattern\n```svelte\n{#if loading}\n\t<Skeleton class=\"h-64 w-full\" />\n{:else}\n\t<p>{article.body}</p>\n{/if}\n```\n\n### Multiple Skeletons\n```svelte\n<div class=\"space-y-4\">\n\t{#each { length: 3 } as _}\n\t\t<Skeleton class=\"h-20 w-full\" />\n\t{/each}\n</div>\n```\n\n## Accessibility\n\n- Skeletons are purely visual loading indicators\n- Consider adding `aria-label=\"Loading\"` or `aria-busy=\"true\"` for screen readers\n- Ensure skeletons match the approximate size and shape of the content being loaded\n- Replace skeletons with actual content as soon as data is available\n\n## Notes\n\n- The skeleton uses CSS animation (`animate-pulse`) which is provided by Tailwind CSS\n- The default color is 'neutral' which provides high visibility\n- Color variants use the theme's color system and adapt to your theme configuration\n- Skeletons should be replaced with actual content once loading is complete\n- Consider using skeletons that match the layout of the content being loaded for better UX\n- Use semantic colors (danger, success, warning) when the skeleton represents specific states\n\n## Theme Customization\n\nThe Skeleton component uses a theme object that can be customized using the `theme` prop or by setting a global theme.\n\n### Theme Structure\n\nThe theme object contains the following parts:\n- **root**: Main skeleton element styles\n\n### Available Variants\n\n**root**:\n- base: Base classes for skeleton element (includes animation)\n- Variants:\n - color: 'primary' | 'secondary' | 'danger' | 'success' | 'warning' | 'info' | 'neutral' - Background color\n\n### Usage Examples\n\n**Basic Theme Override**:\n```svelte\n<Skeleton \n theme={{\n root: {\n base: 'rounded-lg',\n color: {\n primary: 'bg-primary/30'\n }\n }\n }}\n/>\n```\n\n**Custom Animation**:\n```svelte\n<Skeleton \n theme={{\n root: {\n base: 'animate-pulse rounded-md bg-linear-to-r from-neutral/10 via-neutral/20 to-neutral/10',\n color: {\n neutral: 'bg-transparent'\n }\n }\n }}\n/>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setSkeletonTheme } from '../components/Skeleton/index.ts';\n \n setSkeletonTheme({\n root: {\n base: 'animate-pulse rounded-md',\n color: {\n neutral: 'bg-neutral/15',\n primary: 'bg-primary/20'\n }\n }\n });\n</script>\n```\n";
90
90
  readonly spinner: "\n# Spinner Component\n\nThe Spinner component is a standalone indeterminate loading indicator. It inherits `spinnerVariant` from Theme and allows a per-instance override. The `default` variant uses the global `.ui-spinner` engine from the Entasis Tailwind plugin.\n\n## Basic Usage\n\n```svelte\n<Spinner />\n```\n\n## Props\n\n- **size**: 'small' | 'normal' | 'large' (default: 'normal')\n - Controls indicator size and label typography.\n- **color**: 'primary' | 'secondary' | 'danger' | 'success' | 'warning' | 'info' | 'neutral' (default: 'neutral')\n - Applies a theme color token to the indicator.\n- **variant**: 'default' | 'grid' | 'pulse' | 'puff' | 'lines' | 'circles' (default: Theme spinnerVariant, then 'default')\n - Selects the indicator animation and overrides the global Theme setting.\n- **text**: string | Snippet\n - Optional visible loading text rendered after the indicator.\n- **children**: Snippet\n - Rich visible label content. When provided, it replaces `text`.\n- **label**: string (default: 'Loading')\n - Accessible label used when no visible text is rendered.\n- **decorative**: boolean (default: false)\n - Removes status semantics and hides the spinner from assistive technology.\n- **class**: string\n - Additional classes for the root element.\n- **theme**: SpinnerThemeProps\n - Per-instance theme overrides.\n\n## Examples\n\n### Icon-only Spinner\n\n```svelte\n<Spinner label=\"Loading results\" />\n```\n\n### Spinner With Text\n\n```svelte\n<Spinner text=\"Loading results\" />\n```\n\n### Indicator Variants\n\n```svelte\n<Spinner variant=\"grid\" />\n<Spinner variant=\"pulse\" />\n<Spinner variant=\"puff\" />\n<Spinner variant=\"lines\" />\n<Spinner variant=\"circles\" />\n```\n\n### Global Default\n\n```svelte\n<Theme spinnerVariant=\"pulse\">\n\t<Spinner />\n</Theme>\n```\n\n### Semantic Colors\n\n```svelte\n<div class=\"flex items-center gap-3\">\n\t<Spinner color=\"primary\" />\n\t<Spinner color=\"success\" />\n\t<Spinner color=\"danger\" />\n</div>\n```\n\n### Decorative Spinner\n\n```svelte\n<button aria-busy=\"true\">\n\t<Spinner decorative size=\"small\" />\n\tSaving\n</button>\n```\n\n## Accessibility\n\n- The component renders `role=\"status\"` and `aria-live=\"polite\"` by default.\n- When no visible text is provided, `label` becomes the accessible name.\n- Use `decorative` when another nearby element already announces the loading state.\n\n## Theme Customization\n\nThe theme object contains three parts:\n\n- **root**: root inline-flex wrapper\n- **indicator**: animated indicator element with size and variant classes\n- **label**: visible text wrapper\n\n```svelte\n<script>\n\timport { setSpinnerTheme } from 'entasis/spinner';\n\n\tsetSpinnerTheme({\n\t\tindicator: {\n\t\t\tsize: {\n\t\t\t\tnormal: '[--spinner-size:1.5rem]'\n\t\t\t}\n\t\t}\n\t});\n</script>\n```\n";
91
- readonly 'spinner-text': "\n# SpinnerText Component\n\nSpinnerText combines the existing Spinner with a stable-width sequence of loading messages. Messages cycle on a configurable delay and transition vertically or through a left-to-right reveal without shifting surrounding layout.\n\n## Import\n\n```svelte\n<script lang=\"ts\">\n\timport { SpinnerText } from 'entasis/spinner-text';\n</script>\n```\n\n## Basic usage\n\n```svelte\n<SpinnerText\n\ttexts={['Reading files', 'Building context', 'Preparing answer']}\n\tdelay={1800}\n\tshimmer\n/>\n```\n\n## Props\n\n- **texts**: `readonly string[]` (required) - Messages displayed in sequence. The first message is rendered during SSR.\n- **delay**: `number` (default: `2200`) - Milliseconds between message changes. Zero, negative, and non-finite values pause cycling.\n- **transition**: `'vertical' | 'reveal'` (default: `'vertical'`) - Moves the outgoing message down while the next enters from above, or replaces both through opposing left-to-right clip reveals.\n- **shimmer**: `boolean` (default: `false`) - Applies the Entasis shimmer utility to the active message.\n- **showSpinner**: `boolean` (default: `true`) - Shows or hides the leading Spinner.\n- **spinnerVariant**: `'default' | 'grid' | 'pulse' | 'puff' | 'lines' | 'circles'` (default: Theme `spinnerVariant`, then `'default'`) - Overrides the global spinner animation for this instance.\n- **spinner**: `Snippet<[SpinnerTextSpinnerPayload]>` - Replaces the default visual spinner. Receives the resolved `color`, `size`, and `variant`.\n- **size**: `'small' | 'normal' | 'large'` (default: `'normal'`) - Controls spinner dimensions, gap, text size, and line height.\n- **color**: `Colors` (default: `'neutral'`) - Semantic color applied to both spinner and text.\n- **label**: `string` (default: `'Loading'`) - Accessible fallback when `texts` is empty.\n- **ref**: `HTMLElement | null` (bindable) - Root status element.\n- **class**: `string` - Additional root classes.\n- **theme**: `SpinnerTextThemeProps` - Per-instance theme overrides.\n\nStandard Svelte attachments are spread onto the root status element.\n\n## Custom spinner\n\n```svelte\n<script lang=\"ts\">\n\timport { Spinner } from 'entasis/spinner';\n\timport { SpinnerText } from 'entasis/spinner-text';\n</script>\n\n<SpinnerText texts={['Thinking', 'Composing']} color=\"primary\">\n\t{#snippet spinner({ size, color })}\n\t\t<Spinner variant=\"circles\" decorative {size} {color} />\n\t{/snippet}\n</SpinnerText>\n```\n\n## Behavior\n\n- A root attachment owns the interval and restarts it when `texts` length or `delay` changes.\n- One or zero messages do not create an interval.\n- All messages occupy the same hidden CSS grid cell, so the component reserves the width of its longest message and does not resize on every transition.\n- The vertical transition uses the design system's configured duration and easing.\n- The reveal transition clips the outgoing text from the left while revealing the incoming text from the left.\n- Vertical uses 1.5 times the configured theme duration; reveal uses 2.5 times that duration. Both use the configured easing.\n- The default Spinner is visually reduced one step relative to the message line height. Custom spinner snippets retain full control over their dimensions.\n- Shimmer behavior remains owned by the existing global shimmer utility.\n- The default indicator delegates to Spinner and remains compatible with global spinner theme configuration.\n\n## Accessibility\n\n- The root uses `role=\"status\"`, `aria-live=\"polite\"`, and `aria-atomic=\"true\"`.\n- Visual transition layers and the spinner are hidden from assistive technology.\n- A single screen-reader-only message changes with the active text, avoiding duplicate announcements while outgoing and incoming visual layers overlap.\n- When `texts` is empty, `label` supplies the accessible status name.\n\n## Theme parts\n\n- **root** - Inline status wrapper, semantic color, and size-specific gap.\n- **spinner** - Default or custom spinner container.\n- **viewport** - Clipped text transition viewport.\n- **sizer** - Hidden grid that reserves the longest message width.\n- **sizerItem** - Individual hidden sizing message.\n- **message** - Active visual message and optional shimmer state.\n\n## Motion\n\n- **motion** theme slot, keyed by `mode`: the `vertical` slide runs on `slow`, the `reveal`\n wipe on `slower`. Only `duration` / `easing` are read; the geometry is fixed.\n- Ladder: `<Theme components={{ spinnerText: { motion } }}>` → `setSpinnerTextTheme({ motion })`\n → `theme.motion`. Reduced motion collapses it to 0 (the text swaps instantly).\n";
91
+ readonly 'spinner-text': "\n# SpinnerText Component\n\nSpinnerText combines the existing Spinner with a stable-width sequence of loading messages. Messages cycle on a configurable delay and transition vertically or through a left-to-right reveal without shifting surrounding layout.\n\n## Import\n\n```svelte\n<script lang=\"ts\">\n\timport { SpinnerText } from 'entasis/spinner-text';\n</script>\n```\n\n## Basic usage\n\n```svelte\n<SpinnerText\n\ttexts={['Reading files', 'Building context', 'Preparing answer']}\n\tdelay={1800}\n\tshimmer\n/>\n```\n\n## Props\n\n- **texts**: `readonly string[]` (required) - Messages displayed in sequence. The first message is rendered during SSR.\n- **delay**: `number` (default: `2200`) - Milliseconds between message changes. Zero, negative, and non-finite values pause cycling.\n- **transition**: `'vertical' | 'reveal'` (default: `'vertical'`) - Moves the outgoing message down while the next enters from above, or replaces both through opposing left-to-right clip reveals.\n- **shimmer**: `boolean` (default: `false`) - Applies the Entasis shimmer utility to the active message.\n- **showSpinner**: `boolean` (default: `true`) - Shows or hides the leading Spinner.\n- **spinnerVariant**: `'default' | 'grid' | 'pulse' | 'puff' | 'lines' | 'circles'` (default: Theme `spinnerVariant`, then `'default'`) - Overrides the global spinner animation for this instance.\n- **spinner**: `Snippet<[SpinnerTextSpinnerPayload]>` - Replaces the default visual spinner. Receives the resolved `color`, `size`, and `variant`.\n- **size**: `'small' | 'normal' | 'large'` (default: `'normal'`) - Controls spinner dimensions, gap, text size, and line height.\n- **color**: `Colors` (default: `'neutral'`) - Semantic color applied to both spinner and text.\n- **label**: `string` (default: `'Loading'`) - Accessible fallback when `texts` is empty.\n- **ref**: `HTMLElement | null` (bindable) - Root status element.\n- **class**: `string` - Additional root classes.\n- **theme**: `SpinnerTextThemeProps` - Per-instance theme overrides.\n\nStandard Svelte attachments are spread onto the root status element.\n\n## Custom spinner\n\n```svelte\n<script lang=\"ts\">\n\timport { Spinner } from 'entasis/spinner';\n\timport { SpinnerText } from 'entasis/spinner-text';\n</script>\n\n<SpinnerText texts={['Thinking', 'Composing']} color=\"primary\">\n\t{#snippet spinner({ size, color })}\n\t\t<Spinner variant=\"circles\" decorative {size} {color} />\n\t{/snippet}\n</SpinnerText>\n```\n\n## Behavior\n\n- A root attachment owns the interval and restarts it when `texts` length or `delay` changes.\n- One or zero messages do not create an interval.\n- All messages occupy the same hidden CSS grid cell, so the component reserves the width of its longest message and does not resize on every transition.\n- The vertical transition uses the design system's configured duration and easing.\n- The reveal transition clips the outgoing text from the left while revealing the incoming text from the left.\n- Vertical uses 1.5 times the configured theme duration; reveal uses 2.5 times that duration. Both use the configured easing.\n- The default Spinner is visually reduced one step relative to the message line height. Custom spinner snippets retain full control over their dimensions.\n- Shimmer behavior remains owned by the existing global shimmer utility.\n- The default indicator delegates to Spinner and remains compatible with global spinner theme configuration.\n\n## Accessibility\n\n- The root uses `role=\"status\"`, `aria-live=\"polite\"`, and `aria-atomic=\"true\"`.\n- Visual transition layers and the spinner are hidden from assistive technology.\n- A single screen-reader-only message changes with the active text, avoiding duplicate announcements while outgoing and incoming visual layers overlap.\n- When `texts` is empty, `label` supplies the accessible status name.\n\n## Theme parts\n\n- **root** - Inline status wrapper, semantic color, and size-specific gap.\n- **spinner** - Default or custom spinner container.\n- **viewport** - Clipped text transition viewport.\n- **sizer** - Hidden grid that reserves the longest message width.\n- **sizerItem** - Individual hidden sizing message.\n- **message** - Active visual message and optional shimmer state.\n\n## Motion\n\n- **motion** theme slot, keyed by `mode`: the `vertical` slide runs on `slow`, the `reveal`\n wipe on `slower`. Only `duration` / `easing` are read; the geometry is fixed.\n- Ladder: `<Theme components={{ 'spinner-text': { motion } }}>` → `setSpinnerTextTheme({ motion })`\n → `theme.motion`. Reduced motion collapses it to 0 (the text swaps instantly).\n";
92
92
  readonly toast: "\nThe toast function displays non-blocking notification messages to the user. It provides color-based methods (primary, secondary, success, warning, danger, info, neutral) that each return a Toast instance.\n\n\n**Usage:**\n```typescript\nimport { toast } from 'entasis/toast';\n\n// Basic toast with a color variant\ntoast.success({\n title: 'Success!',\n description: 'Your changes have been saved.',\n duration: 4000\n});\n\n// Toast with custom position\ntoast.danger({\n title: 'Error',\n description: 'Something went wrong.',\n position: 'top-center',\n duration: 5000\n});\n\n// Toast with loading state\ntoast.info({\n title: 'Processing',\n description: 'Please wait...',\n loading: true,\n duration: false // Don't auto-close\n});\n\n// Toast with callbacks\ntoast.warning({\n title: 'Warning',\n description: 'This action cannot be undone.',\n duration: 6000,\n onAfterOpen: (payload) => console.log('Toast opened:', payload.id),\n onDismiss: (payload) => console.log('Toast dismissed:', payload.id),\n onAutoDismiss: (payload) => console.log('Toast timed out:', payload.id)\n});\n```\n\n**Available Color Methods:**\n- `toast.primary(options)` - Primary color variant\n- `toast.secondary(options)` - Secondary color variant\n- `toast.success(options)` - Success/green variant\n- `toast.warning(options)` - Warning/yellow variant\n- `toast.danger(options)` - Danger/red variant\n- `toast.info(options)` - Info/blue variant\n- `toast.neutral(options)` - Neutral color variant\n\n**Parameters (all optional):**\n- `title` (Slot or string): The toast title text\n- `description` (Slot or string) optional: The toast description/message text\n- `position` (ToastPosition, optional): Position on screen. Options: `'top-left'`, `'top-right'`, `'top-center'`, `'bottom-left'`, `'bottom-right'`, `'bottom-center'`, plus `'banner-top'` / `'banner-bottom'` which render a full screen-width bar flush to the top/bottom edge. Default: `'bottom-right'`. Swipe axis follows the anchor: left/right corners swipe horizontally, center + banner positions swipe vertically.\n- `duration` (number | false, optional): Time in milliseconds before auto-closing. Set to `false` to disable auto-close. Default: 4000ms\n- `closeOnClick` (boolean, optional): If true, clicking the toast closes it. Default: inherited from Toaster\n- `showCloseIcon` (boolean, optional): If true, shows a close button. Default: inherited from Toaster\n- `dismissible` (boolean, optional): If false, prevents user from dismissing. Default: inherited from Toaster\n- `richColors` (boolean, optional): If true, uses richer color variants. Default: inherited from Toaster\n- `loading` (boolean, optional): If true, shows a loading spinner using Theme's global `spinnerVariant`\n- `progress` (boolean, optional): If true, shows a bar counting down the remaining duration (pauses on hover). Only appears when the toast has a finite `duration`. Can also be set on `<Toaster progress />` as a default.\n- `swipeToDismiss` (boolean, optional, default true): Drag the toast toward its anchored screen edge (down for bottom-*, up for top-*) past a threshold to dismiss it; dragging the other way rubber-bands. A manual dismiss fires `onDismiss`, not `onAutoDismiss`.\n- `closeOnClick` (boolean, optional, default false): Dismiss when the toast body is clicked. Off by default now that swipe-to-dismiss exists; the close icon and swipe are the primary dismiss affordances.\n- `size` (Sizes, optional): Size of the toast — scales padding, corner radius, type and icon. Options: `'small'`, `'normal'`, `'large'` (default `'normal'`). Can be defaulted for all toasts with `<Toaster size=\"...\" />`.\n- `prefix` (Slot | false, optional): Content before the text. `false` hides the default icon\n- `suffix` (Slot, optional): Content to display after the toast text\n- `actions` (ToastAction[], optional): Buttons rendered inside the toast. `ToastAction` is full Button props plus `content` (the label) and `dismiss` (default true — clicking dismisses the toast). Each button's `onclick` runs with the native MouseEvent, then the toast fires `onDismiss`.\n- `closeIcon` (Slot, optional): Custom close button component\n- `icon` (string, optional): Icon name to display before the toast text\n- `important` (boolean, optional): Uses `role=\"alert\"` + assertive announcements for screen readers\n- `transition` (FSOProps, optional): Enter/exit transition override for this toast\n- `theme` (ToastThemeProps, optional): Theme overrides for this toast alone, layered over the `<Toaster theme>` object (`base` classes are appended, so the per-toast ones win)\n- `id` (string, optional): Custom ID for the toast. Auto-generated if not provided\n- `onAfterOpen` (function, optional): Called once the toast finishes entering: `(payload: Toast) => void`\n- `onDismiss` (function, optional): Called on manual dismiss (close button, an action, or `toast.remove()`). Not called on timeout: `(payload: Toast) => void`\n- `onAutoDismiss` (function, optional): Called only when the toast times out after `duration`. Put deferred irreversible work here; it never runs if the toast is dismissed first: `(payload: Toast) => void`\n\n### Undo / deferred-commit pattern\n\nRemove the item from the UI immediately, defer the real irreversible action to `onAutoDismiss`, and offer an `Undo` action. Undo dismisses the toast manually, so `onAutoDismiss` never fires:\n\n```ts\nfunction deleteItemWithUndo(item) {\n removeFromUI(item); // optimistic\n toast.neutral({\n title: `Deleted \"${item.name}\"`,\n duration: 5000,\n actions: [{ content: 'Undo', onclick: () => restore(item) }],\n onAutoDismiss: () => commitDelete(item) // runs only if not undone\n });\n}\n```\n\n**Mounting order:** `toast()` never throws when no `<Toaster />` is mounted yet — the toast is queued and shown by the first Toaster that mounts. In development, a single `console.warn` reports a queue that is still waiting a tick later. Dismissing a queued toast drops it from the queue, and a `toast()` call made during SSR is discarded instead of queued.\n\n**Returns:**\nA `Toast` instance that you can use to programmatically control the root:\n- `toast.remove()` - Remove the toast manually\n- `toast.id` - Unique identifier\n- `toast.opts` - Toast options\n\n**Notes:**\n- Toasts are non-blocking and don't prevent user interaction\n- The toaster is a `role=\"region\"` landmark named \"Notifications\" (not a `<dialog>`); pressing F6 anywhere moves focus into it. Each toast is `role=\"status\"`, or `role=\"alert\"` when `important`\n- Toasts stacked away behind the front one are `inert` (rather than `aria-hidden`), so they take no clicks or tab stops until they surface\n- Multiple toasts can be displayed simultaneously and will stack based on position\n- Toasts pause their auto-close timer when hovered\n- Toasts can be dismissed by clicking the close icon, clicking the toast (if `closeOnClick` is true), or automatically after the duration expires\n\n## Theme Customization\n\nThe Toast component uses a theme object that can be customized using the `theme` prop in toast options or by setting a global theme.\n\n### Theme Structure\n\nThe theme object contains the following parts:\n- **motion**: Enter/exit transition preset, keyed by `position` (each toast flies in from the\n edge it is pinned to). Takes `in` / `out` FSO params plus a `duration` / `easing` motion\n token; overrides ladder `<Theme components={{ toast }}>` → `setToastTheme` → `theme.motion`\n → the Toaster's `transition` prop → a toast's own `transition`\n- **root**: Main toast container styles\n- **prefix**: Prefix icon/content styles\n- **suffix**: Suffix content styles\n- **content**: Content wrapper styles\n- **closeIcon**: Close button icon styles\n- **title**: Title text styles\n- **description**: Description text styles\n\n### Available Variants\n\n**root**:\n- base: Base classes for toast container\n- Variants:\n - richColors: boolean - Rich color variant styling\n - color: Color variants\n - size: 'small' | 'normal' | 'large' - Toast size\n\n**prefix**:\n- base: Base classes for prefix content\n- Variants:\n - size: 'small' | 'normal' | 'large' - Icon size\n - color: Color variants\n - richColors: boolean - Rich color variant styling\n\n**suffix**:\n- base: Base classes for suffix content\n- Variants:\n - size: 'small' | 'normal' | 'large' - Content size\n - color: Color variants\n - richColors: boolean - Rich color variant styling\n\n**content**:\n- base: Base classes for content wrapper\n- Variants:\n - size: 'small' | 'normal' | 'large' - Content size\n - color: Color variants\n - richColors: boolean - Rich color variant styling\n\n**closeIcon**:\n- base: Base classes for close button\n- Variants:\n - richColors: boolean - Rich color variant styling\n - color: Color variants\n\n**title**:\n- base: Base classes for title text\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n - color: Color variants\n - richColors: boolean - Rich color variant styling\n\n**description**:\n- base: Base classes for description text\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n - color: Color variants\n - richColors: boolean - Rich color variant styling\n\n### Usage Examples\n\n**Basic Theme Override**:\n```typescript\nimport { toast } from 'entasis/toast';\n\ntoast.success({\n title: 'Success',\n description: 'Operation completed',\n theme: {\n root: {\n base: 'rounded-xl raised-5',\n size: {\n normal: 'px-4 py-3'\n }\n }\n }\n});\n```\n\n**Custom Toast Styling**:\n```typescript\ntoast.danger({\n title: 'Error',\n description: 'Something went wrong',\n theme: {\n root: {\n base: 'border-2 border-red-500',\n richColors: {\n true: 'bg-red-50 border-red-500'\n }\n },\n title: {\n base: 'font-bold text-red-900'\n }\n }\n});\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setToastTheme } from '../components/Toast/index.ts';\n \n setToastTheme({\n root: {\n base: 'rounded-lg raised-4',\n size: {\n normal: 'px-3 py-2'\n }\n },\n title: {\n base: 'font-semibold'\n }\n });\n</script>\n```\n";
93
93
  readonly accordion: "\n# Accordion Component\n\nThe Accordion component provides an interactive collapsible container for organizing content. It supports single or multiple expanded items, various visual styles, and customizable transitions.\n\n## Basic Usage\n\n```svelte\n<script>\n\timport { Accordion } from 'entasis/accordion';\n</script>\n\n<Accordion \n\titems={[\n\t\t{ title: 'Section 1', content: 'Content 1' },\n\t\t{ title: 'Section 2', content: 'Content 2' }\n\t]}\n/>\n```\n\n## Props\n\n### Core Props\n- **items**: Array<Item> (bindable) - Array of accordion items to display\n- **value**: string[] (bindable) - Expanded item ids\n- **defaultValue**: string[] - Initially expanded item ids when value is omitted\n- **titleKey**: string - Key to extract title from items (default: 'title')\n- **contentKey**: string - Key to extract content from items (default: 'content')\n- **descriptionKey**: string - Key to extract description from items (default: 'description')\n\n### Layout Props\n- **variant**: 'classic' | 'card' | 'outline' (default: 'classic')\n - classic: flat rows separated by a muted border (nova/shadcn look) — the title underlines on hover, the chevron rotates\n - card: the rows wrapped in a raised surface (rows inset with px-4)\n - outline: the rows wrapped in a muted border (rows inset with px-4)\n\n- **size**: 'small' | 'normal' | 'large' (default: 'normal')\n - Scales typography only: title, description and content text sizes plus the icon size. Spacing is controlled by density.\n\n- **density**: 'compact' | 'normal' | 'comfortable' (default: 'normal')\n - Scales paddings and gaps only: trigger vertical padding, content bottom padding, header gap, and the gap between splitted items. Combine freely with size.\n\n- **splitted**: boolean (default: false) - Breaks the list into one surface per item with a gap: each item gets its own raised card (card), its own border (outline), or its own underline (classic)\n\n### Event Props\n- **onValueChange**: (value: string[]) => void - Called once when expanded item ids change\n- **onItemOpenChange**: (options: { item: Item; index: number; open: boolean }) => void - Called after one item's open state changes\n\n### Slot Props\n- **title**: Snippet - Custom title rendering\n- **description**: Snippet - Custom description rendering\n- **content**: Snippet - Custom content rendering\n- **icon**: Snippet - Custom icon rendering\n\n### Behavior Props\n- **oneAtATime**: boolean (default: true) - Whether only one item can be expanded at a time\n\n### Visual Props\n- **icon**: 'chevron' | 'plus-minus' | 'none' | Snippet (default: 'chevron')\n - chevron: Down chevron that rotates\n - plus-minus: Plus/minus glyph\n - none: Hide the indicator\n - Custom snippet for custom icons\n\n- **transition**: ResponsiveProps<FSOProps> - Slide transition override for the expanded content; beats the `motion` theme slot\n\n### Styling Props\n- **class**: string - Additional CSS classes\n- **theme**: ComponentTheme - Custom theme overrides\n\n## Structure\n\n```\n<Accordion>\n\t<AccordionItem>\n\t\t<AccordionTrigger>\n\t\t\t<AccordionHeader>\n\t\t\t\t<Title />\n\t\t\t\t<Description />\n\t\t\t</AccordionHeader>\n\t\t\t<Icon />\n\t\t</AccordionTrigger>\n\t\t<AccordionContent />\n\t</AccordionItem>\n</Accordion>\n```\n\n## Examples\n\n### Basic Example\n\n```svelte\n<script>\n\timport { Accordion } from 'entasis/accordion';\n\t\n\tlet items = [\n\t\t{ title: 'What is Svelte?', content: 'Svelte is a radical new approach to building user interfaces.' },\n\t\t{ title: 'Why use Svelte?', content: 'Svelte offers better performance and smaller bundle sizes.' }\n\t];\n</script>\n\n<Accordion {items} />\n```\n\n### Multiple Expanded Items\n\n```svelte\n<script>\n\timport { Accordion } from 'entasis/accordion';\n\t\n\tlet items = [\n\t\t{ title: 'Section 1', content: 'Content 1' },\n\t\t{ title: 'Section 2', content: 'Content 2' }\n\t];\n</script>\n\n<Accordion \n\t{items}\n\toneAtATime={false}\n/>\n```\n\n### Advanced Example\n\n```svelte\n<script>\n\timport { Accordion } from 'entasis/accordion';\n\t\n\tlet items = [\n\t\t{ \n\t\t\ttitle: 'Getting Started',\n\t\t\tdescription: 'Learn the basics',\n\t\t\tcontent: 'Start by installing Svelte...'\n\t\t}\n\t];\n</script>\n\n<Accordion {items} />\n```\n\n### Different Variants\n\n```svelte\n<script>\n\timport { Accordion } from 'entasis/accordion';\n\t\n\tlet items = [\n\t\t{ title: 'Item 1', content: 'Content 1' }\n\t];\n</script>\n\n<!-- Default flat look -->\n<Accordion {items} />\n\n<!-- Raised card container -->\n<Accordion variant=\"card\" {items} />\n\n<!-- Bordered container -->\n<Accordion variant=\"outline\" {items} />\n\n<!-- One surface per item -->\n<Accordion variant=\"card\" splitted {items} />\n```\n\n### Different Icons\n\n```svelte\n<script>\n\timport { Accordion } from 'entasis/accordion';\n\timport { starIcon } from 'entasis/icons/star';\n\t\n\tlet items = [\n\t\t{ title: 'Section 1', content: 'Content 1' }\n\t];\n</script>\n\n<!-- Chevron icon -->\n<Accordion icon=\"chevron\" {items} />\n\n<!-- Plus/minus icon -->\n<Accordion icon=\"plus-minus\" {items} />\n\n<!-- Custom icon (a snippet, no payload) -->\n<Accordion {items}>\n\t{#snippet icon()}\n\t\t{@render starIcon()}\n\t{/snippet}\n</Accordion>\n```\n\n### With Custom Keys\n\n```svelte\n<script>\n\timport { Accordion } from 'entasis/accordion';\n\t\n\tlet faqs = [\n\t\t{ question: 'How to install?', answer: 'Run npm install...' }\n\t];\n</script>\n\n<Accordion \n\titems={faqs}\n\ttitleKey=\"question\"\n\tcontentKey=\"answer\"\n/>\n```\n\n### With Event Handler\n\n```svelte\n<script>\n\timport { Accordion } from 'entasis/accordion';\n\t\n\tlet items = [\n\t\t{ title: 'Section 1', content: 'Content 1' }\n\t];\n\t\n\tfunction handleToggle({ item, index, open }) {\n\t\tconsole.log(`Item ${item.title} at index ${index} is now ${open ? 'open' : 'closed'}`);\n\t}\n</script>\n\n<Accordion \n\t{items}\n\tonItemOpenChange={handleToggle}\n/>\n```\n\n### Custom Content Rendering\n\n```svelte\n<script>\n\timport { Accordion } from 'entasis/accordion';\n\t\n\tlet items = [\n\t\t{ title: 'Section 1', content: 'Content 1' }\n\t];\n</script>\n\n<Accordion {items}>\n\t{#snippet title({ item })}\n\t\t<strong>{item.title}</strong>\n\t{/snippet}\n\t\n\t{#snippet content({ item })}\n\t\t<div class=\"p-4\">\n\t\t\t{@html item.content}\n\t\t</div>\n\t{/snippet}\n</Accordion>\n```\n\n## Accessibility\n\n- Automatically handles ARIA attributes\n- Keyboard navigation support (Enter/Space to toggle)\n- Focus management for expanded items\n- Screen reader friendly with proper roles\n\n## Notes\n\n- Items are automatically assigned IDs if not provided\n- Uses Melt UI's Accordion builder for accessibility\n- Smooth transitions with the library's themed slide transition\n- Supports bindable items for dynamic updates\n\n## Theme Customization\n\nThe Accordion component uses a theme object that can be customized using the `theme` prop or by setting a global theme.\n\n### Theme Structure\n\nThe theme object contains the following parts:\n- **root**: Main accordion container styles\n- **item**: Individual accordion item styles\n- **trigger**: Accordion trigger button styles\n- **header**: Header section styles (contains title and description)\n- **title**: Title text styles\n- **description**: Description text styles\n- **icon**: Expand/collapse icon styles\n- **content**: Content panel styles\n\n### Available Variants\n\n**root**:\n- base: Base classes for main container\n- Variants:\n - size: 'small' | 'normal' | 'large'\n - density: 'compact' | 'normal' | 'comfortable' - Gap between splitted items (via compounds)\n - variant: 'classic' | 'card' | 'outline' - Container surface (raised / bordered / none)\n - splitted: boolean - Gap layout for per-item surfaces\n\n**item**:\n- base: Base classes for individual items (muted separator when not splitted; own surface when splitted)\n- Variants:\n - size: 'small' | 'normal' | 'large' - Item size\n - density: 'compact' | 'normal' | 'comfortable'\n - variant: 'classic' | 'card' | 'outline' - Per-item surface when splitted\n - splitted: boolean\n - expanded: boolean - Expanded state styling\n\n**trigger**:\n- base: Base classes for trigger button\n- Variants:\n - size: 'small' | 'normal' | 'large'\n - density: 'compact' | 'normal' | 'comfortable' - Vertical padding\n - variant: 'classic' | 'card' | 'outline' - Horizontal inset on contained variants\n\n**header**:\n- base: Base classes for header section\n- Variants:\n - size: 'small' | 'normal' | 'large'\n - density: 'compact' | 'normal' | 'comfortable' - Gap between title and description\n\n**title**:\n- base: Base classes for title text (underlines on trigger hover)\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n\n**description**:\n- base: Base classes for description text\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n\n**icon**:\n- base: Base classes for expand/collapse icon (muted, rotates for the chevron)\n- Variants:\n - size: 'small' | 'normal' | 'large' - Icon size\n\n**content**:\n- base: Base classes for content panel\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n - density: 'compact' | 'normal' | 'comfortable' - Bottom padding\n - variant: 'classic' | 'card' | 'outline' - Horizontal inset on contained variants\n\n### Usage Examples\n\n**Bordered look (composition)**:\n```svelte\n<Accordion\n items={items}\n class=\"rounded-lg border border-neutral-muted\"\n theme={{\n item: { base: 'px-4' },\n content: { base: 'px-4' }\n }}\n/>\n```\n\n**Basic Theme Override**:\n```svelte\n<Accordion\n items={items}\n theme={{\n trigger: {\n base: 'state-layer'\n },\n item: {\n expanded: {\n true: 'bg-primary/5'\n }\n }\n }}\n/>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setAccordionTheme } from '../components/Accordion/index.ts';\n\n setAccordionTheme({\n trigger: {\n base: 'transition-colors',\n density: {\n normal: 'px-4 py-3'\n }\n }\n });\n</script>\n```\n\n## Motion\n\n- **motion** theme slot: a slide keyed by `axis` (`y` by default, `x` for a horizontal list).\n- Takes `in` / `out` slide params plus a `duration` / `easing` motion token.\n- Ladder: `<Theme components={{ accordion: { motion } }}>` → `setAccordionTheme({ motion })` →\n `theme.motion` → the `transition` prop. Reduced motion collapses it to 0.\n";
94
94
  readonly collapsible: "\n# Collapsible Component\n\nThe Collapsible component provides a way to show and hide content with a toggle trigger. It supports both controlled and uncontrolled modes, keyboard navigation, and smooth slide transitions.\n\n## Basic Usage\n\n```svelte\n<Collapsible>\n\t{#snippet trigger()}\n\t\tClick to expand\n\t{/snippet}\n\tThis content will be shown when expanded.\n</Collapsible>\n```\n\n## Props\n\n### Core Props\n- **open**: boolean (optional)\n - Current bindable disclosure state.\n\n- **defaultOpen**: boolean (default: false)\n - Initial open state when `open` is omitted.\n - Ignored when `open` prop is provided.\n\n- **disabled**: boolean (default: false)\n - Disables the collapsible trigger and prevents toggling.\n - Applies opacity styling and removes pointer events.\n\n- **onOpenChange**: (open: boolean) => void (optional)\n - Callback fired once after a component-owned open state change.\n - Receives the new open state as parameter.\n\n### Layout Props\n- **size**: 'small' | 'normal' | 'large' (default: 'normal')\n - Controls padding and text size of trigger and content.\n - small: Reduced padding (py-2 px-2) and text-sm\n - normal: Standard padding (py-3 px-4) and text-base\n - large: Increased padding (py-4 px-6) and text-lg\n\n- **icon**: 'chevron' | 'plus-minus' | 'none' | Snippet (default: 'chevron')\n - Disclosure indicator rendered in the trigger.\n - chevron: rotating chevron; plus-minus: plus/minus glyph; none: no indicator.\n - Pass a snippet (it receives `{ open }`) for a custom icon.\n\n### Content Props (Slots)\n- **trigger**: Snippet - Content rendered in the toggle button\n - Required for the component to function\n - Typically contains text, icons, or both\n\n- **children**: Snippet<{ open: boolean }> - Content shown when expanded\n - Rendered inside the content container with a slide transition\n - Receives the current `open` state as a payload\n\n### Advanced Props\n- **theme**: CollapsibleThemeProps - Theme configuration overrides\n - Allows customizing styles for container, trigger, and content parts\n\n## Examples\n\n### Example 1 - Uncontrolled\n```svelte\n<script lang=\"ts\">\n\timport { Collapsible } from 'entasis/collapsible';\n\timport { caretDownIcon } from 'entasis/icons/caretDown';\n</script>\n\n<Collapsible defaultOpen={false} icon=\"none\">\n\t{#snippet trigger()}\n\t\t<span>Toggle Content</span>\n\t\t{@render caretDownIcon()}\n\t{/snippet}\n\t<p>This content can be toggled.</p>\n</Collapsible>\n```\n\n### Example 2 - Controlled\n```svelte\n<script>\n\tlet open = false;\n</script>\n\n<Collapsible bind:open={open} onOpenChange={(open) => console.log('State:', open)}>\n\t{#snippet trigger()}\n\t\tToggle (Currently: {open ? 'Open' : 'Closed'})\n\t{/snippet}\n\t<p>Controlled content</p>\n</Collapsible>\n```\n\n### Example 3 - Explicit Children Snippet\n```svelte\n<Collapsible>\n\t{#snippet trigger()}\n\t\tShow Details\n\t{/snippet}\n\t{#snippet children({ open })}\n\t\t<p>This panel is {open ? 'open' : 'closed'}.</p>\n\t\t<ul>\n\t\t\t<li>Item 1</li>\n\t\t\t<li>Item 2</li>\n\t\t</ul>\n\t{/snippet}\n</Collapsible>\n```\n\n### Example 4 - Disabled State\n```svelte\n<Collapsible disabled={true}>\n\t{#snippet trigger()}\n\t\tDisabled Collapsible\n\t{/snippet}\n\tThis content cannot be toggled.\n</Collapsible>\n```\n\n### Example 5 - Different Sizes\n```svelte\n<Collapsible size=\"small\">\n\t{#snippet trigger()}\n\t\tSmall Collapsible\n\t{/snippet}\n\tSmall content\n</Collapsible>\n\n<Collapsible size=\"large\">\n\t{#snippet trigger()}\n\t\tLarge Collapsible\n\t{/snippet}\n\tLarge content\n</Collapsible>\n```\n\n## Structure\n\nThe component renders:\n- A container `<div>` with data attributes for state\n- A trigger `<button>` with ARIA attributes\n- A content `<div>` with slide transition (only when open)\n\n## Accessibility\n\n- **ARIA Attributes**:\n - `aria-expanded` on trigger indicates open/closed state\n - `aria-controls` links trigger to content element\n - `data-state` attribute provides state information for styling\n\n- **Keyboard Support**:\n - **Enter** or **Space**: Toggles the collapsible\n - Focus management handled by browser default behavior\n\n- **Semantic HTML**:\n - Uses `<button>` element for trigger (proper focus and keyboard handling)\n - Content is hidden from accessibility tree when closed\n\n## Notes\n\n- The component uses Svelte's built-in `slide` transition with a 200ms duration.\n- When `open` prop is provided, the component is controlled. Otherwise, it manages its own state.\n- Content is completely removed from DOM when closed (not just hidden) for better performance.\n\n## Theme Customization\n\nThe Collapsible component uses a theme object that can be customized using the `theme` prop or by setting a global theme.\n\n### Theme Structure\n\nThe theme object contains the following parts:\n- **root**: Main collapsible container styles\n- **trigger**: Toggle trigger button styles\n- **content**: Collapsible content panel styles\n- **icon**: Expand/collapse icon styles\n\n### Available Variants\n\n**root**:\n- base: Base classes for main container\n- Variants:\n - size: 'small' | 'normal' | 'large' - Container size\n\n**trigger**:\n- base: Base classes for trigger button\n- Variants:\n - size: 'small' | 'normal' | 'large' - Trigger padding and text size\n - disabled: boolean - Disabled state styling\n\n**content**:\n- base: Base classes for content panel\n- Variants:\n - size: 'small' | 'normal' | 'large' - Content gap and text size\n\n**icon**:\n- base: Base classes for expand/collapse icon\n- Variants:\n - size: 'small' | 'normal' | 'large' - Icon size\n\n### Usage Examples\n\n**Basic Theme Override**:\n```svelte\n<Collapsible \n theme={{\n root: {\n base: 'w-full'\n },\n trigger: {\n base: 'flex items-center justify-between w-full',\n size: {\n normal: 'px-4 py-2'\n }\n }\n }}\n>\n {#snippet trigger()}\n Toggle\n {/snippet}\n Content\n</Collapsible>\n```\n\n**Custom Trigger Styling**:\n```svelte\n<Collapsible \n theme={{\n trigger: {\n base: 'state-layer rounded-lg transition-colors',\n size: {\n large: 'px-6 py-4 text-lg'\n },\n disabled: {\n true: 'opacity-50 cursor-not-allowed'\n }\n },\n icon: {\n size: {\n normal: 'size-5'\n }\n }\n }}\n>\n {#snippet trigger()}\n Custom Trigger\n {/snippet}\n Content\n</Collapsible>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setCollapsibleTheme } from '../components/Collapsible/index.ts';\n \n setCollapsibleTheme({\n root: {\n base: 'w-full flex flex-col'\n },\n trigger: {\n base: 'transition-all hover:opacity-80',\n size: {\n normal: 'px-2 py-2 text-sm'\n }\n },\n content: {\n size: {\n normal: 'gap-2 mt-2'\n }\n }\n });\n</script>\n```\n\n## Motion\n\n- **motion** theme slot, keyed by `variant`: `default` slides the content open on the y axis,\n `peek` animates its clip height on `slow` / `enter`.\n- Ladder: `<Theme components={{ collapsible: { motion } }}>` → `setCollapsibleTheme({ motion })`\n → `theme.motion` → the `transition` prop. Reduced motion collapses it to 0.\n";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "entasis",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "dev": "vite dev",