entasis 0.4.1 → 0.6.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 (180) hide show
  1. package/README.md +1 -0
  2. package/dist/attachments/spinnerOverlay.theme.d.ts +2 -36
  3. package/dist/components/AIAskUserQuestion/aiAskUserQuestion.theme.d.ts +2 -30
  4. package/dist/components/AIChat/aiChat.theme.d.ts +2 -14
  5. package/dist/components/AIComposer/aiComposer.theme.d.ts +2 -50
  6. package/dist/components/AIContext/aiContext.theme.d.ts +2 -37
  7. package/dist/components/AIConversation/aiConversation.theme.d.ts +2 -4
  8. package/dist/components/AIFilePreview/aiFilePreview.theme.d.ts +2 -17
  9. package/dist/components/AIMarker/aiMarker.theme.d.ts +2 -18
  10. package/dist/components/AIMessage/aiMessage.theme.d.ts +2 -72
  11. package/dist/components/AIMessageActions/aiMessageActions.theme.d.ts +2 -29
  12. package/dist/components/AIModelSelector/aiModelSelector.theme.d.ts +2 -25
  13. package/dist/components/AIReasoning/aiReasoning.theme.d.ts +2 -9
  14. package/dist/components/AISuggestion/aiSuggestion.theme.d.ts +2 -6
  15. package/dist/components/AIThread/aiThread.theme.d.ts +2 -35
  16. package/dist/components/AIThreadToc/aiThreadToc.theme.d.ts +2 -44
  17. package/dist/components/AITool/aiTool.mcp.d.ts +1 -1
  18. package/dist/components/AITool/aiTool.mcp.js +1 -1
  19. package/dist/components/AITool/aiTool.theme.d.ts +2 -170
  20. package/dist/components/AITool/aiTool.theme.js +14 -12
  21. package/dist/components/Accordion/accordion.theme.d.ts +2 -135
  22. package/dist/components/Alert/alert.theme.d.ts +2 -88
  23. package/dist/components/AppShell/appShell.theme.d.ts +2 -34
  24. package/dist/components/AspectRatio/aspectRatio.theme.d.ts +2 -5
  25. package/dist/components/AudioPlayer/audioPlayer.theme.d.ts +2 -179
  26. package/dist/components/Avatar/avatar.theme.d.ts +2 -38
  27. package/dist/components/Avatar/avatarGroup.theme.d.ts +2 -17
  28. package/dist/components/Breadcrumbs/breadcrumbs.theme.d.ts +2 -33
  29. package/dist/components/Button/Button.svelte +15 -13
  30. package/dist/components/Button/button.theme.d.ts +2 -55
  31. package/dist/components/ButtonGroup/buttonGroup.theme.d.ts +2 -4
  32. package/dist/components/Card/card.theme.d.ts +2 -119
  33. package/dist/components/Carousel/carousel.theme.d.ts +2 -73
  34. package/dist/components/Chart/chart.theme.d.ts +2 -24
  35. package/dist/components/Chip/chip.theme.d.ts +2 -56
  36. package/dist/components/Code/code.theme.d.ts +2 -9
  37. package/dist/components/Collapsible/collapsible.theme.d.ts +2 -44
  38. package/dist/components/Command/command.theme.d.ts +2 -103
  39. package/dist/components/Confirmation/confirmation.theme.d.ts +2 -10
  40. package/dist/components/ContextMenu/contextMenu.theme.d.ts +2 -10
  41. package/dist/components/DataTable/dataTable.theme.d.ts +2 -160
  42. package/dist/components/Dialog/Dialog.svelte +16 -0
  43. package/dist/components/Dialog/dialog.mcp.d.ts +1 -1
  44. package/dist/components/Dialog/dialog.mcp.js +2 -1
  45. package/dist/components/Dialog/dialog.props.d.ts +5 -0
  46. package/dist/components/Dialog/dialog.theme.d.ts +2 -137
  47. package/dist/components/Dialog/dialog.theme.js +12 -8
  48. package/dist/components/Diff/diff.theme.d.ts +2 -6
  49. package/dist/components/DocumentViewer/documentViewer.theme.d.ts +2 -87
  50. package/dist/components/Empty/empty.theme.d.ts +2 -71
  51. package/dist/components/EventCalendar/eventCalendar.theme.d.ts +2 -3171
  52. package/dist/components/FloatingWindow/floatingWindow.theme.d.ts +2 -96
  53. package/dist/components/Form/Calendar/CalendarPrimitive.svelte.d.ts +2 -63
  54. package/dist/components/Form/Calendar/calendar.theme.d.ts +2 -63
  55. package/dist/components/Form/CheckboxesInput/checkboxesInput.theme.d.ts +2 -100
  56. package/dist/components/Form/ColorInput/colorInput.theme.d.ts +2 -32
  57. package/dist/components/Form/ColorPicker/colorPicker.theme.d.ts +2 -127
  58. package/dist/components/Form/Combobox/combobox.theme.d.ts +2 -50
  59. package/dist/components/Form/DateInput/dateInput.theme.d.ts +2 -26
  60. package/dist/components/Form/DateSelector/dateSelector.theme.d.ts +2 -17
  61. package/dist/components/Form/Field/field.theme.d.ts +2 -146
  62. package/dist/components/Form/File/fileInput.theme.d.ts +2 -41
  63. package/dist/components/Form/Form/form.state.svelte.d.ts +4 -4
  64. package/dist/components/Form/Form/form.theme.d.ts +2 -129
  65. package/dist/components/Form/Form/visibility.d.ts +54 -54
  66. package/dist/components/Form/KeyValueInput/keyValueInput.theme.d.ts +2 -50
  67. package/dist/components/Form/MultiStepForm/multiStepForm.state.svelte.d.ts +4 -4
  68. package/dist/components/Form/MultiStepForm/multiStepForm.theme.d.ts +2 -25
  69. package/dist/components/Form/NumberInput/numberInput.theme.d.ts +2 -25
  70. package/dist/components/Form/PasswordInput/passwordInput.theme.d.ts +2 -25
  71. package/dist/components/Form/PhoneInput/phoneInput.theme.d.ts +2 -112
  72. package/dist/components/Form/PinInput/pinInput.theme.d.ts +2 -38
  73. package/dist/components/Form/RadioInput/radioInput.theme.d.ts +2 -94
  74. package/dist/components/Form/Select/select.theme.d.ts +2 -71
  75. package/dist/components/Form/Slider/slider.theme.d.ts +2 -266
  76. package/dist/components/Form/Switch/switch.theme.d.ts +2 -40
  77. package/dist/components/Form/TagGroup/tagGroup.theme.d.ts +2 -19
  78. package/dist/components/Form/TagsInput/tagsInput.theme.d.ts +2 -53
  79. package/dist/components/Form/TextArea/textArea.theme.d.ts +2 -25
  80. package/dist/components/Form/TextInput/textInput.theme.d.ts +2 -25
  81. package/dist/components/Form/TimeInput/timeInput.theme.d.ts +2 -47
  82. package/dist/components/Form/VoiceInput/voiceInput.theme.d.ts +2 -155
  83. package/dist/components/GanttChart/ganttChart.theme.d.ts +2 -2478
  84. package/dist/components/Globe/globe.theme.d.ts +2 -13
  85. package/dist/components/Grid/grid.theme.d.ts +2 -18
  86. package/dist/components/Grid/gridSpan.theme.d.ts +2 -4
  87. package/dist/components/Heading/heading.theme.d.ts +2 -41
  88. package/dist/components/Hitbox/hitbox.theme.d.ts +2 -10
  89. package/dist/components/HoverCard/hoverCard.theme.d.ts +11 -27
  90. package/dist/components/HoverCard/hoverCard.theme.js +9 -4
  91. package/dist/components/ImageGallery/imageGallery.theme.d.ts +2 -6
  92. package/dist/components/ImageZoom/imageZoom.theme.d.ts +2 -16
  93. package/dist/components/Kanban/kanban.theme.d.ts +2 -60
  94. package/dist/components/Kbd/kbd.theme.d.ts +2 -33
  95. package/dist/components/Layout/layoutSpacing.d.ts +1 -1
  96. package/dist/components/LinkPreview/linkPreview.theme.d.ts +2 -58
  97. package/dist/components/Map/map.theme.d.ts +2 -14
  98. package/dist/components/Markdown/markdown.theme.d.ts +2 -10
  99. package/dist/components/Marquee/marquee.theme.d.ts +2 -37
  100. package/dist/components/MediaVolume/mediaVolumeControl.theme.d.ts +2 -22
  101. package/dist/components/Menu/menu.theme.d.ts +2 -12
  102. package/dist/components/MenuBar/menuBar.theme.d.ts +2 -16
  103. package/dist/components/MenuOption/menuOption.theme.d.ts +2 -75
  104. package/dist/components/Mermaid/mermaid.theme.d.ts +2 -15
  105. package/dist/components/MetadataList/metadataList.theme.d.ts +2 -97
  106. package/dist/components/Meter/meter.theme.d.ts +2 -111
  107. package/dist/components/MiniCalendar/miniCalendar.theme.d.ts +2 -71
  108. package/dist/components/NetworkIndicator/networkIndicator.theme.d.ts +2 -41
  109. package/dist/components/Overlay/overlay.theme.d.ts +2 -92
  110. package/dist/components/PageShell/pageShell.theme.d.ts +2 -36
  111. package/dist/components/Pagination/pagination.theme.d.ts +2 -108
  112. package/dist/components/Popover/popover.theme.d.ts +2 -40
  113. package/dist/components/PopupMenu/popupMenu.theme.d.ts +2 -4
  114. package/dist/components/ProgressCircle/progressCircle.theme.d.ts +2 -22
  115. package/dist/components/QRCode/qrCode.theme.d.ts +2 -19
  116. package/dist/components/Rating/rating.theme.d.ts +2 -37
  117. package/dist/components/Resizable/resizable.theme.d.ts +2 -65
  118. package/dist/components/RichTextInput/richTextInput.theme.d.ts +2 -167
  119. package/dist/components/ScrollArea/scrollArea.theme.d.ts +2 -15
  120. package/dist/components/SegmentedControl/segmentedControl.theme.d.ts +2 -76
  121. package/dist/components/SelectionMenu/selectionMenu.theme.d.ts +2 -5
  122. package/dist/components/Separator/separator.theme.d.ts +2 -33
  123. package/dist/components/Sidebar/Sidebar.svelte +8 -2
  124. package/dist/components/Sidebar/SidebarAction.svelte +2 -2
  125. package/dist/components/Sidebar/SidebarActivityBar.svelte +3 -3
  126. package/dist/components/Sidebar/SidebarDesktopShell.svelte +3 -0
  127. package/dist/components/Sidebar/SidebarDesktopShell.svelte.d.ts +1 -0
  128. package/dist/components/Sidebar/SidebarGroup.svelte +6 -6
  129. package/dist/components/Sidebar/SidebarMenuButton.svelte +15 -18
  130. package/dist/components/Sidebar/SidebarMenuItem.svelte +15 -21
  131. package/dist/components/Sidebar/SidebarMenuSubItem.svelte +5 -6
  132. package/dist/components/Sidebar/SidebarMobileDrawer.svelte +3 -1
  133. package/dist/components/Sidebar/SidebarMobileDrawer.svelte.d.ts +1 -0
  134. package/dist/components/Sidebar/SidebarPanel.svelte +3 -6
  135. package/dist/components/Sidebar/SidebarTreeNode.svelte +2 -2
  136. package/dist/components/Sidebar/sidebar.mcp.d.ts +1 -1
  137. package/dist/components/Sidebar/sidebar.mcp.js +1 -0
  138. package/dist/components/Sidebar/sidebar.props.d.ts +2 -0
  139. package/dist/components/Sidebar/sidebar.theme.d.ts +116 -540
  140. package/dist/components/Sidebar/sidebar.theme.js +73 -67
  141. package/dist/components/Skeleton/skeleton.theme.d.ts +2 -14
  142. package/dist/components/SortableList/sortableList.theme.d.ts +2 -43
  143. package/dist/components/Spinner/spinner.theme.d.ts +2 -41
  144. package/dist/components/SpinnerText/spinnerText.theme.d.ts +2 -49
  145. package/dist/components/Stack/stack.theme.d.ts +2 -12
  146. package/dist/components/Stat/stat.theme.d.ts +2 -132
  147. package/dist/components/Stepper/stepper.theme.d.ts +2 -22
  148. package/dist/components/Tabbar/tabbar.theme.d.ts +2 -110
  149. package/dist/components/Table/table.theme.d.ts +2 -42
  150. package/dist/components/TableOfContents/tableOfContents.theme.d.ts +2 -28
  151. package/dist/components/Tabs/tabs.theme.d.ts +2 -20
  152. package/dist/components/Theme/Theme.svelte +4 -4
  153. package/dist/components/Theme/theme.designTokens.d.ts +10 -0
  154. package/dist/components/Theme/theme.designTokens.js +14 -1
  155. package/dist/components/Theme/theme.state.svelte.js +3 -3
  156. package/dist/components/Timeline/timeline.theme.d.ts +2 -226
  157. package/dist/components/Toast/toast.theme.d.ts +2 -236
  158. package/dist/components/ToggleButton/toggleButton.theme.d.ts +2 -57
  159. package/dist/components/ToggleButtonGroup/toggleButtonGroup.theme.d.ts +2 -9
  160. package/dist/components/ToggleMenu/toggleMenu.theme.d.ts +2 -7
  161. package/dist/components/Tooltip/tooltip.theme.d.ts +2 -25
  162. package/dist/components/Tree/tree.theme.d.ts +2 -7
  163. package/dist/components/VideoPlayer/videoPlayer.theme.d.ts +2 -145
  164. package/dist/generated/componentContract.d.ts +1 -1
  165. package/dist/generated/componentContract.js +2 -0
  166. package/dist/generated/componentMcpRegistry.d.ts +5 -5
  167. package/dist/tailwind/colors.js +7 -1
  168. package/dist/tailwind/global.js +4 -1
  169. package/dist/tailwind/spacing.d.ts +13 -0
  170. package/dist/tailwind/spacing.js +5 -2
  171. package/dist/tailwind/theme.mcp.d.ts +1 -1
  172. package/dist/tailwind/theme.mcp.js +1 -1
  173. package/dist/utils/cva/cva.mcp.d.ts +1 -1
  174. package/dist/utils/cva/cva.mcp.js +1 -1
  175. package/dist/utils/cva/index.d.ts +1 -1
  176. package/dist/utils/cva/merge.d.ts +108 -0
  177. package/dist/utils/cva/merge.js +6 -2
  178. package/dist/utils/cva/theme.d.ts +36 -1
  179. package/dist/utils/cva/theme.js +25 -2
  180. package/package.json +1 -1
@@ -12,7 +12,7 @@ export declare const componentMcpRegistry: {
12
12
  readonly 'ai-composer': "\n# AIComposer\n\nAIComposer is a Markdown prompt composer built on the existing `RichTextInput`, `VoiceInput`, file-acceptance helpers, `SortableList`, `ScrollArea`, and `AIFilePreview`. It adds AI command, mention, reference, and skill tokens; optional voice capture; raw or managed files; queue editing; steering; submit/stop state; and optional `AIConversation` integration without owning transport.\n\n## Requires\n\nAIComposer embeds RichTextInput, which is built on Lexical. Those packages are optional peer dependencies of entasis, so install them alongside it:\n\n`pnpm add lexical @lexical/history @lexical/link @lexical/list @lexical/markdown @lexical/rich-text @lexical/selection @lexical/utils`\n\n## Import\n\n```svelte\n<script lang=\"ts\">\n import {\n AIComposer,\n type AIComposerAttachment,\n type AIComposerCommand,\n type AIComposerHandle,\n type AIComposerMentionItem,\n type AIComposerQueuedMessage,\n type AIComposerSkillItem,\n type AIComposerSubmitPayload\n } from '../components/AIComposer/index.ts';\n</script>\n```\n\n## State and defaults\n\n- `value`, `files`, `attachments`, and `queue` are bindable.\n- Omitted `value`, `files`, `attachments`, `busy`, and labels inherit from the nearest `AIConversation`. A supplied direct prop always wins.\n- `defaultValue` initializes an uncontrolled draft once; `onValueChange` reports each library edit once and stays silent for parent updates.\n- Provider queue synchronization is signature-based and idempotent. It never compares proxy queue objects to their raw counterparts.\n\n## Submission\n\n`onSubmit` receives `AIComposerSubmitPayload`: display `markdown`, model-ready `modelInput`, raw files, attachment records, normalized tokens, and command/file/mention/reference/skill id lists. Every submitted token has serialized MDX-style `markdown`.\n\n```svelte\n<AIComposer\n commands={[\n {\n id: 'summarize',\n label: 'Summarize',\n prompt: 'Summarize the request and preserve decisions and risks.'\n }\n ]}\n onSubmit={({ markdown, modelInput, tokens, files }) =>\n sendPrompt({ markdown, modelInput, tokens, files })}\n/>\n```\n\nWhen no direct submit callback is supplied, the nearest conversation receives a user message and the draft clears after successful submission. Direct callbacks retain the draft so application code controls when it clears. Callback failures render a danger alert. `onStop` overrides `conversation.requestStop()`; stop failures are also visible.\n\n## Trigger sources\n\n- `commands` drives `/`; it accepts a Svelte Pro-compatible command array or a trigger-source object.\n- `mentionItems` is the compatibility list for files, references, and skills.\n- `mentions` and `references` compose into `@`; `skills` drives `$`.\n- Trigger-source objects support items, title, empty copy, grouping, token-kind resolution, custom token conversion, sync/async search, and selection.\n- Compatibility callbacks are `onCommandSearch`, `onMentionSearch`, and `onSkillSearch`. Mention search receives `{ query, type }`; skill search falls back to `onMentionSearch({ query, type: 'skill' })`.\n- Synchronous searches stay synchronous. Promise searches expose loading/error/request state through the reused RichTextInput lifecycle and ignore stale responses.\n- A trigger source's `onSelect({ item, context })` is the pick event. The per-kind\n `onCommandInsert`, `onMentionInsert`, and `onSkillInsert` callbacks run after the token is\n inserted, so they are named for the insertion rather than the pick: `onSelect` is reserved for\n \"the user picked this item\" and one component cannot own three of them.\n- Those callbacks and `onSuggestionOpen`, `onSuggestionClose`, `onSuggestionQueryChange`, and `onSuggestionHighlightChange` receive normalized source/lifecycle data.\n\n## Files and attachments\n\nSet `fileDropzone` to enable the chooser, paste, and drag-and-drop intake. The composer delegates to the shared `FileDropzone`, exposes `data-file-drag-state=\"potential | valid | invalid\"`, and renders a default overlay while a file drag is active. Override its copy with `dropLabel` and `dropInvalidLabel`, or replace the overlay content through the `dropzone` slot, which receives `{ state, files, accept, multiple, maxFiles, maxFileSize }`. `fileMultiple`, accepted types, maximum count, and maximum bytes use the shared file acceptance rules and report detailed rejections through `onFileReject`.\n\nWith only `files`, the composer uses raw `File[]`. Supplying `attachments`, an attachment callback, or conversation attachment state activates managed attachments. Managed records use `pending | uploading | uploaded | failed`, keep stable ids across queue edits, show `previewUrl` or `remoteUrl`, and expose add/retry/remove callbacks. Rejected files and retry failures remain visible.\n\n## Voice input\n\nSet `voiceInput` to render the existing VoiceInput primitive before the submit control. `voiceInputVariant` is `compact | expandable` and defaults to `compact`. The expandable presentation grows into the remaining footer width while recording; compact remains a mic-sized control.\n\nConfigure capture with `voiceInputMinDuration`, `voiceInputMaxDuration`, `voiceInputColor`, the accessible labels, and `voiceInputTheme`.\n\n`onVoiceInput` is the only voice lifecycle callback. It receives the finalized recording as an `ArrayBuffer` and must return a promise. AIComposer clears the internal recording before playback can render and replaces the voice control with a spinner until the promise settles. Callback failures render on the voice field. AIComposer remains transport-free: the callback owns transcription, upload, or any other application workflow. Replacing the complete `footer` also replaces the integrated voice control.\n\n```svelte\n<AIComposer\n voiceInput\n voiceInputVariant=\"expandable\"\n onVoiceInput={(audioBuffer) => transcribe(audioBuffer)}\n/>\n```\n\n## Queue\n\nWhen `busy` and `queueWhileBusy` are true, submission creates a flat `AIComposerQueuedMessage` and clears the draft. Queue rows can be reordered, steered, edited, restored, cancelled, or have editing cancelled. The lifecycle callbacks are:\n\n- `onQueueChange`\n- `onQueuedMessageAdd`, `onQueuedMessageCancel`\n- `onQueuedMessageEditStart`, `onQueuedMessageEditCommit`, `onQueuedMessageEditCancel`\n- `onQueuedMessageReorder`, `onSteer`\n\nSingle-message queue callbacks receive `{ message, index }`; edit commits also include `previousMessage`.\n\nAIComposer does not automatically drain the queue when `busy` becomes false. Missing queue targets throw instead of reporting a false success.\n\n## Editor and composition\n\n`submitShortcut` is `none | enter | shift-enter | command-enter`. `toolbar` is `hover | fixed | both | none`; `formats` and `autoresize` are forwarded to RichTextInput.\n\n`header`, `prefix`, `suffix`, and `modelSelector` are content slots. `dropzone` customizes the active file-drop overlay. `footerStart`, `actions`, and replacement `footer` receive `{ value, files, attachments, isEmpty, isBusy }`. The default footer orders file/model controls at the start and custom actions, voice input, and submit/stop at the end.\n\nThe component handle exposes `focus`, `clear`, `insertText`, `insertItem`, `insertToken`, `insertCommand`, `insertMention`, `insertReference`, and `insertSkill`. `clear()` clears editor Markdown and token metadata, not attached files.\n\nThe root accepts native form attributes plus bindable `ref`, `class`, and `theme`. Theme parts cover root, dropzone/dropzone icon, header, files, file rows, body, editor, toolbar, errors, footer/actions, the voice-input region, and every queue region. `voiceInputTheme` is forwarded to the reused VoiceInput primitive.\n";
13
13
  readonly 'ai-reasoning': "\n# AIReasoning\n\nAIReasoning renders an AI reasoning trace in the Entasis Collapsible primitive. It opens when a stream starts, measures elapsed time in seconds, and closes shortly after the first streamed completion.\n\n## Import\n\n```svelte\n<script lang=\"ts\">\n\timport { AIReasoning } from 'entasis/ai-reasoning';\n</script>\n```\n\n## Basic usage\n\n```svelte\n<AIReasoning\n\tcontent={reasoningText}\n\t{streaming}\n\tthinkingMessages={['Planning', 'Checking constraints', 'Preparing response']}\n/>\n```\n\nThe default trigger displays a brain icon and a shimmer-only `SpinnerText` label while streaming. A supplied `thinkingMessages` list replaces the resolved `labels.thinking` value and advances every two seconds when it contains more than one message. The compact `labels` object also overrides the unknown-duration sentence and completed-duration formatter.\n\n## Streaming lifecycle\n\n- `open` starts from `defaultOpen ?? streaming`.\n- At the start of a streaming session, the component auto-opens once unless `defaultOpen={false}`.\n- Closing the panel manually during that stream keeps it closed; streaming does not force it open again.\n- When streaming ends, the measured duration is rounded up to whole seconds.\n- After the first observed stream completes, an open panel closes after `1000` ms by default. A trace that never streamed is not auto-closed.\n- An explicit `duration` is expressed in seconds and takes precedence over the measured duration.\n\nUse `defaultOpen={false}` to opt out of streaming auto-open without disabling manual toggling:\n\n```svelte\n<AIReasoning content={reasoningText} streaming defaultOpen={false} />\n```\n\n## Controlled state\n\n`open` is bindable. `onOpenChange` runs once for user toggles and automatic stream-driven open or close changes. Initialization and parent assignments do not invoke it.\n\n```svelte\n<script lang=\"ts\">\n\tlet open = $state(true);\n\tlet lastUserState = $state(open);\n\n\tfunction handleOpenChange(nextOpen: boolean) {\n\t\tlastUserState = nextOpen;\n\t}\n</script>\n\n<AIReasoning\n\tcontent={reasoningText}\n\tduration={8}\n\tbind:open\n\tonOpenChange={handleOpenChange}\n/>\n<p>Last user-selected state: {lastUserState ? 'open' : 'closed'}</p>\n```\n\n## Custom trigger and body\n\nA custom `trigger` replaces the complete default row, including its default label and caret. The Collapsible button remains the interactive and accessible owner. The trigger payload is `{ open, streaming, duration, message }`, where `message` is the currently displayed thinking label.\n\n```svelte\n<AIReasoning streaming thinkingMessages={['Planning', 'Checking']}>\n\t{#snippet trigger({ open, streaming, duration, message })}\n\t\t<span class=\"flex w-full items-center justify-between\">\n\t\t\t{#if streaming}\n\t\t\t\t<span>{message}</span>\n\t\t\t{:else if duration !== undefined}\n\t\t\t\t<span>Thought for {duration}s</span>\n\t\t\t{/if}\n\t\t\t<span>{open ? 'Hide' : 'Show'}</span>\n\t\t</span>\n\t{/snippet}\n\n\t{#snippet children({ message })}\n\t\t<p>Current step: {message}</p>\n\t{/snippet}\n</AIReasoning>\n```\n\n`content` is optional. When it is non-null, it is rendered as Markdown and takes precedence over `children`:\n\n```svelte\n<AIReasoning content=\"**This Markdown is rendered.**\" defaultOpen>\n\t<p>This custom body is ignored because content was supplied.</p>\n</AIReasoning>\n```\n\n## Markdown safety\n\nPass Markdown options through `markdown`. AIReasoning owns `content` and always forces `renderHtml={false}`, even if renderer options are spread into Markdown.\n\n```svelte\n<AIReasoning content={reasoningText} markdown={markdownOptions} />\n```\n\n## Theme slots\n\nThe AIReasoning `trigger` and `content` theme slots are composed into the actual Collapsible trigger button and content panel. `root` styles the Collapsible root; `icon`, `status`, and `duration` style the default trigger regions.\n\n```svelte\n<AIReasoning\n\tcontent={reasoningText}\n\tdefaultOpen\n\ttheme={{\n\t\troot: { base: 'w-full' },\n\t\ttrigger: { base: 'rounded-md px-2' },\n\t\tcontent: { base: 'mt-3 pl-5' }\n\t}}\n/>\n```\n\nGlobal overrides use `setAIReasoningTheme` from the same package entry.\n\n## Props\n\n- `content?: string`: Markdown trace. Takes precedence over custom children.\n- `streaming?: boolean`: Drives status labels, auto-open, duration measurement, and completion close.\n- `thinkingMessages?: readonly string[]`: Optional labels cycled every two seconds while streaming; takes precedence over `labels.thinking`.\n- `labels?: Partial<AIReasoningLabels>`: Default thinking text, unknown-duration text, and duration formatter.\n- `open?: boolean`: Bindable open state.\n- `defaultOpen?: boolean`: Initial state; false also opts out of streaming auto-open.\n- `onOpenChange?: (open: boolean) => void`: Component-owned open-state callback.\n- `duration?: number`: Controlled duration in seconds.\n- `autoCloseDelay?: number`: First-completion close delay in milliseconds; defaults to 1000.\n- `trigger?: Slot<AIReasoningState>`: Complete trigger replacement.\n- `children?: Slot<AIReasoningState>`: Custom body used only when content is omitted.\n- `markdown?: Omit<MarkdownProps, 'content' | 'renderHtml'>`: Markdown renderer options.\n- `class?: string`: Class merged onto the Collapsible root.\n- `theme?: AIReasoningThemeProps`: Root, trigger, and content theme overrides.\n- Additional attachments and DOM attributes are forwarded to the Collapsible root.\n";
14
14
  readonly 'ai-suggestion': "\n# AISuggestion and AISuggestions\n\nPrompt suggestions rendered as a horizontal, scroll-faded button row.\n\n- `AISuggestion` is the theme-aware button primitive, defaults to the soft variant, accepts regular Button size, color, and variant props, and reports semantic selection through `onSelect`.\n- `AISuggestions` owns horizontal scrolling, optional `scrollFade`, bindable `value`, `defaultValue`, disabled state, shared built-in item `variant`, and `onSelect`.\n- `defaultValue` initializes the selected suggestion when `value` is omitted. `onValueChange(value)` fires once when a user changes that selection; parent updates and selecting the same value stay silent. `onSelect(value)` reports every suggestion activation, including repeated selection.\n- Callback-naming decision: the selected suggestion is a value state, so it keeps the `value`/`defaultValue`/`onValueChange` trio, and `onSelect` stays the pick event on both components. `AIThread` and `AIChat` forward the same `onSelect` name for their empty-state suggestions.\n- Its `suggestion` snippet receives `{ suggestion, selected, disabled, select }` for composed item rendering.\n\n```svelte\n<script>import { AISuggestions } from '../components/AISuggestion/index.ts';</script>\n<AISuggestions suggestions={['Summarize', 'Explain', 'Compare']} bind:value />\n```\n\nUse conversation-owned suggestions through `AIThread` or `AIChat` when they are the empty transcript state. An explicit selection callback takes precedence over the default conversation input update.\n";
15
- readonly 'ai-tool': "\n# AITool\n\nRender one AI tool call or one collapsible group of consecutive calls. Non-empty `tools` takes precedence over `tool`. Missing statuses are inferred from output and errors, while arbitrary values use circular-safe depth and entry limits.\n\nExpanded call/group IDs use bindable `value`, initial `defaultValue`, and `onValueChange(value)`. The callback fires once for each user expansion change; parent prop updates stay silent. Nested rows inside a grouped call keep their own expansion state.\n\n```svelte\n<script lang=\"ts\">\n import { AITool, type AIToolCall } from '../components/AITool/index.ts';\n\n const tools: AIToolCall[] = [\n { id: 'search', name: 'search_docs', input: { query: 'Svelte' }, output: { count: 4 } },\n { id: 'read', name: 'read_page', status: 'running', input: { path: '/docs' } }\n ];\n let open = $state(['search']);\n</script>\n\n<AITool {tools} bind:value={open} multiple />\n```\n\nUse `icon`, `title`, `status`, `input`, `output`, `error`, or `content` snippets with a `{ tool, index }` payload. Default value panels use the existing Entasis ScrollArea and are capped vertically while supporting both scroll axes.\n\nDefault status is represented by the semantic left indicator: a spinner for active calls and a dot for settled calls. Use the `status` snippet only when a visible custom status treatment is required.\n\nDefault input and output sections use compact sign-in and sign-out icons. Their configured labels remain available to assistive technology and on hover.\n\nUse `toggleIcon=\"none\"` for the default minimal trigger, `chevron` for a rotating disclosure icon, or `plus-minus` for plus/minus expansion controls. The choice applies to both group and child triggers.\n\nThe default `ghost` variant renders an unframed tool call. Use `card` for an elevated surface, `outline` for a transparent bounded surface, or `soft` for a subtle status-aware tint. Group triggers keep intrinsic width independently from their expanded call content, while each child call receives the same variant around its complete row and panel.\n";
15
+ readonly 'ai-tool': "\n# AITool\n\nRender one AI tool call or one collapsible group of consecutive calls. Non-empty `tools` takes precedence over `tool`. Missing statuses are inferred from output and errors, while arbitrary values use circular-safe depth and entry limits.\n\nExpanded call/group IDs use bindable `value`, initial `defaultValue`, and `onValueChange(value)`. The callback fires once for each user expansion change; parent prop updates stay silent. Nested rows inside a grouped call keep their own expansion state.\n\n```svelte\n<script lang=\"ts\">\n import { AITool, type AIToolCall } from '../components/AITool/index.ts';\n\n const tools: AIToolCall[] = [\n { id: 'search', name: 'search_docs', input: { query: 'Svelte' }, output: { count: 4 } },\n { id: 'read', name: 'read_page', status: 'running', input: { path: '/docs' } }\n ];\n let open = $state(['search']);\n</script>\n\n<AITool {tools} bind:value={open} multiple />\n```\n\nUse `icon`, `title`, `status`, `input`, `output`, `error`, or `content` snippets with a `{ tool, index }` payload. Default value panels use the existing Entasis ScrollArea and are capped vertically while supporting both scroll axes.\n\nDefault status is a bare mark on the left, no badge: a spinner for active calls and a coloured dot for settled calls (info while running, success, danger, muted when cancelled). Use the `status` snippet only when a visible custom status treatment is required.\n\nDefault input and output sections use compact sign-in and sign-out icons. Their configured labels remain available to assistive technology and on hover.\n\nUse `toggleIcon=\"none\"` for the default minimal trigger, `chevron` for a rotating disclosure icon, or `plus-minus` for plus/minus expansion controls. The choice applies to both group and child triggers.\n\nThe default `ghost` variant renders an unframed tool call. Use `card` for an elevated surface, `outline` for a transparent bounded surface, or `soft` for a subtle status-aware tint. Group triggers keep intrinsic width independently from their expanded call content, while each child call receives the same variant around its complete row and panel.\n";
16
16
  readonly 'ai-file-preview': "\n# AI file preview\n\nImport from `entasis/ai-file-preview`.\n\nAIFilePreview displays a File or file metadata, a name, preview URL, upload status, and errors. The size on file metadata is a byte count. onRemove and onRetry report the corresponding actions. It inherits native div attributes and accepts theme overrides for its preview parts.\n";
17
17
  readonly 'aspect-ratio': "\n# AspectRatio Component\n\nThe AspectRatio component maintains a consistent aspect ratio for its content, ensuring that content scales proportionally regardless of its natural dimensions. This is particularly useful for images, videos, and other media that need to maintain specific proportions.\n\n## Basic Usage\n\n```svelte\n<AspectRatio ratio=\"16x9\">\n\t{#snippet children()}\n\t\t<img src=\"/image.jpg\" alt=\"Description\" />\n\t{/snippet}\n</AspectRatio>\n```\n\n## Props\n\n### Core Props\n- **ratio**: '2x1' | '2x3' | '16x9' | '4x3' | '1x1' | '3x4' | '3x2' | '9x16' | '1x2' (default: '2x1')\n - Specifies the aspect ratio to maintain\n - '2x1': 2:1 ratio (wide landscape)\n - '2x3': 2:3 ratio (portrait)\n - '16x9': 16:9 ratio (widescreen video)\n - '4x3': 4:3 ratio (traditional display)\n - '1x1': 1:1 ratio (square)\n - '3x4': 3:4 ratio (portrait)\n - '3x2': 3:2 ratio (photo)\n - '9x16': 9:16 ratio (vertical video/phone)\n - '1x2': 1:2 ratio (tall portrait)\n\n### Layout Props\n- **class**: string - Additional CSS classes for the aspect ratio container\n- **ref**: HTMLElement | null - Reference to the aspect ratio container element\n\n### Content Props (Slots)\n- **children**: Snippet - Content to be displayed within the aspect ratio container\n\n### Styling Props\n- **theme**: AspectRatioThemeProps - Custom theme overrides\n\n## Structure\n\nThe AspectRatio component uses a two-layer structure:\n\n```\n<div class=\"relative w-full overflow-hidden aspect-[ratio]\" data-aspect-ratio-wrapper=\"\">\n\t<div class=\"absolute inset-0 h-full w-full\">\n\t\t<!-- Your content -->\n\t</div>\n</div>\n```\n\nThe outer container maintains the aspect ratio with overflow hidden to prevent content overflow, while the inner content fills the available space using absolute positioning.\n\n## Examples\n\n### Image with 16:9 Aspect Ratio\n```svelte\n<AspectRatio ratio=\"16x9\">\n\t{#snippet children()}\n\t\t<img src=\"/hero-image.jpg\" alt=\"Hero\" class=\"h-full w-full object-cover\" />\n\t{/snippet}\n</AspectRatio>\n```\n\n### Square Image Gallery\n```svelte\n<div class=\"grid grid-cols-3 gap-4\">\n\t{#each images as image}\n\t\t<AspectRatio ratio=\"1x1\">\n\t\t\t{#snippet children()}\n\t\t\t\t<img src={image.src} alt={image.alt} class=\"h-full w-full object-cover rounded-lg\" />\n\t\t\t{/snippet}\n\t\t</AspectRatio>\n\t{/each}\n</div>\n```\n\n### Video Container\n```svelte\n<AspectRatio ratio=\"16x9\">\n\t{#snippet children()}\n\t\t<iframe\n\t\t\tsrc=\"https://www.youtube.com/embed/...\"\n\t\t\tclass=\"h-full w-full\"\n\t\t\tallowfullscreen\n\t\t></iframe>\n\t{/snippet}\n</AspectRatio>\n```\n\n### Portrait Image\n```svelte\n<AspectRatio ratio=\"3x4\">\n\t{#snippet children()}\n\t\t<img src=\"/portrait.jpg\" alt=\"Portrait\" class=\"h-full w-full object-cover\" />\n\t{/snippet}\n</AspectRatio>\n```\n\n### Vertical Video (9:16)\n```svelte\n<AspectRatio ratio=\"9x16\">\n\t{#snippet children()}\n\t\t<video src=\"/vertical-video.mp4\" class=\"h-full w-full object-cover\" controls></video>\n\t{/snippet}\n</AspectRatio>\n```\n\n### Card with Fixed Aspect Ratio\n```svelte\n<Card>\n\t{#snippet title()}\n\t\tCard Title\n\t{/snippet}\n\t{#snippet children()}\n\t\t<AspectRatio ratio=\"16x9\">\n\t\t\t<div class=\"bg-gradient-to-br from-primary to-secondary flex h-full w-full items-center justify-center\">\n\t\t\t\t<span class=\"text-primary-contrast text-2xl font-bold\">Content</span>\n\t\t\t</div>\n\t\t</AspectRatio>\n\t\t<p>Card content below the aspect ratio container.</p>\n\t{/snippet}\n</Card>\n```\n\n### Responsive Aspect Ratio\n```svelte\n<AspectRatio ratio=\"16x9\" class=\"max-w-4xl\">\n\t{#snippet children()}\n\t\t<img src=\"/responsive-image.jpg\" alt=\"Responsive\" class=\"h-full w-full object-cover\" />\n\t{/snippet}\n</AspectRatio>\n```\n\n## Accessibility\n\n- The component maintains semantic structure without adding unnecessary ARIA attributes\n- Ensure images within the component have proper `alt` attributes\n- Videos should include proper captions and controls\n\n## Notes\n\n- The aspect ratio is maintained using the padding-bottom technique (padding-bottom percentage is calculated from the ratio)\n- This ensures compatibility across all browsers and maintains the aspect ratio regardless of content size\n- Content inside should use `object-cover` or `object-contain` classes for images/videos to fill the space properly\n- The component uses absolute positioning for the inner content container to ensure proper scaling\n- Works well with responsive images and videos\n- Can be nested within other components like Card, Dialog, etc.\n\n## Theme Customization\n\nThe AspectRatio 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**: Outer aspect ratio container styles\n- **content**: Inner content container styles\n\n### Available Variants\n\n**root**:\n- base: Base classes for the outer container (maintains aspect ratio)\n\n**content**:\n- base: Base classes for the inner content container (fills the aspect ratio space)\n\n### Usage Examples\n\n**Basic Theme Override**:\n```svelte\n<AspectRatio \n ratio=\"16x9\"\n theme={{\n root: {\n base: 'rounded-lg overflow-hidden lift-3'\n },\n content: {\n base: 'bg-gradient-to-br from-primary to-secondary'\n }\n }}\n>\n {#snippet children()}\n <img src=\"/image.jpg\" alt=\"Image\" class=\"h-full w-full object-cover\" />\n {/snippet}\n</AspectRatio>\n```\n\n**Custom Container Styling**:\n```svelte\n<AspectRatio \n ratio=\"1x1\"\n theme={{\n root: {\n base: 'rounded-full border-4 border-primary overflow-hidden'\n },\n content: {\n base: 'p-4 flex items-center justify-center'\n }\n }}\n>\n {#snippet children()}\n <div class=\"text-center\">Square Content</div>\n {/snippet}\n</AspectRatio>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setAspectRatioTheme } from '../components/AspectRatio/index.ts';\n \n setAspectRatioTheme({\n root: {\n base: 'rounded-xl overflow-hidden lift-4'\n },\n content: {\n base: 'transition-transform hover:scale-105'\n }\n });\n</script>\n```\n";
18
18
  readonly card: "\n# Card Component\n\nThe Card component is a flexible container component used to display content in a structured, visually distinct card format. It supports multiple sections (header, title, description, action, content, footer) through slots and can be made interactive with links or click handlers.\n\n## Basic Usage\n\n```svelte\n<Card>\n\t{#snippet title()}\n\t\tCard Title\n\t{/snippet}\n\t{#snippet description()}\n\t\tCard description text\n\t{/snippet}\n\t{#snippet children()}\n\t\tCard content goes here\n\t{/snippet}\n</Card>\n```\n\n## Props\n\n### Core Props\n- **color**: 'primary' | 'secondary' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' (default: 'neutral')\n - Determines the color scheme of the card\n\n- **variant**: 'solid' | 'outline' | 'soft' | 'ghost' (default: 'solid')\n- **elevation**: 1 | 2 | 3 | 4 | 5 (default: 1) - Elevation step a solid card lifts by on the theme's elevation scale; other variants cast no shadow\n - solid: Filled background with shadow (raised effect)\n - outline: Transparent background with colored border\n - soft: Semi-transparent background with color\n - ghost: Transparent background, no border\n\n- **size**: 'small' | 'normal' | 'large' (default: 'normal')\n - Scales the typography only: title (text-sm / text-base / text-lg), description and body text\n - Combine with density to control spacing independently\n\n- **density**: 'compact' | 'normal' | 'comfortable' (default: 'normal')\n - Controls paddings and gaps between header/content/footer\n - small: p-3 / gap-3 for dense dashboards\n - normal: p-4 / gap-4 everyday scale\n - large: p-6 / gap-6 roomy marketing/detail surfaces (vega default)\n\n### Layout Props\n- **disabled**: boolean (default: false)\n - Disables interactions and applies opacity styling\n\n- **showBorders**: boolean (default: false)\n - Shows edge-to-edge neutral-muted boundaries below the header and above the footer\n - Boundary spacing follows density and is owned by the adjacent header/footer section\n\n### Interactive Props\n- **href**: string - Makes the card a link (renders as <a>)\n- **target**: string - Link target attribute (e.g., '_blank')\n- **rel**: string - Link rel attribute (e.g., 'noopener noreferrer')\n- **onclick**: (event: MouseEvent) => void - Native click handler (renders as role=\"button\" with keyboard activation via Enter/Space)\n- **onpointerenter**: (event: PointerEvent) => void - Native pointer enter handler\n- **onpointerleave**: (event: PointerEvent) => void - Native pointer leave handler\n\nCards with href or onclick automatically get the internal `clickable` styling: pointer cursor, a hover effect matched to the surface (solids lift with a stronger ring and shadow, outline/ghost gain a translucent wash of the card color, soft deepens its tint), a pressed translate, and a keyboard focus ring. No prop needed — it follows from the interactivity.\n\nInteractive descendants stay independent: clicks (and Enter/Space) on buttons, links, form controls, or role=\"button|link|checkbox|radio|switch|menuitem\" elements inside the card never trigger the card's own onclick, and on href cards they don't navigate — only clicks on the card surface itself do.\n\n### Content Props (Slots)\n- **header**: Snippet - Custom header content (overrides default header structure)\n- **title**: Snippet - Card title text\n- **description**: Snippet - Card description text\n- **action**: Snippet | ButtonProps - Action button/element (positioned top-right in header)\n - Can be a snippet (custom content) or a ButtonProps object for easy composition\n - When using ButtonProps object, a Button component is automatically rendered\n- **content**: Snippet - Custom content (overrides default content structure)\n- **footer**: Snippet - Footer content\n- **children**: Snippet - Default content (rendered inside content section)\n\n### Styling Props\n- **class**: string - Additional CSS classes for the card container\n- **ref**: HTMLElement | null - Reference to the card element\n- **theme**: CardThemeProps - Custom theme overrides\n\n## Structure\n\nThe Card component uses a flexible slot-based structure:\n\n```\n<Card>\n\t<!-- Header section (optional) -->\n\t{#snippet header()}\n\t\t<!-- Custom header -->\n\t{/snippet}\n\t\n\t<!-- Or use default header structure -->\n\t{#snippet title()}\n\t\tTitle\n\t{/snippet}\n\t{#snippet description()}\n\t\tDescription\n\t{/snippet}\n\t{#snippet action()}\n\t\tAction button\n\t{/snippet}\n\t\n\t<!-- Content section -->\n\t{#snippet content()}\n\t\t<!-- Custom content -->\n\t{/snippet}\n\t\n\t<!-- Or use children -->\n\t{#snippet children()}\n\t\tDefault content\n\t{/snippet}\n\t\n\t<!-- Footer section (optional) -->\n\t{#snippet footer()}\n\t\tFooter content\n\t{/snippet}\n</Card>\n```\n\n## Examples\n\n### Basic Card\n```svelte\n<Card>\n\t{#snippet title()}\n\t\tCard Title\n\t{/snippet}\n\t{#snippet description()}\n\t\tThis is a description of the card content.\n\t{/snippet}\n\t{#snippet children()}\n\t\t<p>Card content goes here.</p>\n\t{/snippet}\n</Card>\n```\n\n### Card with Action Button (Snippet)\n```svelte\n<script lang=\"ts\">\n\timport { Card } from 'entasis/card';\n\timport { Button } from 'entasis/button';\n\timport { dotsThreeVerticalIcon } from 'entasis/icons/dotsThreeVertical';\n</script>\n\n<Card>\n\t{#snippet title()}\n\t\tSettings\n\t{/snippet}\n\t{#snippet description()}\n\t\tManage your preferences\n\t{/snippet}\n\t{#snippet action()}\n\t\t<Button variant=\"ghost\" size=\"small\">\n\t\t\t{@render dotsThreeVerticalIcon()}\n\t\t</Button>\n\t{/snippet}\n\t{#snippet children()}\n\t\t<p>Settings content...</p>\n\t{/snippet}\n</Card>\n```\n\n### Card with Action Button (ButtonProps Object)\n```svelte\n<Card\n\taction={{\n\t\tvariant: 'ghost',\n\t\tsize: 'small',\n\t\tchildren: 'Action'\n\t}}\n>\n\t{#snippet title()}\n\t\tSettings\n\t{/snippet}\n\t{#snippet description()}\n\t\tManage your preferences\n\t{/snippet}\n\t{#snippet children()}\n\t\t<p>Settings content...</p>\n\t{/snippet}\n</Card>\n```\n\n### Card with Action Button (ButtonProps with onclick)\n```svelte\n<Card\n\taction={{\n\t\tvariant: 'ghost',\n\t\tsize: 'small',\n\t\tchildren: 'Delete',\n\t\tcolor: 'danger',\n\t\tonclick: () => console.log('Deleted!')\n\t}}\n>\n\t{#snippet title()}\n\t\tDangerous Action\n\t{/snippet}\n\t{#snippet children()}\n\t\t<p>This action cannot be undone.</p>\n\t{/snippet}\n</Card>\n```\n\n### Interactive Card (Link)\n```svelte\n<Card href=\"/article/123\" target=\"_blank\" rel=\"noopener\">\n\t{#snippet title()}\n\t\tArticle Title\n\t{/snippet}\n\t{#snippet description()}\n\t\tRead more about this topic\n\t{/snippet}\n\t{#snippet children()}\n\t\t<p>Article preview...</p>\n\t{/snippet}\n</Card>\n```\n\n### Interactive Card (Click Handler)\n```svelte\n<Card onclick={(event) => console.log(event)} onpointerenter={(event) => console.log(event)}>\n\t{#snippet title()}\n\t\tClickable Card\n\t{/snippet}\n\t{#snippet children()}\n\t\t<p>Click me!</p>\n\t{/snippet}\n</Card>\n```\n\n### Card Variants\n```svelte\n<!-- Solid (default, with raised shadow) -->\n<Card variant=\"solid\" color=\"primary\">\n\t{#snippet children()}\n\t\tSolid card with shadow\n\t{/snippet}\n</Card>\n\n<!-- Outline -->\n<Card variant=\"outline\" color=\"primary\">\n\t{#snippet children()}\n\t\tCard with border\n\t{/snippet}\n</Card>\n\n<!-- Soft -->\n<Card variant=\"soft\" color=\"primary\">\n\t{#snippet children()}\n\t\tCard with muted background\n\t{/snippet}\n</Card>\n\n<!-- Ghost -->\n<Card variant=\"ghost\" color=\"primary\">\n\t{#snippet children()}\n\t\tTransparent card\n\t{/snippet}\n</Card>\n```\n\n### Sizes and Density\n```svelte\n<!-- size scales the typography -->\n<Card size=\"small\" title=\"Small type\" />\n<Card size=\"normal\" title=\"Normal type (default)\" />\n<Card size=\"large\" title=\"Large type\" />\n\n<!-- density scales the paddings and gaps -->\n<Card density=\"compact\" title=\"Dense dashboard card\" />\n<Card density=\"normal\" title=\"Everyday card (default)\" />\n<Card density=\"comfortable\" title=\"Roomy detail card\" />\n```\n\n### Card with Border Separators\nEnable edge-to-edge boundaries between sections using the `showBorders` prop.\n\n```svelte\n<Card showBorders={true}>\n\t{#snippet title()}\n\t\tTitle\n\t{/snippet}\n\t{#snippet children()}\n\t\tContent with border above\n\t{/snippet}\n\t{#snippet footer()}\n\t\tFooter with border above\n\t{/snippet}\n</Card>\n```\n\n### Custom Header\n```svelte\n<Card>\n\t{#snippet header()}\n\t\t<div class=\"flex items-center justify-between\">\n\t\t\t<h3>Custom Header</h3>\n\t\t\t<Button size=\"small\">Action</Button>\n\t\t</div>\n\t{/snippet}\n\t{#snippet children()}\n\t\tContent\n\t{/snippet}\n</Card>\n```\n\n### Disabled Card\n```svelte\n<Card disabled={true}>\n\t{#snippet title()}\n\t\tDisabled Card\n\t{/snippet}\n\t{#snippet children()}\n\t\tThis card is disabled\n\t{/snippet}\n</Card>\n```\n\n## Accessibility\n\n- When `href` is provided, the card renders as an `<a>` element with `role=\"link\"`\n- When `onclick` is provided without `href`, the card renders as a `<div>` with `role=\"button\"`\n- Disabled cards have `pointer-events-none` and reduced opacity\n- The card uses semantic HTML structure with data attributes for styling hooks\n\n## Notes\n\n- The `solid` variant draws a `ring-neutral-muted` hairline and lifts by `elevation` (`lift-1` … `lift-5`) on the theme's elevation scale\n- Header uses CSS Grid with container queries (@container) for responsive layout\n- Action slot is automatically positioned top-right when present (via `hasAction` variant)\n- Borders are optional and can be enabled with `showBorders={true}` (subtle neutral-muted, 1px)\n- All slots are optional - the card adapts to missing sections\n- `children` slot is rendered inside the content section by default\n- Custom `header` or `content` slots override the default structure\n\n## Theme Customization\n\nThe Card 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 card container styles\n- **header**: Card header section styles\n- **title**: Card title text styles\n- **description**: Card description text styles\n- **action**: Action button/element styles\n- **content**: Card content section styles\n- **footer**: Card footer section styles\n\n### Theme Type Definition\n\n```typescript\nimport type { CardThemeProps } from 'entasis/card';\n\n// Example theme customization\nconst customTheme: CardThemeProps = {\n root: {\n base: 'custom-base-classes',\n size: {\n small: 'py-2 gap-2',\n normal: 'py-4 gap-4',\n large: 'py-6 gap-6'\n },\n\t\tcolor: {\n\t\t\tprimary: 'bg-primary text-primary-contrast',\n\t\t\tneutral: 'bg-neutral text-neutral-contrast'\n\t\t},\n variant: {\n solid: 'bg-color border-color lift-1',\n outline: 'bg-transparent border-color'\n }\n },\n header: {\n density: {\n compact: 'px-2 gap-1',\n normal: 'px-4 gap-2',\n comfortable: 'px-6 gap-3'\n },\n hasAction: {\n true: 'grid-cols-[1fr_auto]',\n false: ''\n }\n },\n title: {\n size: {\n small: 'text-sm',\n normal: 'text-base',\n large: 'text-lg'\n }\n }\n};\n```\n\n### Available Variants\n\n**root**:\n- base: Base classes applied to all cards\n- Variants:\n - size: 'small' | 'normal' | 'large' - Typography scale\n - density: 'compact' | 'normal' | 'comfortable' - Padding and gap spacing\n - color: 'primary' | 'secondary' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' - Color scheme\n - variant: 'solid' | 'outline' | 'soft' | 'ghost' - Visual style variant\n - clickable: boolean - Internal; set automatically when href/onclick is present (hover, press, focus ring)\n - disabled: boolean - Disabled state styling\n\n**header**:\n- base: Base classes for header container\n- Variants:\n - size: 'small' | 'normal' | 'large' - Padding and gap spacing\n - hasAction: boolean - Grid layout when action is present\n - hasBorder: boolean - Border styling\n - variant: 'solid' | 'outline' | 'soft' | 'ghost' - Inherited from card\n\n**title**:\n- base: Base classes for title text\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n - variant: 'solid' | 'outline' | 'soft' | 'ghost' - Text color based on card variant\n\n**description**:\n- base: Base classes for description text\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n - variant: 'solid' | 'outline' | 'soft' | 'ghost' - Text color based on card variant\n\n**action**:\n- base: Base classes for action element (positioned top-right)\n\n**content**:\n- base: Base classes for content section\n- Variants:\n - size: 'small' | 'normal' | 'large' - Horizontal padding\n - hasBorder: boolean - Border styling\n - hasBorderTop: boolean - Top border\n - hasBorderBottom: boolean - Bottom border\n\n**footer**:\n- base: Base classes for footer section\n- Variants:\n - size: 'small' | 'normal' | 'large' - Padding and gap spacing\n - hasBorder: boolean - Border styling\n\n### Usage Examples\n\n**Basic Theme Override**:\n```svelte\n<Card \n theme={{\n root: {\n base: 'border-2 border-dashed',\n variant: {\n solid: 'raised-5'\n }\n },\n title: {\n size: {\n large: 'text-2xl font-bold'\n }\n }\n }}\n>\n {#snippet title()}\n Custom Styled Card\n {/snippet}\n</Card>\n```\n\n**Color and Variant Customization**:\n```svelte\n<Card \n color=\"primary\"\n variant=\"outline\"\n theme={{\n root: {\n variant: {\n outline: 'border-4 border-primary/50 bg-primary/5'\n }\n },\n content: {\n density: {\n comfortable: 'px-8 py-6'\n }\n }\n }}\n>\n {#snippet children()}\n Custom outline card\n {/snippet}\n</Card>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setCardTheme } from '../components/Card/index.ts';\n \n setCardTheme({\n root: {\n base: 'rounded-2xl transition-all duration-300',\n variant: {\n solid: 'raised-4 hover:raised-5',\n outline: 'border-2 hover:border-opacity-80'\n }\n },\n header: {\n density: {\n normal: 'px-6 gap-3'\n }\n }\n });\n</script>\n```\n";
@@ -25,7 +25,7 @@ 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- **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";
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
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";
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";
@@ -104,7 +104,7 @@ export declare const componentMcpRegistry: {
104
104
  readonly 'menu-bar': "\n# MenuBar Component\n\nMenuBar composes several PopupMenu and Menu instances into one horizontal application menu. A click or keyboard action opens the first menu. While any menu is open, moving the pointer or keyboard focus across another top-level trigger switches to that menu immediately.\n\n## Basic Usage\n\n```svelte\n<script lang=\"ts\">\n\timport { MenuBar, type MenuBarMenu } from 'entasis/menu-bar';\n\n\tconst menus: MenuBarMenu[] = [\n\t\t{\n\t\t\tlabel: 'File',\n\t\t\titems: [\n\t\t\t\t{ type: 'option', title: 'New file' },\n\t\t\t\t{ type: 'option', title: 'Open...' },\n\t\t\t\t{ type: 'separator' },\n\t\t\t\t{ type: 'option', title: 'Save' }\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\tlabel: 'Edit',\n\t\t\titems: [\n\t\t\t\t{ type: 'option', title: 'Undo' },\n\t\t\t\t{ type: 'option', title: 'Redo' }\n\t\t\t]\n\t\t}\n\t];\n</script>\n\n<MenuBar {menus} />\n```\n\n## Interaction\n\n- Click, Enter, Space, ArrowDown, or ArrowUp opens the focused top-level menu.\n- ArrowLeft and ArrowRight move between closed top-level triggers (mirrored in RTL).\n- Typing letters jumps to the next top-level trigger whose label starts with the typed text; the same type-ahead works inside each open menu.\n- Once a menu is open, hovering or focusing a sibling trigger switches the open menu immediately.\n- ArrowLeft and ArrowRight inside an open root menu switch to the adjacent top-level menu.\n- ArrowRight on a submenu trigger remains owned by Menu and opens that submenu.\n- Escape and outside-click dismissal remain owned by Popover.\n- Selecting a leaf item closes the active menu by default.\n\n## Props\n\n- **menus**: MenuBarMenu[] (required) - Top-level menus. Each entry accepts a label, optional prefix/suffix, disabled state, and normal Menu props such as items, theme, header, footer, and submenuMode.\n- **size**: 'small' | 'normal' | 'large' (default: 'normal') - Size shared by every top-level trigger.\n- **dir**: 'ltr' | 'rtl' (optional) - Explicit text direction for horizontal keyboard navigation. When omitted it is auto-detected from the i18n direction context, else from the menubar's computed CSS direction.\n- **closeOnItemClick**: boolean (default: true) - Closes the active popup after a leaf item is selected.\n- **class**: string - Additional classes for the root menubar.\n- **theme**: MenuBarThemeProps - Theme overrides for the root and trigger parts.\n\n## Menu Entry\n\n```typescript\ntype MenuBarMenu = Omit<MenuProps, 'focusOnMount'> & {\n\tlabel: string | Snippet;\n\tprefix?: string | Snippet;\n\tsuffix?: string | Snippet;\n\tdisabled?: boolean;\n};\n```\n\n## Structure\n\n```\n<div role=\"menubar\">\n\t<Button role=\"menuitem\" haspopup=\"menu\" />\n\t<PopupMenu>\n\t\t<Menu />\n\t</PopupMenu>\n</div>\n```\n\n## Accessibility\n\nMenuBar uses the ARIA menubar/menu pattern. Its triggers use roving tabindex, expose expanded state and popup relationships, skip disabled entries, loop at either edge, and preserve nested submenu keyboard behavior.\n";
105
105
  readonly 'menu-option': "\n# MenuOption Component\n\nThe MenuOption component is a flexible menu item that can be used in dropdown menus, navigation menus, or context menus. It supports title/description layout, custom content, icons, colors, and various interaction handlers.\n\n## Basic Usage\n\n```svelte\n<MenuOption>\n\t{#snippet title()}\n\t\tMy Menu Item\n\t{/snippet}\n</MenuOption>\n```\n\n## Props\n\n### Core Props\n- **size**: 'small' | 'normal' | 'large' (default: 'normal') - Scales typography and icons only\n- **density**: 'compact' | 'normal' | 'comfortable' (default: 'normal') - Owns paddings, gaps and min-height; reflected as `data-density` on the row. Combine freely with size.\n- **color**: Colors (default: 'primary') - Sets the semantic text color and persistent active tint\n - Available: primary, secondary, success, warning, danger, info, neutral\n\n### Content Slots\nEither use **title/description** OR **children** (mutually exclusive):\n- **title**: Snippet - Main text of the menu item\n- **description**: Snippet - Secondary descriptive text below the title\n- **children**: Snippet - Custom content (replaces title+description)\n\n### Icon/Badge Slots\n- **prefix**: Snippet - Icon or badge at the start of the menu item\n- **suffix**: Snippet - Icon or badge at the end of the menu item\n\n### Interaction 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### Link Props\n- **href**: string - If provided, renders as an anchor element\n- **target**: string - Link target attribute (e.g., '_blank')\n- **rel**: string - Link rel attribute (e.g., 'noopener noreferrer')\n\n### Listbox / option props\nMenuOption is also the shared row primitive for the listbox family (Command, Select, Combobox).\n- **role**: string - ARIA role override. Defaults to button/link/menuitem; pass `option` inside a `listbox`. Menu passes `menuitemradio` for option items that set `selected`.\n- **highlighted**: boolean - Keyboard-active state (virtual focus). Applies the highlight background and reflects to `data-highlighted`. Menus omit this and rely on `useNavigation` setting `data-highlighted` imperatively.\n- **selected**: boolean - Sets `data-selected` plus the role-appropriate state: `aria-checked` for checkable roles (`menuitemradio`, `menuitemcheckbox`, `checkbox`, `radio`, `switch`) and `aria-selected` for listbox `option` rows (pass a check icon via `suffix`).\n- **disabled**: boolean - Dims the row, sets `aria-disabled`, blocks pointer/click.\n- **attrs**: Record<string, any> - Extra attributes/handlers spread onto the row (`id`, `data-value`, `tabindex`, `onpointermove`, `onmousedown`).\n\n### Styling Props\n- **class**: string - Additional CSS classes\n- **theme**: MenuOptionThemeProps - Custom theme overrides\n- **as**: string - Override the automatic element type detection\n\n## Menu Structure\n\n```\n<MenuOption>\n\t<Prefix /> <!-- Icon/badge at start -->\n\t<Content> <!-- Main content area -->\n\t\t<Title /> <!-- Primary text -->\n\t\t<Description /> <!-- Secondary text -->\n\t</Content>\n\t<Suffix /> <!-- Icon/badge at end -->\n</MenuOption>\n```\n\n## Examples\n\n### Basic Menu Item with Title\n```svelte\n<MenuOption>\n\t{#snippet title()}\n\t\tSettings\n\t{/snippet}\n</MenuOption>\n```\n\n### Menu Item with Title and Description\n```svelte\n<MenuOption>\n\t{#snippet title()}\n\t\tAccount Settings\n\t{/snippet}\n\t{#snippet description()}\n\t\tManage your account preferences and security\n\t{/snippet}\n</MenuOption>\n```\n\n### Menu Item with Prefix Icon\n```svelte\n<script lang=\"ts\">\n\timport { MenuOption } from 'entasis/menu-option';\n\timport { gearIcon } from 'entasis/icons/gear';\n</script>\n\n<MenuOption>\n\t{#snippet prefix()}\n\t\t{@render gearIcon()}\n\t{/snippet}\n\t{#snippet title()}\n\t\tSettings\n\t{/snippet}\n</MenuOption>\n```\n\n### Menu Item with Suffix Icon\n```svelte\n<script lang=\"ts\">\n\timport { MenuOption } from 'entasis/menu-option';\n\timport { caretRightIcon } from 'entasis/icons/caretRight';\n</script>\n\n<MenuOption>\n\t{#snippet title()}\n\t\tMore Options\n\t{/snippet}\n\t{#snippet suffix()}\n\t\t{@render caretRightIcon()}\n\t{/snippet}\n</MenuOption>\n```\n\n### Menu Item with Both Icons\n```svelte\n<script lang=\"ts\">\n\timport { MenuOption } from 'entasis/menu-option';\n\timport { userIcon } from 'entasis/icons/user';\n\timport { checkIcon } from 'entasis/icons/check';\n</script>\n\n<MenuOption>\n\t{#snippet prefix()}\n\t\t{@render userIcon()}\n\t{/snippet}\n\t{#snippet title()}\n\t\tJohn Doe\n\t{/snippet}\n\t{#snippet suffix()}\n\t\t{@render checkIcon({ class: 'text-success' })}\n\t{/snippet}\n</MenuOption>\n```\n\n### Different Sizes\n```svelte\n<MenuOption size=\"small\">\n\t{#snippet title()}Small Menu Item{/snippet}\n</MenuOption>\n\n<MenuOption size=\"normal\">\n\t{#snippet title()}Normal Menu Item{/snippet}\n</MenuOption>\n\n<MenuOption size=\"large\">\n\t{#snippet title()}Large Menu Item{/snippet}\n</MenuOption>\n```\n\n### Different Densities\n```svelte\n<!-- density scales paddings/gaps/min-height; size scales text/icons -->\n<MenuOption density=\"compact\">\n\t{#snippet title()}Small row{/snippet}\n</MenuOption>\n\n<MenuOption density=\"normal\">\n\t{#snippet title()}Normal row{/snippet}\n</MenuOption>\n\n<MenuOption density=\"comfortable\">\n\t{#snippet title()}Large row{/snippet}\n</MenuOption>\n```\n\n### Different Colors\n```svelte\n<MenuOption color=\"primary\">\n\t{#snippet title()}Primary{/snippet}\n</MenuOption>\n\n<MenuOption color=\"danger\">\n\t{#snippet title()}Delete{/snippet}\n</MenuOption>\n\n<MenuOption color=\"success\">\n\t{#snippet title()}Approve{/snippet}\n</MenuOption>\n```\n\n### Interactive Menu Item with Click Handler\n```svelte\n<script>\n\tlet count = $state(0);\n</script>\n\n<MenuOption onclick={() => count++}>\n\t{#snippet title()}\n\t\tClicked {count} times\n\t{/snippet}\n</MenuOption>\n```\n\n### Menu Item with Hover Handlers\n```svelte\n<script>\n\tlet isHovered = $state(false);\n</script>\n\n<MenuOption \n\tonpointerenter={() => isHovered = true}\n\tonpointerleave={() => isHovered = false}\n>\n\t{#snippet title()}\n\t\t{isHovered ? 'Hovering!' : 'Hover over me'}\n\t{/snippet}\n</MenuOption>\n```\n\n### Menu Item as Link\n```svelte\n<MenuOption href=\"/settings\">\n\t{#snippet title()}\n\t\tGo to Settings\n\t{/snippet}\n</MenuOption>\n```\n\n### External Link\n```svelte\n<script lang=\"ts\">\n\timport { MenuOption } from 'entasis/menu-option';\n\timport { arrowSquareOutIcon } from 'entasis/icons/arrowSquareOut';\n</script>\n\n<MenuOption \n\thref=\"https://example.com\" \n\ttarget=\"_blank\" \n\trel=\"noopener noreferrer\"\n>\n\t{#snippet title()}\n\t\tVisit External Site\n\t{/snippet}\n\t{#snippet suffix()}\n\t\t{@render arrowSquareOutIcon()}\n\t{/snippet}\n</MenuOption>\n```\n\n### Custom Content with Children\n```svelte\n<MenuOption>\n\t{#snippet children()}\n\t\t<div class=\"flex items-center gap-2\">\n\t\t\t<img src=\"/avatar.jpg\" alt=\"User\" class=\"w-8 h-8 rounded-full\" />\n\t\t\t<div>\n\t\t\t\t<div class=\"font-bold\">John Doe</div>\n\t\t\t\t<div class=\"text-xs text-neutral/70\">john@example.com</div>\n\t\t\t</div>\n\t\t</div>\n\t{/snippet}\n</MenuOption>\n```\n\n### Menu with Multiple Options\n```svelte\n<script lang=\"ts\">\n\timport { MenuOption } from 'entasis/menu-option';\n\timport { gearIcon } from 'entasis/icons/gear';\n\timport { userIcon } from 'entasis/icons/user';\n\timport { signOutIcon } from 'entasis/icons/signOut';\n\timport { questionIcon } from 'entasis/icons/question';\n</script>\n\n<div class=\"w-64 bg-surface rounded-xl border border-neutral-muted p-1\">\n\t<MenuOption>\n\t\t{#snippet prefix()}{@render userIcon()}{/snippet}\n\t\t{#snippet title()}Profile{/snippet}\n\t\t{#snippet description()}View and edit your profile{/snippet}\n\t</MenuOption>\n\t\n\t<MenuOption>\n\t\t{#snippet prefix()}{@render gearIcon()}{/snippet}\n\t\t{#snippet title()}Settings{/snippet}\n\t\t{#snippet description()}Manage your preferences{/snippet}\n\t</MenuOption>\n\t\n\t<MenuOption>\n\t\t{#snippet prefix()}{@render questionIcon()}{/snippet}\n\t\t{#snippet title()}Help & Support{/snippet}\n\t</MenuOption>\n\t\n\t<div class=\"border-t border-neutral-muted my-1\"></div>\n\t\n\t<MenuOption color=\"danger\">\n\t\t{#snippet prefix()}{@render signOutIcon()}{/snippet}\n\t\t{#snippet title()}Log Out{/snippet}\n\t</MenuOption>\n</div>\n```\n\n### With Custom Theme\n```svelte\n<MenuOption \n\ttheme={{\n\t\troot: { base: 'rounded-full' },\n\t\ttitle: { base: 'font-bold' }\n\t}}\n>\n\t{#snippet title()}\n\t\tCustom Styled Menu Item\n\t{/snippet}\n</MenuOption>\n```\n\n### With Attachments\n```svelte\n<script lang=\"ts\">\n\timport { MenuOption } from 'entasis/menu-option';\n\timport { spinnerOverlay } from 'entasis/spinner-overlay';\n\t\n\tlet loading = $state(false);\n\t\n\tasync function handleClick() {\n\t\tloading = true;\n\t\tawait fetch('/api/action');\n\t\tloading = false;\n\t}\n</script>\n\n<MenuOption \n\tonclick={handleClick}\n\t{@attach spinnerOverlay({ loading })}\n>\n\t{#snippet title()}\n\t\tPerform Action\n\t{/snippet}\n</MenuOption>\n```\n\n### Override Element Type\n```svelte\n<!-- Force render as div even with onclick -->\n<MenuOption as=\"div\" onclick={() => console.log('clicked')}>\n\t{#snippet title()}\n\t\tCustom Element Type\n\t{/snippet}\n</MenuOption>\n```\n\n## Accessibility\n\n- Automatically sets appropriate `role` attribute based on element type\n - `button` for interactive elements\n - `link` for anchor elements\n - `menuitem` for non-interactive elements\n- Supports keyboard navigation when used as button or link\n- Proper semantic HTML structure\n- Color foreground meets accessibility standards\n\n## Element Type Detection\n\nThe component automatically determines the HTML element to render:\n1. If `as` prop is provided → uses that element\n2. If `href` is provided → renders as `<a>`\n3. Otherwise → renders as `<button>`\n4. Otherwise → renders as `<div>`\n\n## Notes\n\n- Title and description snippets are mutually exclusive with children snippet\n- Hover states automatically apply background color based on the color prop\n- Prefix icons are positioned at the start, suffix icons at the end (with ml-auto)\n- Hover and virtual focus use the shared current-color state layer\n- Works well within Popover or Dialog components for dropdown menus\n\n## Theme Customization\n\nThe MenuOption 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 menu option container styles\n- **title**: Menu option title text styles\n- **description**: Menu option description text styles\n- **prefix**: Prefix icon/content styles\n- **suffix**: Suffix icon/content styles\n- **content**: Content wrapper styles\n\n### Available Variants\n\n**root**:\n- base: Base classes applied to all menu options\n- Variants:\n - size: 'small' | 'normal' | 'large' - Text size\n - density: 'compact' | 'normal' | 'comfortable' - Padding, gap, and min-height\n - color: 'primary' | 'secondary' | 'neutral' | 'danger' | 'success' | 'warning' | 'info' - Color scheme and hover states\n\n**title**:\n- base: Base classes for title 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**prefix**:\n- base: Base classes for prefix content\n- Variants:\n - size: 'small' | 'normal' | 'large' - Icon size\n - align: 'start' | 'center' - Vertical alignment\n\n**suffix**:\n- base: Base classes for suffix content\n- Variants:\n - size: 'small' | 'normal' | 'large' - Icon size\n\n**content**:\n- base: Base classes for content wrapper\n- Variants:\n - density: 'compact' | 'normal' | 'comfortable' - Gap spacing between title and description\n\n### Usage Examples\n\n**Basic Theme Override**:\n```svelte\n<MenuOption\n theme={{\n root: {\n base: 'rounded-lg',\n density: {\n comfortable: 'px-4 py-3 min-h-12'\n }\n },\n title: {\n size: {\n large: 'text-lg font-semibold'\n }\n }\n }}\n>\n {#snippet title()}\n Custom Menu Option\n {/snippet}\n</MenuOption>\n```\n\n**Color Customization**:\n```svelte\n<MenuOption \n color=\"danger\"\n theme={{\n root: {\n color: {\n danger: 'text-red-600 highlight:bg-red-50 highlight:text-red-700'\n }\n }\n }}\n>\n {#snippet title()}\n Delete Item\n {/snippet}\n</MenuOption>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setMenuOptionTheme } from '../components/MenuOption/index.ts';\n \n setMenuOptionTheme({\n root: {\n base: 'rounded-md transition-colors',\n density: {\n normal: 'px-3 py-2'\n }\n },\n prefix: {\n size: {\n normal: 'w-5 h-5'\n }\n }\n });\n</script>\n```\n";
106
106
  readonly 'popup-menu': "\n# PopupMenu Component\n\nThe PopupMenu component is a wrapper around Popover that renders a Menu inside. It provides all Popover functionality (positioning, transitions, triggers) with integrated Menu rendering for quick menu implementations.\n\n## Basic Usage\n\n```svelte\n<script lang=\"ts\">\n\timport type { MenuItem } from 'entasis/menu';\n\timport { PopupMenu } from 'entasis/popup-menu';\n\timport { userIcon } from 'entasis/icons/user';\n\timport { gearIcon } from 'entasis/icons/gear';\n\timport { signOutIcon } from 'entasis/icons/signOut';\n\t\n\tconst menuItems = [\n\t\t{ type: 'option', prefix: userIcon, title: 'Profile' },\n\t\t{ type: 'option', prefix: gearIcon, title: 'Settings' },\n\t\t{ type: 'separator' },\n\t\t{ type: 'option', prefix: signOutIcon, title: 'Logout', color: 'danger' }\n\t] satisfies MenuItem[];\n</script>\n\n<PopupMenu\n\ttrigger={{ content: 'Open Menu' }}\n\tposition=\"bottom-start\"\n\tmenu={{ items: menuItems }}\n/>\n```\n\n## Props\n\n### Menu Props\n- **menu**: MenuProps (required)\n - items: MenuItem[] - Array of menu items (buttons, options, separators)\n - class: string - Custom class for the menu container\n - theme: MenuThemeProps - Theme overrides for menu and its items\n - submenuMode: 'auto' | 'popover' | 'stack' - defaults to auto; mobileSheet menus stack submenus automatically\n\n- **closeOnItemClick**: boolean (default: true)\n - Whether to close the menu when a menu item (button or link) is clicked\n - Set to false for menus that should stay open for multiple selections\n\n### Popover Props (All Available)\n\n#### Positioning & Layout\n- **position**: ResponsiveProps<Placement> - Popover position relative to trigger\n - Values: 'top', 'bottom', 'left', 'right', 'top-start', 'bottom-start', etc.\n \n- **offset**: number - Distance from trigger in pixels\n\n- **size**: ResponsiveProps<'small' | 'normal' | 'large'> - Popover size\n\n- **fitTrigger**: boolean - Make popover width match trigger width\n\n#### Trigger Configuration\n- **trigger**: Snippet | ButtonProps | false\n - Snippet: Custom trigger rendering with popover state\n - ButtonProps: Render a button with these props\n - false: No trigger (control externally via open)\n\n#### Interaction Behavior\n- **open**: boolean (bindable) - Control open state externally\n\n- **openOnClick**: boolean (default: true) - Open on trigger click\n\n- **openOnHover**: boolean (default: false) - Open on trigger hover\n\n- **delay**: number (default: 100) - Delay before opening on hover (ms)\n\n- **closeOnClickOutside**: boolean (default: true) - Close when clicking outside\n\n- **closeOnEscape**: boolean (default: true) - Close on Escape key\n\n- **closeOnMouseLeave**: boolean (default: false) - Close when the pointer leaves the hover safe area. The safe area is the trigger, the panel, and a prediction cone toward the submenu, so a diagonal move into the submenu keeps it open while sibling rows stay hoverable.\n\n- **debugSafeArea**: boolean (default: false) - Show hover safe-area overlays. Trigger/panel rectangles render in blue; the prediction cone toward the submenu renders in orange.\n\n#### Visual & Animation\n- **transition**: ResponsiveProps<FSOProps> - Custom transition configuration\n\n- **directedTransition**: boolean (default: true) - Transition direction based on position\n\n- **lockScroll**: boolean (default: true) - Lock body scroll when open\n\n- **class**: string - Custom class for popover dialog\n\n- **mobileSheet**: boolean (default: false) - Render as a bottom sheet on mobile viewports. With menu.submenuMode='auto', nested submenus become stacked views.\n\n#### Advanced\n- **id**: string - Custom ID for popover element\n\n- **ref**: HTMLElement | null - External reference element (instead of trigger)\n\n- **onOpenChange**: (open: boolean) => void - Called for component-owned state changes\n\n- **onAfterOpen**: (popover: PopoverState) => void - Called after the popover opens\n\n- **onAfterClose**: (popover: PopoverState) => void - Called after the popover closes\n\n- **theme**: PopoverThemeProps - Theme overrides for popover\n\n## Structure\n\nPopupMenu renders as:\n```\n<Popover {...popoverProps}>\n <Menu {...menuProps} />\n</Popover>\n```\n\nThe Menu inherits the Popover's dialog styling (background, border, shadow, etc.)\n\n## Examples\n\n### Basic Dropdown Menu\n```svelte\n<script lang=\"ts\">\n\timport type { MenuItem } from 'entasis/menu';\n\tconst items = [\n\t\t{ type: 'option', title: 'New File' },\n\t\t{ type: 'option', title: 'Open...' },\n\t\t{ type: 'option', title: 'Save' },\n\t\t{ type: 'separator' },\n\t\t{ type: 'option', title: 'Exit' }\n\t] satisfies MenuItem[];\n</script>\n\n<PopupMenu\n\ttrigger={{ content: 'File', variant: 'ghost' }}\n\tposition=\"bottom-start\"\n\tmenu={{ items }}\n/>\n```\n\n### User Profile Menu\n```svelte\n<script lang=\"ts\">\n\timport type { MenuItem } from 'entasis/menu';\n\timport { userIcon } from 'entasis/icons/user';\n\timport { gearIcon } from 'entasis/icons/gear';\n\timport { questionIcon } from 'entasis/icons/question';\n\timport { signOutIcon } from 'entasis/icons/signOut';\n\t\n\tconst items = [\n\t\t{ type: 'option', prefix: userIcon, title: 'Profile', href: '/profile' },\n\t\t{ type: 'option', prefix: gearIcon, title: 'Settings', href: '/settings' },\n\t\t{ type: 'option', prefix: questionIcon, title: 'Help' },\n\t\t{ type: 'separator' },\n\t\t{ type: 'option', prefix: signOutIcon, title: 'Log Out', color: 'danger' }\n\t] satisfies MenuItem[];\n</script>\n\n<PopupMenu\n\ttrigger={{ content: 'John Doe', variant: 'outline' }}\n\tposition=\"bottom-end\"\n\tmenu={{ items }}\n/>\n```\n\n### Context Menu (Right Click)\n```svelte\n<script lang=\"ts\">\n\timport type { MenuItem } from 'entasis/menu';\n\timport { trashIcon } from 'entasis/icons/trash';\n\timport { copyIcon } from 'entasis/icons/copy';\n\timport { shareIcon } from 'entasis/icons/share';\n\t\n\tlet open = $state(false);\n\tlet contextMenuRef = $state<HTMLElement | null>(null);\n\t\n\tfunction handleContextMenu(e: MouseEvent) {\n\t\te.preventDefault();\n\t\tcontextMenuRef = e.currentTarget as HTMLElement;\n\t\topen = true;\n\t}\n\t\n\tconst items = [\n\t\t{ type: 'option', title: 'Open' },\n\t\t{ type: 'option', prefix: copyIcon, title: 'Copy' },\n\t\t{ type: 'option', prefix: shareIcon, title: 'Share' },\n\t\t{ type: 'separator' },\n\t\t{ type: 'option', prefix: trashIcon, title: 'Delete', color: 'danger' }\n\t] satisfies MenuItem[];\n</script>\n\n<div oncontextmenu={handleContextMenu}>\n\tRight-click me\n</div>\n\n<PopupMenu\n\ttrigger={false}\n\tbind:open\n\tref={contextMenuRef}\n\tposition=\"bottom-start\"\n\tmenu={{ items }}\n/>\n```\n\n### With Custom Trigger Snippet\n```svelte\n<script lang=\"ts\">\n\timport type { MenuItem } from 'entasis/menu';\n\tlet open = $state(false);\n\n\tconst items = [\n\t\t{ type: 'option', title: 'Option 1' },\n\t\t{ type: 'option', title: 'Option 2' }\n\t] satisfies MenuItem[];\n</script>\n\n<PopupMenu bind:open position=\"bottom\" menu={{ items }}>\n\t{#snippet trigger(popover)}\n\t\t<button onclick={() => popover.toggle()}>\n\t\t\tCustom Trigger {open ? '▲' : '▼'}\n\t\t</button>\n\t{/snippet}\n</PopupMenu>\n```\n\n### Hover Menu\n```svelte\n<script lang=\"ts\">\n\timport type { MenuItem } from 'entasis/menu';\n\tconst items = [\n\t\t{ type: 'option', title: 'Quick Action 1' },\n\t\t{ type: 'option', title: 'Quick Action 2' }\n\t] satisfies MenuItem[];\n</script>\n\n<PopupMenu\n\ttrigger={{ content: 'Hover Me', variant: 'ghost' }}\n\topenOnHover={true}\n\topenOnClick={false}\n\tdelay={200}\n\tcloseOnMouseLeave={true}\n\tmenu={{ items }}\n/>\n```\n\n### Actions Menu with Buttons\n```svelte\n<script lang=\"ts\">\n\timport type { MenuItem } from 'entasis/menu';\n\tconst items = [\n\t\t{ type: 'button', children: 'Save Draft', variant: 'ghost', fullWidth: true },\n\t\t{ type: 'button', children: 'Publish', variant: 'solid', color: 'primary', fullWidth: true },\n\t\t{ type: 'separator' },\n\t\t{ type: 'button', children: 'Delete', variant: 'soft', color: 'danger', fullWidth: true }\n\t] satisfies MenuItem[];\n</script>\n\n<PopupMenu\n\ttrigger={{ content: 'Actions' }}\n\tposition=\"bottom-end\"\n\tmenu={{ items }}\n/>\n```\n\n### External Control with Bindable State\n```svelte\n<script lang=\"ts\">\n\timport type { MenuItem } from 'entasis/menu';\n\tlet menuOpen = $state(false);\n\t\n\tconst items = [\n\t\t{ type: 'option', title: 'Item 1' },\n\t\t{ type: 'option', title: 'Item 2' }\n\t] satisfies MenuItem[];\n\t\n\tfunction openMenu() {\n\t\tmenuOpen = true;\n\t}\n</script>\n\n<button onclick={openMenu}>Open Menu Externally</button>\n\n<PopupMenu\n\ttrigger={{ content: 'Menu' }}\n\tbind:open={menuOpen}\n\tmenu={{ items }}\n/>\n```\n\n### Positioned Menu\n```svelte\n<script lang=\"ts\">\n\timport type { MenuItem } from 'entasis/menu';\n\tconst items = [\n\t\t{ type: 'option', title: 'Top Start' },\n\t\t{ type: 'option', title: 'Example' }\n\t] satisfies MenuItem[];\n</script>\n\n<div class=\"flex gap-2\">\n\t<PopupMenu trigger={{ content: 'Top Start' }} position=\"top-start\" menu={{ items }} />\n\t<PopupMenu trigger={{ content: 'Bottom' }} position=\"bottom\" menu={{ items }} />\n\t<PopupMenu trigger={{ content: 'Right' }} position=\"right\" menu={{ items }} />\n</div>\n```\n\n### With Custom Theme\n```svelte\n<script lang=\"ts\">\n\timport type { MenuItem } from 'entasis/menu';\n\tconst items = [\n\t\t{ type: 'option', title: 'Themed Option 1' },\n\t\t{ type: 'option', title: 'Themed Option 2' }\n\t] satisfies MenuItem[];\n\t\n\tconst menuTheme = {\n\t\troot: { base: 'gap-3' },\n\t\toption: {\n\t\t\troot: { base: 'px-4 py-3' }\n\t\t}\n\t};\n</script>\n\n<PopupMenu\n\ttrigger={{ content: 'Themed Menu' }}\n\tmenu={{ items, theme: menuTheme }}\n/>\n```\n\n### Keep Menu Open for Multiple Interactions\n```svelte\n<script lang=\"ts\">\n\timport type { MenuItem } from 'entasis/menu';\n\tlet selections = $state<string[]>([]);\n\t\n\tconst items = [\n\t\t{ \n\t\t\ttype: 'option', \n\t\t\ttitle: 'Option 1',\n\t\t\tonclick: () => selections.push('Option 1')\n\t\t},\n\t\t{ \n\t\t\ttype: 'option', \n\t\t\ttitle: 'Option 2',\n\t\t\tonclick: () => selections.push('Option 2')\n\t\t},\n\t\t{ type: 'separator' },\n\t\t{ \n\t\t\ttype: 'button', \n\t\t\tchildren: 'Done',\n\t\t\tvariant: 'solid',\n\t\t\tfullWidth: true\n\t\t}\n\t] satisfies MenuItem[];\n</script>\n\n<PopupMenu\n\ttrigger={{ content: 'Select Multiple' }}\n\tcloseOnItemClick={false}\n\tmenu={{ items }}\n/>\n```\n\n### Nested Submenus\n```svelte\n<script lang=\"ts\">\n\timport type { MenuItem } from 'entasis/menu';\n\n\tconst items = [\n\t\t{ type: 'option', title: 'New File' },\n\t\t{\n\t\t\ttype: 'submenu',\n\t\t\ttitle: 'More Options',\n\t\t\tmenu: [\n\t\t\t\t{ type: 'option', title: 'Sub Option 1' },\n\t\t\t\t{ type: 'option', title: 'Sub Option 2' }\n\t\t\t]\n\t\t}\n\t] satisfies MenuItem[];\n</script>\n\n<PopupMenu trigger={{ content: 'Main Menu' }} position=\"bottom-start\" menu={{ items }} />\n```\n\n## Accessibility\n\n- Inherits all Popover accessibility features: the trigger carries `aria-haspopup=\"menu\"`, `aria-expanded`, and `aria-controls`, and focus returns to it on close\n- Menu items have appropriate roles (`menuitem`, or `menuitemradio` with `aria-checked` for options that set `selected`) and keyboard navigation\n- Type-ahead: typing letters moves the highlight to the next matching item\n- Escape closes only the topmost open layer, so a submenu closes before its parent (configurable)\n- An outside press closes every layer above the one pressed (configurable)\n\n## Notes\n\n- PopupMenu is a lightweight wrapper - all Popover props work as expected\n- Menu styling inherits from Popover's dialog theme\n- Use `closeOnClickOutside={true}` (default) for typical dropdown menus\n- Use `closeOnMouseLeave={true}` for hover-triggered quick menus; a prediction cone toward the submenu keeps it open during the diagonal move while sibling rows stay hoverable.\n- The `menu` prop accepts full MenuProps including theme forwarding to child components\n";
107
- readonly dialog: "\n# Dialog Component\n\nThe Dialog component (also known as Modal) displays content in a layer above the page, blocking interaction with the rest of the application until dismissed.\n\n## Basic Usage\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\timport { Button } from 'entasis/button';\n\t\t\n</script>\n// By default Dialog comes with a button that trigger them, no need to define a callback and a $state\n<Dialog title=\"Dialog Title\">\n\tDialog content goes here\n</Dialog>\n```\n\n## Props\n\n### Core Props\n- **open**: boolean (bindable) - Controls dialog visibility\n- **defaultOpen**: boolean (default: false) - Initial state when open is not provided\n- **id**: string - Unique identifier for the dialog\n- **type**: 'fullScreen' | 'drawerRight' | 'drawerLeft' | 'drawerBottom' | 'drawerTop' | 'alert' | 'modal' (default: 'modal')\n - fullScreen: Full screen dialog overlay\n - drawerRight: Drawer sliding in from the right\n - drawerLeft: Drawer sliding in from the left\n - drawerBottom: Drawer sliding in from the bottom\n - drawerTop: Drawer sliding in from the top\n - alert: Alert-style dialog\n - modal: Standard modal dialog\n - Supports responsive values: pass a `Partial<Record<Breakpoint, DialogType>>` record such as `{ xs: 'drawerBottom', md: 'modal' }` to vary the type per breakpoint (breakpoint is one of 'xs' | 'sm' | 'md' | 'lg' | 'xl', tracked live from the viewport; the nearest defined key at or below the active one wins)\n- **responsive**: boolean (default: true) - When the resolved type is `modal`, collapse it into a `drawerBottom` bottom sheet on mobile (viewport < 768px). The sheet inherits swipe-to-dismiss and the drag thumb. Set false to keep a centered modal on every screen size\n\n### Layout Props\n- **size**: 'small' | 'normal' | 'large' (default: 'normal')\n - small: Compact dialog size\n - normal: Standard dialog size\n - large: Larger dialog size\n\n### Event Props\n- **onOpenChange**: (open: boolean) => void - Called once for each library-requested state change\n- **onAfterOpen**: (payload: DialogState) => void - Called after the open transition finishes\n- **onAfterClose**: (payload: DialogState) => void - Called after the close transition finishes\n\n### Slot Props\n- **title**: string | Snippet<[DialogState]> - Dialog title\n- **description**: string | Snippet<[DialogState]> - Dialog description\n- **children**: Snippet<[DialogState]> - Main dialog content\n- **header**: Snippet - Custom header content\n- **footer**: Snippet - Custom footer content\n- **trigger**: Snippet | (ButtonProps & { content?: string }) - Custom trigger button\n- **closeButton**: Snippet - Custom close button\n\n### Behavior Props\n- **closeOnEscape**: boolean (default: true) - Close when Escape key is pressed\n- **closeOnClickOutside**: boolean (default: true) - Close when clicking outside dialog\n- **closable**: boolean (default: true) - Whether dialog can be closed\n- **swipeToDismiss**: boolean (default: true for drawer types) - Drag the drawer toward its edge to dismiss. Direction-aware (drawerRight drags right, drawerBottom drags down, etc.) and never hijacks inner scrolling; opt elements out with `data-no-swipe`\n- **thumb**: boolean (default: true) - Drag thumb bar shown on swipe-dismissable drawers (inner edge, orientation follows the drawer side, oversized hitbox); set false to hide. Themeable via the `thumb` theme part\n- **swipeFrom**: 'panel' | 'handle' (default: 'panel') - Where a swipe can start: anywhere on the panel, or only the drag handles (thumb and header)\n\n### Visual Props\n- **transition**: TransitionConfig - Custom transition animation\n\n### Styling Props\n- **class**: string - Additional CSS classes\n- **theme**: ComponentTheme - Custom theme overrides\n\n## Structure\n\n```\n<DialogOverlay>\n\t<DialogContent>\n\t\t<DialogHeader>\n\t\t\t<Title />\n\t\t\t<Description />\n\t\t\t<CloseButton />\n\t\t</DialogHeader>\n\t\t<DialogBody>\n\t\t\t<Children />\n\t\t</DialogBody>\n\t\t<DialogFooter />\n\t</DialogContent>\n</DialogOverlay>\n```\n\n## Examples\n\n### More Examples\n\n### A with a custom trigger \n```svelte\n\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\timport { Button } from 'entasis/button';\n\t\n\tlet open = $state(false);\n</script>\n\n\n<Dialog bind:open title=\"Welcome\">\n\t<p>This is a basic dialog.</p>\n\t\n\t{#snippet trigger(dialog)}\n\t\t<Button onclick={() => dialog.open()}>Open</Button>\n\t{/snippet}\n</Dialog>\n```\n\n### A with a custom as button props \n```svelte\n\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\timport { Button } from 'entasis/button';\n\t\n\tlet open = $state(false);\n</script>\n\n\n<Dialog bind:open title=\"Welcome\"\ntrigger={{\ncontent:\"Click me\",\ncolor:\"secondary\",\nsize:\"small\"\n}}\n>\n\t<p>This is a basic dialog.</p>\t\n</Dialog>\n```\n\n### With Description\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\t\n</script>\n\n<Dialog \t\n\ttitle=\"Confirm Action\"\n\tdescription=\"Are you sure you want to continue?\"\n>\n\t<p>This action cannot be undone.</p>\n</Dialog>\n```\n\n### Different Sizes\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\t\n\tlet open = $state(false);\n</script>\n\n```\n\n### Advanced Example\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\timport { Button } from 'entasis/button';\n\t\n\tlet open = $state(false);\n\t\n\tfunction handleConfirm() {\n\t\tconsole.log('Confirmed!');\n\t\topen = false;\n\t}\n</script>\n\n<Dialog bind:open title=\"Confirm\">\n\tAre you sure?\n\t\n\t{#snippet footer()}\n\t\t<div class=\"flex gap-2 justify-end\">\n\t\t\t<Button variant=\"ghost\" onclick={() => open = false}>\n\t\t\t\tCancel\n\t\t\t</Button>\n\t\t\t<Button color=\"danger\" onclick={handleConfirm}>\n\t\t\t\tConfirm\n\t\t\t</Button>\n\t\t</div>\n\t{/snippet}\n</Dialog>\n```\n\n### Drawer Types\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\t\n\t\n</script>\n\n<!-- Right drawer -->\n<Dialog type=\"drawerRight\" title=\"Side Drawer\">\n\tThis slides in from the right\n</Dialog>\n\n<!-- Left drawer -->\n<Dialog type=\"drawerLeft\" title=\"Left Drawer\">\n\tThis slides in from the left\n</Dialog>\n\n<!-- Bottom drawer -->\n<Dialog type=\"drawerBottom\" title=\"Bottom Drawer\">\n\tThis slides in from the bottom\n</Dialog>\n\n<!-- Full screen -->\n<Dialog type=\"fullScreen\" title=\"Full Screen\">\n\tFull screen dialog content\n</Dialog>\n```\n\n### Custom Header\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\timport { warningIcon } from 'entasis/icons/warning';\n</script>\n\n<Dialog bind:open>\n\t{#snippet header()}\n\t\t<div class=\"flex items-center gap-2\">\n\t\t\t{@render warningIcon()}\n\t\t\t<h2>Warning</h2>\n\t\t</div>\n\t{/snippet}\n\t\n\tThis is important!\n</Dialog>\n```\n\n\n### With Lifecycle Hooks\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\t\n\tlet open = $state(false);\n</script>\n\n<Dialog \n\tbind:open\n\ttitle=\"Lifecycle\"\n\tonAfterOpen={(payload) => console.log('Dialog opened', payload)}\n\tonAfterClose={(payload) => console.log('Dialog closed', payload)}\n>\n\tWatch the console\n</Dialog>\n```\n\n## State Management\n\nThe Dialog component uses a `DialogState` instance that is passed to all slot snippets. This state object provides:\n\n- **id**: string - Dialog identifier\n- **type**: DialogType - Current dialog type\n- **size**: Size - Current dialog size\n- **open()**: () => void - Method to open the dialog\n- **close()**: () => void - Method to close the dialog\n\n## Accessibility\n\n- Initial focus goes to an `[autofocus]` / `[data-autofocus]` element inside the dialog, else the first tabbable control (the close button is skipped), else the panel itself\n- Tab and Shift+Tab are contained inside the dialog, and the rest of the page is `inert` while a modal is open\n- Focus is restored to the opener after the close transition finishes, just before `onAfterClose`\n- `aria-labelledby` links the `title` and `aria-describedby` links the `description`\n- Escape closes only the topmost open layer and an outside press dismisses the layers above the one pressed; both honour `closeOnEscape` / `closable` / `closeOnClickOutside` through the shared layer stack\n- Body scroll is locked when dialog is open\n\n## Notes\n\n- Multiple dialogs can be stacked\n- Last opened dialog receives focus\n- Background overlay prevents interaction with page\n- Scroll locking prevents background scroll\n- Transitions are customizable\n\n## Theme Customization\n\nThe Dialog 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- **motion**: Open/close transition preset, keyed by `type` (drawers fly from their edge). Takes\n `in` / `out` FSO params plus a `duration` / `easing` motion token; the `transition` prop wins\n over it\n- **root**: Dialog overlay/backdrop styles\n- **content**: Dialog content container styles\n- **thumb**: Drag thumb bar styles (type variant controls per-side placement)\n- **header**: Dialog header section styles\n- **footer**: Dialog footer section styles\n- **closeButton**: Close button styles\n- **title**: Dialog title text styles\n- **description**: Dialog description text styles\n\n### Theme Type Definition\n\n```typescript\nimport type { DialogThemeProps } from 'entasis/dialog';\n\n// Example theme customization\nconst customTheme: DialogThemeProps = {\n root: {\n base: 'z-[+50] fixed inset-0 flex',\n scroll: {\n inner: 'overflow-hidden',\n outer: 'overflow-auto'\n }\n },\n align: {\n type: {\n fullScreen: 'justify-center items-center',\n drawerRight: 'justify-end',\n drawerLeft: 'justify-start',\n drawerBottom: 'justify-center items-end',\n drawerTop: 'justify-center items-start',\n modal: 'justify-center',\n alert: 'justify-center'\n }\n },\n content: {\n size: {\n small: 'max-w-md w-full',\n normal: 'max-w-xl w-full',\n large: 'max-w-3xl w-full'\n },\n type: {\n fullScreen: 'h-full w-full max-w-full',\n drawerRight: 'rounded-l-none h-full',\n modal: ''\n }\n },\n header: {\n size: {\n small: '',\n normal: '',\n large: ''\n }\n },\n title: {\n size: {\n small: '',\n normal: '',\n large: ''\n }\n },\n description: {\n size: {\n small: '',\n normal: '',\n large: ''\n }\n }\n};\n```\n\n### Available Variants\n\n**root**:\n- base: Base classes for dialog overlay/backdrop\n- Variants:\n - size: 'small' | 'normal' | 'large' - Size constraints\n - type: 'fullScreen' | 'drawerRight' | 'drawerLeft' | 'drawerBottom' | 'drawerTop' | 'modal' | 'alert' - Dialog type/layout\n\n**content**:\n- base: Base classes for dialog content container\n- Variants:\n - size: 'small' | 'normal' | 'large' - Content max-width\n - type: 'fullScreen' | 'drawerRight' | 'drawerLeft' | 'drawerBottom' | 'drawerTop' | 'modal' | 'alert' - Content styling based on type\n\n**header**:\n- base: Base classes for header section\n- Variants:\n - size: 'small' | 'normal' | 'large' - Size-based styling\n\n**footer**:\n- base: Base classes for footer section\n- Variants:\n - size: 'small' | 'normal' | 'large' - Size-based styling\n\n**closeButton**:\n- base: Base classes for close button\n- Variants:\n - size: 'small' | 'normal' | 'large' - Size-based styling\n\n**title**:\n- base: Base classes for title 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### Usage Examples\n\n**Basic Theme Override**:\n```svelte\n<Dialog \n title=\"Custom Dialog\"\n theme={{\n content: {\n base: 'rounded-2xl raised-5',\n size: {\n normal: 'max-w-2xl'\n }\n },\n header: {\n base: 'border-b-2 border-primary'\n }\n }}\n>\n Custom styled dialog content\n</Dialog>\n```\n\n**Drawer Type Customization**:\n```svelte\n<Dialog \n type=\"drawerRight\"\n theme={{\n align: {\n type: {\n drawerRight: 'justify-end'\n }\n },\n backdrop: {\n base: 'bg-black/50'\n },\n content: {\n type: {\n drawerRight: 'rounded-l-xl raised-5'\n }\n }\n }}\n>\n Custom drawer styling\n</Dialog>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setDialogTheme } from '../components/Dialog/index.ts';\n \n setDialogTheme({\n root: {\n base: 'backdrop-blur-sm'\n },\n content: {\n base: 'lift-5 border-2',\n size: {\n normal: 'max-w-2xl'\n }\n },\n title: {\n base: 'text-2xl font-bold'\n }\n });\n</script>\n```\n";
107
+ readonly dialog: "\n# Dialog Component\n\nThe Dialog component (also known as Modal) displays content in a layer above the page, blocking interaction with the rest of the application until dismissed.\n\n## Basic Usage\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\timport { Button } from 'entasis/button';\n\t\t\n</script>\n// By default Dialog comes with a button that trigger them, no need to define a callback and a $state\n<Dialog title=\"Dialog Title\">\n\tDialog content goes here\n</Dialog>\n```\n\n## Props\n\n### Core Props\n- **open**: boolean (bindable) - Controls dialog visibility\n- **defaultOpen**: boolean (default: false) - Initial state when open is not provided\n- **id**: string - Unique identifier for the dialog\n- **type**: 'fullScreen' | 'drawerRight' | 'drawerLeft' | 'drawerBottom' | 'drawerTop' | 'alert' | 'modal' (default: 'modal')\n - fullScreen: Full screen dialog overlay\n - drawerRight: Drawer sliding in from the right\n - drawerLeft: Drawer sliding in from the left\n - drawerBottom: Drawer sliding in from the bottom\n - drawerTop: Drawer sliding in from the top\n - alert: Alert-style dialog\n - modal: Standard modal dialog\n - Supports responsive values: pass a `Partial<Record<Breakpoint, DialogType>>` record such as `{ xs: 'drawerBottom', md: 'modal' }` to vary the type per breakpoint (breakpoint is one of 'xs' | 'sm' | 'md' | 'lg' | 'xl', tracked live from the viewport; the nearest defined key at or below the active one wins)\n- **responsive**: boolean (default: true) - When the resolved type is `modal`, collapse it into a `drawerBottom` bottom sheet on mobile (viewport < 768px). The sheet inherits swipe-to-dismiss and the drag thumb. Set false to keep a centered modal on every screen size\n\n### Layout Props\n- **size**: 'small' | 'normal' | 'large' (default: 'normal')\n - small: Compact dialog size\n - normal: Standard dialog size\n - large: Larger dialog size\n\n### Event Props\n- **onOpenChange**: (open: boolean) => void - Called once for each library-requested state change\n- **onAfterOpen**: (payload: DialogState) => void - Called after the open transition finishes\n- **onAfterClose**: (payload: DialogState) => void - Called after the close transition finishes\n\n### Slot Props\n- **title**: string | Snippet<[DialogState]> - Dialog title\n- **description**: string | Snippet<[DialogState]> - Dialog description\n- **children**: Snippet<[DialogState]> - Main dialog content\n- **header**: Snippet - Custom header content\n- **footer**: Snippet - Custom footer content\n- **trigger**: Snippet | (ButtonProps & { content?: string }) - Custom trigger button\n- **closeButton**: Snippet - Custom close button\n\n### Behavior Props\n- **closeOnEscape**: boolean (default: true) - Close when Escape key is pressed\n- **closeOnClickOutside**: boolean (default: true) - Close when clicking outside dialog\n- **closable**: boolean (default: true) - Whether dialog can be closed\n- **swipeToDismiss**: boolean (default: true for drawer types) - Drag the drawer toward its edge to dismiss. Direction-aware (drawerRight drags right, drawerBottom drags down, etc.) and never hijacks inner scrolling; opt elements out with `data-no-swipe`\n- **thumb**: boolean (default: true) - Drag thumb bar shown on swipe-dismissable drawers (inner edge, orientation follows the drawer side, oversized hitbox); set false to hide. Themeable via the `thumb` theme part\n- **inset**: a spacing step or `'none'` — how far a drawer stands off the screen edge for this dialog. Defaults to the theme's `designTokens.drawerInset` (`'layout-md'`). At `'none'` the drawer is edge to edge, its edge corners square off and only the corners facing the page stay rounded\n- **swipeFrom**: 'panel' | 'handle' (default: 'panel') - Where a swipe can start: anywhere on the panel, or only the drag handles (thumb and header)\n\n### Visual Props\n- **transition**: TransitionConfig - Custom transition animation\n\n### Styling Props\n- **class**: string - Additional CSS classes\n- **theme**: ComponentTheme - Custom theme overrides\n\n## Structure\n\n```\n<DialogOverlay>\n\t<DialogContent>\n\t\t<DialogHeader>\n\t\t\t<Title />\n\t\t\t<Description />\n\t\t\t<CloseButton />\n\t\t</DialogHeader>\n\t\t<DialogBody>\n\t\t\t<Children />\n\t\t</DialogBody>\n\t\t<DialogFooter />\n\t</DialogContent>\n</DialogOverlay>\n```\n\n## Examples\n\n### More Examples\n\n### A with a custom trigger \n```svelte\n\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\timport { Button } from 'entasis/button';\n\t\n\tlet open = $state(false);\n</script>\n\n\n<Dialog bind:open title=\"Welcome\">\n\t<p>This is a basic dialog.</p>\n\t\n\t{#snippet trigger(dialog)}\n\t\t<Button onclick={() => dialog.open()}>Open</Button>\n\t{/snippet}\n</Dialog>\n```\n\n### A with a custom as button props \n```svelte\n\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\timport { Button } from 'entasis/button';\n\t\n\tlet open = $state(false);\n</script>\n\n\n<Dialog bind:open title=\"Welcome\"\ntrigger={{\ncontent:\"Click me\",\ncolor:\"secondary\",\nsize:\"small\"\n}}\n>\n\t<p>This is a basic dialog.</p>\t\n</Dialog>\n```\n\n### With Description\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\t\n</script>\n\n<Dialog \t\n\ttitle=\"Confirm Action\"\n\tdescription=\"Are you sure you want to continue?\"\n>\n\t<p>This action cannot be undone.</p>\n</Dialog>\n```\n\n### Different Sizes\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\t\n\tlet open = $state(false);\n</script>\n\n```\n\n### Advanced Example\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\timport { Button } from 'entasis/button';\n\t\n\tlet open = $state(false);\n\t\n\tfunction handleConfirm() {\n\t\tconsole.log('Confirmed!');\n\t\topen = false;\n\t}\n</script>\n\n<Dialog bind:open title=\"Confirm\">\n\tAre you sure?\n\t\n\t{#snippet footer()}\n\t\t<div class=\"flex gap-2 justify-end\">\n\t\t\t<Button variant=\"ghost\" onclick={() => open = false}>\n\t\t\t\tCancel\n\t\t\t</Button>\n\t\t\t<Button color=\"danger\" onclick={handleConfirm}>\n\t\t\t\tConfirm\n\t\t\t</Button>\n\t\t</div>\n\t{/snippet}\n</Dialog>\n```\n\n### Drawer Types\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\t\n\t\n</script>\n\n<!-- Right drawer -->\n<Dialog type=\"drawerRight\" title=\"Side Drawer\">\n\tThis slides in from the right\n</Dialog>\n\n<!-- Left drawer -->\n<Dialog type=\"drawerLeft\" title=\"Left Drawer\">\n\tThis slides in from the left\n</Dialog>\n\n<!-- Bottom drawer -->\n<Dialog type=\"drawerBottom\" title=\"Bottom Drawer\">\n\tThis slides in from the bottom\n</Dialog>\n\n<!-- Full screen -->\n<Dialog type=\"fullScreen\" title=\"Full Screen\">\n\tFull screen dialog content\n</Dialog>\n```\n\n### Custom Header\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\timport { warningIcon } from 'entasis/icons/warning';\n</script>\n\n<Dialog bind:open>\n\t{#snippet header()}\n\t\t<div class=\"flex items-center gap-2\">\n\t\t\t{@render warningIcon()}\n\t\t\t<h2>Warning</h2>\n\t\t</div>\n\t{/snippet}\n\t\n\tThis is important!\n</Dialog>\n```\n\n\n### With Lifecycle Hooks\n\n```svelte\n<script>\n\timport { Dialog } from 'entasis/dialog';\n\t\n\tlet open = $state(false);\n</script>\n\n<Dialog \n\tbind:open\n\ttitle=\"Lifecycle\"\n\tonAfterOpen={(payload) => console.log('Dialog opened', payload)}\n\tonAfterClose={(payload) => console.log('Dialog closed', payload)}\n>\n\tWatch the console\n</Dialog>\n```\n\n## State Management\n\nThe Dialog component uses a `DialogState` instance that is passed to all slot snippets. This state object provides:\n\n- **id**: string - Dialog identifier\n- **type**: DialogType - Current dialog type\n- **size**: Size - Current dialog size\n- **open()**: () => void - Method to open the dialog\n- **close()**: () => void - Method to close the dialog\n\n## Accessibility\n\n- Initial focus goes to an `[autofocus]` / `[data-autofocus]` element inside the dialog, else the first tabbable control (the close button is skipped), else the panel itself\n- Tab and Shift+Tab are contained inside the dialog, and the rest of the page is `inert` while a modal is open\n- Focus is restored to the opener after the close transition finishes, just before `onAfterClose`\n- `aria-labelledby` links the `title` and `aria-describedby` links the `description`\n- Escape closes only the topmost open layer and an outside press dismisses the layers above the one pressed; both honour `closeOnEscape` / `closable` / `closeOnClickOutside` through the shared layer stack\n- Body scroll is locked when dialog is open\n\n## Notes\n\n- Multiple dialogs can be stacked\n- Last opened dialog receives focus\n- Background overlay prevents interaction with page\n- Scroll locking prevents background scroll\n- Transitions are customizable\n\n## Theme Customization\n\nThe Dialog 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- **motion**: Open/close transition preset, keyed by `type` (drawers fly from their edge). Takes\n `in` / `out` FSO params plus a `duration` / `easing` motion token; the `transition` prop wins\n over it\n- **root**: Dialog overlay/backdrop styles\n- **content**: Dialog content container styles\n- **thumb**: Drag thumb bar styles (type variant controls per-side placement)\n- **header**: Dialog header section styles\n- **footer**: Dialog footer section styles\n- **closeButton**: Close button styles\n- **title**: Dialog title text styles\n- **description**: Dialog description text styles\n\n### Theme Type Definition\n\n```typescript\nimport type { DialogThemeProps } from 'entasis/dialog';\n\n// Example theme customization\nconst customTheme: DialogThemeProps = {\n root: {\n base: 'z-[+50] fixed inset-0 flex',\n scroll: {\n inner: 'overflow-hidden',\n outer: 'overflow-auto'\n }\n },\n align: {\n type: {\n fullScreen: 'justify-center items-center',\n drawerRight: 'justify-end',\n drawerLeft: 'justify-start',\n drawerBottom: 'justify-center items-end',\n drawerTop: 'justify-center items-start',\n modal: 'justify-center',\n alert: 'justify-center'\n }\n },\n content: {\n size: {\n small: 'max-w-md w-full',\n normal: 'max-w-xl w-full',\n large: 'max-w-3xl w-full'\n },\n type: {\n fullScreen: 'h-full w-full max-w-full',\n drawerRight: 'rounded-r-[var(--drawer-edge-radius)] h-full',\n modal: ''\n }\n },\n header: {\n size: {\n small: '',\n normal: '',\n large: ''\n }\n },\n title: {\n size: {\n small: '',\n normal: '',\n large: ''\n }\n },\n description: {\n size: {\n small: '',\n normal: '',\n large: ''\n }\n }\n};\n```\n\n### Available Variants\n\n**root**:\n- base: Base classes for dialog overlay/backdrop\n- Variants:\n - size: 'small' | 'normal' | 'large' - Size constraints\n - type: 'fullScreen' | 'drawerRight' | 'drawerLeft' | 'drawerBottom' | 'drawerTop' | 'modal' | 'alert' - Dialog type/layout\n\n**content**:\n- base: Base classes for dialog content container\n- Variants:\n - size: 'small' | 'normal' | 'large' - Content max-width\n - type: 'fullScreen' | 'drawerRight' | 'drawerLeft' | 'drawerBottom' | 'drawerTop' | 'modal' | 'alert' - Content styling based on type\n\n**header**:\n- base: Base classes for header section\n- Variants:\n - size: 'small' | 'normal' | 'large' - Size-based styling\n\n**footer**:\n- base: Base classes for footer section\n- Variants:\n - size: 'small' | 'normal' | 'large' - Size-based styling\n\n**closeButton**:\n- base: Base classes for close button\n- Variants:\n - size: 'small' | 'normal' | 'large' - Size-based styling\n\n**title**:\n- base: Base classes for title 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### Usage Examples\n\n**Basic Theme Override**:\n```svelte\n<Dialog \n title=\"Custom Dialog\"\n theme={{\n content: {\n base: 'rounded-2xl raised-5',\n size: {\n normal: 'max-w-2xl'\n }\n },\n header: {\n base: 'border-b-2 border-primary'\n }\n }}\n>\n Custom styled dialog content\n</Dialog>\n```\n\n**Drawer Type Customization**:\n```svelte\n<Dialog \n type=\"drawerRight\"\n theme={{\n align: {\n type: {\n drawerRight: 'justify-end'\n }\n },\n backdrop: {\n base: 'bg-black/50'\n },\n content: {\n type: {\n drawerRight: 'rounded-l-xl raised-5'\n }\n }\n }}\n>\n Custom drawer styling\n</Dialog>\n```\n\n**Global Theme Setting**:\n```svelte\n<script>\n import { setDialogTheme } from '../components/Dialog/index.ts';\n \n setDialogTheme({\n root: {\n base: 'backdrop-blur-sm'\n },\n content: {\n base: 'lift-5 border-2',\n size: {\n normal: 'max-w-2xl'\n }\n },\n title: {\n base: 'text-2xl font-bold'\n }\n });\n</script>\n```\n";
108
108
  readonly 'floating-window': "\n# FloatingWindow Component\n\nFloatingWindow renders a non-modal, portaled utility window that can be moved, resized, minimized into a configurable viewport-edge dock, restored, and closed. Multiple windows inside the same Theme provider coordinate their z-order and stack independently by dock placement. The Theme keeps floating windows below modal Dialog surfaces, so an open window remains mounted behind a dialog and returns unchanged when the dialog closes.\n\n## Basic Usage\n\n```svelte\n<script lang=\"ts\">\n import { Button } from '../components/Button/index.ts';\n import { FloatingWindow } from '../components/FloatingWindow/index.ts';\n\n let open = $state(false);\n</script>\n\n<Button onclick={() => (open = true)}>Open notes</Button>\n\n<FloatingWindow bind:open title=\"Notes\">\n <p>Window content remains interactive alongside the page.</p>\n</FloatingWindow>\n```\n\n## Props\n\n- **id**: string - Stable DOM id. Generated when omitted.\n- **open**: boolean (default: true) - Bindable rendered state.\n- **defaultOpen**: boolean (default: true) - Initial state when open is not provided.\n- **minimized**: boolean (default: false) - Bindable docked state.\n- **dockPlacement**: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right' | 'left-top' | 'left-bottom' | 'right-top' | 'right-bottom' (default: 'bottom-left') - Edge and alignment used by the minimized dock. Top and bottom placements stack horizontally; left and right placements use a vertical title bar and stack vertically.\n- **title**: Slot<FloatingWindowPayload> (required) - Window title as text or a snippet.\n- **children**: Slot<FloatingWindowPayload> - Main content.\n- **dragFrom**: 'header' | 'window' (default: 'header') - Restricts dragging to the header or allows any non-interactive surface to start a drag.\n- **draggable**: boolean (default: true) - Enables pointer dragging.\n- **resizable**: boolean (default: true) - Enables four edge and four corner resize handles.\n- **minimizable**: boolean (default: true) - Shows the minimize control.\n- **closable**: boolean (default: true) - Shows the close control.\n- **closeOnEscape**: boolean (default: true) - Closes the topmost expanded floating window when Escape is pressed.\n- **position**: { x: number; y: number } - Bindable viewport-relative top-left position. The first render is centered when omitted.\n- **dimensions**: { width: number; height: number; min?: [width, height]; max?: [width, height] } (default: 480 x 320, minimum 280 x 160) - Bindable pixel dimensions and optional constraint tuples. Maximum dimensions remain additionally constrained to the viewport.\n- **class**: string - Additional classes on the visible window.\n- **theme**: FloatingWindowThemeProps - Per-instance theme overrides.\n- **ref**: HTMLDivElement - Bindable reference to the visible window or minimized dock item.\n- **onOpenChange**: (open: boolean) => void - Runs once for each library-requested state change.\n- **onAfterOpen**: (payload) => void - Runs after the open transition finishes.\n- **onAfterClose**: (payload) => void - Runs after the close transition finishes.\n- **onMinimize**: (payload) => void - Runs after minimize state updates.\n- **onRestore**: (payload) => void - Runs after restore state updates.\n- **onMove**: ({ position, window }) => void - Runs when a move commits.\n- **onResize**: ({ dimensions, window }) => void - Runs when a pointer or keyboard resize commits.\n\n## Dragging\n\nHeader dragging is the default because it preserves text selection and content interactions. With `dragFrom=\"window\"`, buttons, links, inputs, editable content, resize handles, and descendants marked `data-floating-window-no-drag` remain excluded from drag starts.\n\n## Accessibility\n\n- The expanded surface uses a non-modal `dialog` role and is labelled by its title.\n- Close, minimize, and restore controls are native Entasis buttons with accessible labels.\n- Edge resize handles use `separator` semantics and support arrow-key resizing; hold Shift for a larger step.\n- Opening focuses the non-modal window, closing restores focus to its previous owner, and only the topmost expanded floating window handles Escape.\n- Alt+Arrow moves the focused window; hold Shift for a larger step.\n- Corner handles are pointer-only because a diagonal separator has no valid ARIA orientation.\n- The component does not trap focus or hide page content because it is explicitly non-modal.\n\n## Theme Parts\n\n- **root**: Floating window surface and drag/resize states.\n- **header**: Default title bar and drag handle.\n- **title**: Header title.\n- **actions**: Header control group.\n- **control**: Header and dock icon buttons.\n- **scrollArea**: Flexible ScrollArea root that owns body scrolling.\n- **content**: Padded content inside the ScrollArea viewport.\n- **resizeHandle**: Edge and corner handles by direction.\n- **dockItem**: Minimized surface.\n- **dockTitle**: Full-width restore button in the dock item.\n- **dockTitleText**: Truncated title text and lateral writing direction.\n- **dockActions**: Dock restore and close controls.\n\n## Motion\n\n- **motion** theme slot, keyed by `phase`: `flight` times the crossfade between window and\n dock pill, `enter` / `exit` the scale fallback when there is no counterpart.\n- Only `duration` / `easing` (plus the fallback's `scale` / `opacity`) are read.\n- Ladder: `<Theme components={{ 'floating-window': { motion } }}>` →\n `setFloatingWindowTheme({ motion })` → `theme.motion`. Read once, at mount.\n";
109
109
  readonly 'hover-card': "\n# HoverCard Component\n\nHoverCard previews supplemental content when a trigger is hovered or focused. It composes Popover for positioning and dismissal with Card for the visible content surface.\n\n## Basic Usage\n\n```svelte\n<script lang=\"ts\">\n\timport { HoverCard } from 'entasis/hover-card';\n</script>\n\n<HoverCard\n\ttrigger={{ content: 'Hover @entasis', variant: 'link' }}\n\ttitle=\"@entasis\"\n\tdescription=\"Composable Svelte UI components.\"\n>\n\t<p>Preview content shown on hover or focus.</p>\n</HoverCard>\n```\n\n## Props\n\n### Core Props\n- **id**: string - Stable id for the underlying popover root.\n- **open**: boolean - Bindable open state.\n- **defaultOpen**: boolean (default: false) - Initial state when open is not provided.\n- **trigger**: string | Snippet<[HoverCardPayload]> | ButtonProps - Trigger content. ButtonProps render a Entasis Button.\n- **children**: string | Snippet<[HoverCardPayload]> - Main card content.\n- **title**: string | Snippet<[HoverCardPayload]> - Card title slot.\n- **description**: string | Snippet<[HoverCardPayload]> - Card description slot.\n- **footer**: string | Snippet<[HoverCardPayload]> - Card footer slot.\n\n### Behavior Props\n- **position**: Placement (default: 'top') - Preferred placement relative to the trigger.\n- **offset**: number (default: 8) - Gap between trigger and card.\n- **delay**: number (default: 150) - Delay before opening on hover or focus.\n- **closeDelay**: number (default: 100) - Delay before closing after pointer/focus leaves.\n- **openOnFocus**: boolean (default: true) - Opens when focus enters the trigger or card.\n- **openOnClick**: boolean (default: false) - Toggles on trigger click, useful for touch fallbacks.\n- **disabled**: boolean (default: false) - Prevents opening and disables Button triggers.\n\n### Dismissal and Transition Props\n- **closeOnEscape**: boolean (default: true) - Escape closes the hover card.\n- **closeOnClickOutside**: boolean (default: true) - Outside clicks close the hover card.\n- **directedTransition**: boolean (default: true) - Transition direction follows placement.\n- **transition**: ResponsiveProps<FSOProps> - Popover transition override.\n\n### Styling Props\n- **size**: 'small' | 'normal' | 'large' (default: 'normal') - Controls Popover panel and Card sizing.\n- **density**: 'compact' | 'normal' | 'comfortable' (default: 'normal') - Controls inner Card padding and spacing.\n- **class**: string - Extra classes on the inner Card.\n- **triggerClass**: string - Extra classes on the trigger wrapper.\n- **popover**: Props forwarded to the transparent Popover panel as one object - `{ class, theme }`.\n- **card**: Props forwarded to the inner Card as one object - `{ color, variant, theme }` (defaults: color 'neutral', variant 'solid').\n- **showBorders**: boolean (default: false) - Card section borders.\n- **theme**: HoverCardThemeProps - Theme overrides for HoverCard wrapper parts.\n\n### Callbacks\n- **onOpenChange**: (open: boolean) => void - Called once for each library-requested state change.\n- **onAfterOpen**: (payload: HoverCardPayload) => void - Called after the open transition finishes.\n- **onAfterClose**: (payload: HoverCardPayload) => void - Called after the close transition finishes.\n\n## Examples\n\n### Delays\n```svelte\n<HoverCard delay={300} closeDelay={200} trigger=\"Hover\">\n\tContent\n</HoverCard>\n```\n\n### Custom Trigger\n```svelte\n<HoverCard position=\"right\">\n\t{#snippet trigger(hoverCard)}\n\t\t<button aria-expanded={hoverCard.isOpen}>Preview</button>\n\t{/snippet}\n\n\tPreview content\n</HoverCard>\n```\n\n## Accessibility\n\n- Opens on pointer hover and keyboard focus by default.\n- Escape and outside click dismissal are delegated to Popover.\n- Button triggers receive aria-haspopup, aria-expanded, and aria-controls.\n- HoverCard is best for supplemental previews; primary content should remain reachable without hover.\n\n## Motion\n\n- **motion** theme slot: one preset (no variants) — a small lift plus scale on `fast` / `enter`.\n- Resolved by HoverCard and handed to the underlying Popover, replacing the popover preset.\n- Ladder: `<Theme components={{ 'hover-card': { motion } }}>` → `setHoverCardTheme({ motion })`\n → `theme.motion` → the `transition` prop. Reduced motion collapses it to 0.\n";
110
110
  readonly 'link-preview': "\n# LinkPreview Component\n\nLinkPreview renders an anchor trigger with a HoverCard preview that loads link metadata asynchronously. It shows Skeleton placeholders while loading and displays title, description, site name, Open Graph image, and favicon when available.\n\n## Import\n\n```svelte\n<script>\n\timport { LinkPreview } from 'entasis/link-preview';\n</script>\n```\n\n## Basic Usage\n\n```svelte\n<LinkPreview href=\"https://svelte.dev\">Svelte</LinkPreview>\n```\n\nBy default, LinkPreview requests `/api/link-metadata?url=<href>` when the card opens. Browser-only fetching of arbitrary links is not reliable because most sites block cross-origin HTML reads, so applications should provide a server endpoint or a custom `fetchMetadata` function.\n\n## With Preloaded Metadata\n\n```svelte\n<LinkPreview\n\thref=\"https://entasis.dev\"\n\tmetadata={{\n\t\ttitle: 'Entasis',\n\t\tdescription: 'Configuration-first Svelte components.',\n\t\tsiteName: 'Entasis',\n\t\tfavicon: '/favicon.png'\n\t}}\n>\n\tEntasis\n</LinkPreview>\n```\n\n## Custom Fetcher\n\n```svelte\n<script>\n\tconst fetchMetadata = async (href, signal) => {\n\t\tconst response = await fetch(`/api/preview?href=${encodeURIComponent(href)}`, { signal });\n\t\tif (!response.ok) throw new Error('Preview unavailable');\n\t\treturn response.json();\n\t};\n</script>\n\n<LinkPreview href=\"https://example.com\" {fetchMetadata}>Example</LinkPreview>\n```\n\n## Props\n\n- **href**: string - URL opened by the trigger link and requested by the metadata loader.\n- **id**: string - Stable DOM id for the underlying HoverCard; falls back to a generated id.\n- **open**: boolean - Bindable open state.\n- **defaultOpen**: boolean (default: false) - Initial state when open is not provided.\n- **children**: string | Snippet<[LinkPreviewPayload]> - Trigger anchor content.\n- **metadata**: LinkPreviewMetadata - Preloaded metadata; skips network loading.\n- **fetchMetadata**: (href, signal) => Promise<LinkPreviewMetadata> - Custom async loader.\n- **metadataEndpoint**: string | (href) => string - Endpoint used when fetchMetadata is not provided. String endpoints receive ?url=<href>.\n- **prefetch**: boolean - Load metadata on mount instead of waiting for open.\n- **target**: string - Trigger anchor target.\n- **rel**: string - Trigger anchor rel. Defaults to noopener noreferrer for target=\"_blank\".\n- **fallbackTitle**: string - Title shown when metadata has no title.\n- **imageAlt**: string - Alt text for the preview image.\n- **showUrl**: boolean - Whether to show the URL line.\n- **loadingLabel**: string - Accessible label for the loading region.\n- **errorLabel**: string - Heading shown when metadata loading fails.\n- **position**: Popover placement - Preferred card placement.\n- **offset**: number - Gap between trigger and card.\n- **delay**: number - Open delay in milliseconds.\n- **closeDelay**: number - Close delay in milliseconds.\n- **openOnFocus**: boolean - Open when focus enters trigger or card.\n- **openOnClick**: boolean - Toggle card on click before navigation.\n- **closeOnEscape**: boolean - Close on Escape.\n- **closeOnClickOutside**: boolean - Close when clicking outside.\n- **directedTransition**: boolean - Use placement-aware transitions.\n- **transition**: object - Popover transition overrides.\n- **size**: 'small' | 'normal' | 'large' - Preview card size.\n- **disabled**: boolean - Disable opening and link navigation.\n- **class**: string - Trigger anchor classes.\n- **card**: Props forwarded to the inner Card as one object - `{ class, color, variant, theme }` (defaults: color 'neutral', variant 'solid').\n- **popover**: Props forwarded to the Popover panel as one object - `{ class, theme }`.\n- **showBorders**: boolean - Show Card section borders.\n- **onOpenChange**: (open: boolean) => void - Called once for each library-requested state change.\n- **onAfterOpen**: (payload) => void - Called after open transition.\n- **onAfterClose**: (payload) => void - Called after close transition.\n- **onLoad**: (payload) => void - Called after metadata loads.\n- **onError**: (error) => void - Called after metadata loading fails.\n- **theme**: LinkPreviewThemeProps - LinkPreview theme overrides.\n- **hoverCardTheme**: HoverCardThemeProps - HoverCard wrapper theme overrides.\n\n## Metadata Shape\n\n```ts\ntype LinkPreviewMetadata = {\n\turl?: string;\n\ttitle?: string;\n\tdescription?: string;\n\tsiteName?: string;\n\timage?: string;\n\tfavicon?: string;\n};\n```\n\n## Endpoint Contract\n\nThe default endpoint should return JSON matching LinkPreviewMetadata. Non-2xx responses should return a JSON object with a `message` string when possible.\n\n## Accessibility\n\n- The trigger remains a real anchor, so the destination is reachable without hover.\n- Loading and error states use role=\"status\".\n- A disabled LinkPreview removes the anchor href and prevents hover opening.\n\n## Theme Parts\n\n- **trigger** - Anchor trigger.\n- **card** - HoverCard surface classes.\n- **content** - Preview content wrapper.\n- **media** - Image container.\n- **image** - Preview image.\n- **body** - Metadata text stack.\n- **header** - Favicon and site row.\n- **favicon** - Favicon image.\n- **site** - Site name text.\n- **title** - Preview title.\n- **description** - Preview description.\n- **url** - URL display line.\n- **loading** - Skeleton stack.\n- **error** - Error state container.\n\n## Motion\n\n- LinkPreview has no preset of its own: it forwards `transition` (now a plain `FSOProps`,\n responsive) to HoverCard, whose **motion** slot owns the preset.\n- Retune it with `<Theme components={{ 'hover-card': { motion } }}>` or\n `setHoverCardTheme({ motion })`; the `transition` prop still wins per instance.\n";
@@ -131,9 +131,9 @@ export declare const componentMcpRegistry: {
131
131
  readonly theme: "\n# Theme\n\n`Theme` owns global theme selection, runtime design tokens, shared overlay state, and theme\ntransitions. Wrap the application once and use the `ThemeState` received by the children snippet.\n\n## Runtime design tokens\n\n```svelte\n<script lang=\"ts\">\n\timport { Theme, type ThemeDesignTokenMap } from 'entasis/theme';\n\n\tlet spacing = $state<'small' | 'normal' | 'large'>('normal');\n\tconst designTokens = $derived({\n\t\tlight: {\n\t\t\tspacing,\n\t\t\tspacingScale: { xs: 1, sm: 1.5, md: 2, lg: 3, xl: 4 },\n\t\t\tradius: 'normal',\n\t\t\ttypeScale: 'default',\n\t\t\traisedWithBorder: true,\n\t\t\tdefaultColor: 'neutral'\n\t\t},\n\t\tdark: {\n\t\t\tspacing,\n\t\t\tspacingScale: { xs: 1, sm: 1.5, md: 2, lg: 3, xl: 4 },\n\t\t\tradius: 'small',\n\t\t\ttypeScale: 'compact',\n\t\t\traisedWithBorder: false,\n\t\t\tdefaultColor: 'neutral'\n\t\t}\n\t} satisfies ThemeDesignTokenMap<readonly ['light', 'dark']>);\n</script>\n\n<Theme {designTokens} transition=\"radial-top-right\">\n\t{#snippet children(theme)}\n\t\t<button onclick={() => (spacing = spacing === 'small' ? 'large' : 'small')}>\n\t\t\tChange density\n\t\t</button>\n\t\t<button onclick={() => (theme.theme = theme.resolvedTheme === 'dark' ? 'light' : 'dark')}>\n\t\t\tToggle color scheme\n\t\t</button>\n\t{/snippet}\n</Theme>\n```\n\n`designTokens` is keyed by logical theme name and respects the `attribute` and `value` props.\nEleven presets ship as `themePresets` (`dense`, `compact`, `balanced`, `comfortable`, `spacious`,\n`sharp`, `rounded`, `display`, `editorial`, `glass`, `terminal`): `designTokens={{ light: themePresets.glass.tokens, dark: themePresets.glass.tokens }}`.\nChanging the controlled object updates already-rendered Tailwind utilities without rebuilding CSS.\n\n### ThemeDesignTokens\n\n- `spacing`: `'small' | 'normal' | 'large' | number`. Globally scales density.\n- `spacingScale`: partial overrides for the strictly increasing `xs`, `sm`, `md`, `lg`,\n and `xl` spacing multipliers. Defaults to 1/1.5/2/3/4.\n- `radius`: `'none' | 'subtile' | 'small' | 'normal' | 'large' | 'round' | number`.\n- `typeScale`: `'compact' | 'default' | 'comfortable' | 'large' | TypeScaleOptions`.\n- `raisedWithBorder`: toggles the border used by `raised-*` utilities.\n- `defaultColor`: `Colors` role kit chrome inherits when a control omits `color`.\n Defaults to `neutral`. Set `primary` to restore an accent-colored kit. Compiles the\n current-color family (`--color`, `--color-readable`, muted/contrast/light/dark variants)\n and `--default-color` onto the theme selector. Do not set `data-color` on `html`.\n- `focusColor`, `selectedColor`, `hoverColor`, `pressedColor`: the four `Colors` **state\n roles**. They pin, for the whole theme, what a focus ring, a persistent selection and the\n transient hover/pressed layer look like, independently of the role of the control the state\n lands on. They compile `--color-focus`, `--color-selected` (plus its `-contrast`,\n `-readable` and `-muted-readable` companions), `--color-hover` and\n `--color-pressed` onto the theme selector. There is no `--color-selected-muted`: the soft\n fill is a translucent tint of `--color-selected` at `--state-selected-opacity`, so it reads\n on any surface. None is declared at `:root`: every use site\n falls back to the matching current role (`ring-focus` is\n `var(--color-focus, var(--color))`, `bg-selected-muted` tints\n `var(--color-selected, var(--color))`, the state layer is\n `var(--color-hover, currentColor)` and on `:active`\n `var(--color-pressed, var(--color-hover, currentColor))`), so leaving them unset changes\n nothing and `data-color` keeps moving the states with `--color`. Theme-level only: there is\n no per-component override. An unknown role throws.\n\nComponent-level density remains a local variant. It selects utility classes whose values inherit\nthe active global spacing token.\n\nGenerated interfaces should use the public `xs | sm | md | lg | xl` vocabulary through component\nprops and named gap/padding utilities. `micro` and `layout-*` are internal recipe tokens. Prefer\nparent-owned gaps over child margins; do not emit arbitrary spacing or unsupported radius values.\n\n## Theme selection\n\nThe selection props wrap `svelte-themes`: `themes`, `defaultTheme`, `forcedTheme`,\n`systemTheme`, `syncColorScheme`, `transitionOnChange`, `storageKey`, `attribute`,\n`value`, and `colorScheme`. The default themes are light and dark, with system selection\nenabled. `systemTheme`, `syncColorScheme`, and `transitionOnChange` all default to\n`true`; they map onto the library's `enableSystem`, `enableColorScheme`, and\n`disableTransitionOnChange` options.\n\n`ThemeState` exposes `theme`, `resolvedTheme`, `themes`, and `systemTheme`. Assign\n`theme.theme` to switch themes. The optional `transition` prop applies a named view transition;\nunsupported browsers and reduced-motion users switch instantly.\n\n`spinnerVariant` sets the global default spinner animation. The children snippet is required.\n\n## Motion tokens\n\nMotion is a token scale like spacing and radius: five duration steps and four easing roles.\n`motion` retunes them app-wide; an omitted token keeps its default.\n\n| Duration | Default | | Easing role | Default |\n| ---------- | ------- | --- | ------------ | ------------- |\n| `instant` | 0ms | | `standard` | `cubicInOut` |\n| `fast` | 100ms | | `enter` | `cubicOut` |\n| `normal` | 200ms | | `exit` | `cubicIn` |\n| `slow` | 300ms | | `emphasized` | `backOut` |\n| `slower` | 500ms | | | |\n\n```svelte\n<script lang=\"ts\">\n\timport { Theme } from 'entasis/theme';\n\n\tlet { children } = $props();\n</script>\n\n<Theme motion={{ duration: { normal: 150, slow: 260 }, easing: { standard: 'quintOut' } }}>\n\t{@render children()}\n</Theme>\n```\n\nThe Tailwind plugin emits the same scale as CSS variables on `html` (`--duration-normal`,\n`--ease-standard`, ...) plus the matching `duration-*` / `ease-*` utilities, so CSS transitions\nand Svelte transitions read one set of numbers. The `motion` prop rewrites those variables on\n`html` at runtime and `designTokens.motion` rewrites them again per theme, layered over the prop;\n`ThemeState.motion` resolves through the same two rungs, so the utilities and the presets never\ndisagree. `ThemeState.transition` is a deprecated alias for its `normal` duration and `standard`\neasing. Reduced motion resolves every duration to 0 and collapses the `--duration-*` variables via\nthe `data-entasis-reduce-motion` attribute on `html`.\n\nComponents keep their own transition in a reserved `motion` slot on their theme, so the `theme`\nprop covers motion as well as classes:\n\n```svelte\n<script lang=\"ts\">\n\timport { Dialog } from 'entasis/dialog';\n</script>\n\n<Dialog theme={{ motion: { duration: 'fast', easing: 'emphasized' } }} title=\"Quick\">Body</Dialog>\n```\n\n## Component theme registry\n\n`components` sets app-wide component theme defaults without a wrapper component per component:\nit is keyed by theme name (`dialog`, `button`, ...) and each entry takes the same slots as that\ncomponent's `theme` prop, the `motion` slot included. A `set<Component>Theme` call in a subtree\nbeats the registry, and an instance `theme` prop beats both — per slot: each rung layers on the one\nbelow it, so a subtree that restyles one slot keeps the registry's others.\n\n```svelte\n<script lang=\"ts\">\n\timport { Theme } from 'entasis/theme';\n\n\tlet { children } = $props();\n</script>\n\n<Theme\n\tcomponents={{\n\t\tdialog: { motion: { duration: 'fast' }, content: { base: 'rounded-2xl' } },\n\t\tbutton: { root: { base: 'tracking-wide' } }\n\t}}\n>\n\t{@render children()}\n</Theme>\n```\n\n## Reduced motion\n\n`reduceMotion` forces reduced motion on (`true`) or off (`false`) for every entasis animation,\noverriding the OS `prefers-reduced-motion` setting; omit it to follow the OS. The live result is\nexposed as `ThemeState.preferReducesMotion` (reactive, so it updates when the OS setting changes)\nand mirrored as a `data-entasis-reduce-motion` attribute on `html` for CSS-only animations.\n\n```svelte\n<script>\n\timport { Theme } from 'entasis/theme';\n\n\tlet { children } = $props();\n</script>\n\n<Theme reduceMotion>{@render children()}</Theme>\n```\n\n## Build-time boundary\n\nThe Tailwind plugin still generates color palettes and registers utility names, variants,\nkeyframes, and spinner CSS. Spacing, radius, typography scale, raised borders,\n`defaultColor` and the four state roles (`focusColor`, `selectedColor`, `hoverColor`,\n`pressedColor`) belong to `Theme.designTokens`; colors remain CSS variables and can be\noverridden directly. `ThemeState.defaultColor` exposes the active role. Kit chrome should\nresolve omitted `color` props with `useDefaultColor`.\n";
132
132
  readonly i18n: "\n# Internationalization\n\nImport from `entasis/i18n`.\n\nI18n provides locale messages to child components. setI18n and useI18n set and read the component context. en is the English message set; Messages and I18nInput describe translation inputs. locales and localeList expose the supported locale inventory with LocaleCode and LocaleMeta types.\n";
133
133
  readonly 'tailwind-plugin': "\n# Main Tailwind plugin\n\n`@plugin 'entasis/tailwind-plugin'`\n\nThis palette-agnostic plugin registers shared utilities, variants, keyframes, and spinner CSS.\nUse it when colors are defined separately instead of through the theme plugin.\n\n## Configuration\n\n`spinner`\n- **Type**: `Spinner` object\n- **Default**: Auto-generated\n- **Description**: Custom spinner configuration for the `.ui-spinner` class\n\n## Shared utilities\n\n### `.state-layer`\n- Composites `currentColor` at `--state-hover-opacity` on hover and `data-highlighted=\"true\"`\n- Composites `currentColor` at `--state-pressed-opacity` on `:active`\n- Does not activate for disabled, `data-disabled`, or `aria-disabled=\"true\"` elements\n- Theme plugin defaults the opacities to 5% and 10% in light themes, and 16% and 32% in dark themes\n\n### `bg-selected-muted` / `rounded-<step>-concentric`\n- `bg-selected-muted` composites `var(--color-selected, var(--color))` at\n `--state-selected-opacity` (0.07 light, 0.10 dark), so a persistent selection reads the same on\n `surface`, `surface-raised` and `surface-floating`. `bg-color-muted` stays opaque.\n- `rounded-<step>-concentric` (also `rounded-t-<step>-concentric` /\n `rounded-b-<step>-concentric`, with `<step>` one of `xs sm md lg xl 2xl 3xl 4xl`) keeps the\n child on its own design step but caps it at what concentricity allows inside a rounded padded\n container:\n `min(var(--radius-<step>), var(--radius-parent) - max(--pad-parent-x, --pad-parent-y))`. The\n container declares nothing: every `rounded-<step>` publishes `--radius-parent` to its\n children and `p` / `px` / `py` publish `--pad-parent-x/-y`, so the two boxes stay\n concentric at every `radius` preset. Outside any rounded container the parent radius is\n infinite, so the child is exactly its step; a negative difference clamps to 0, a square corner.\n Put it on a child that sits flush against the padding box; a floating child (an avatar, a\n Button, a Chip) keeps its own radius.\n\nConfigure spacing, radius, typography scale, and raised borders at runtime through\n`Theme.designTokens`.\n\nSemantic spacing utilities use the active theme's `xs`, `sm`, `md`, `lg`, and `xl`\nscale for gaps, padding, margins, and physical insets. For example, `gap-lg`, `p-lg`,\n`top-lg`, and `left-lg` use the same spacing value. Inset utilities support `top`,\n`right`, `bottom`, and `left`, including responsive variants.\n";
134
- readonly 'theme-tailwind-plugin': "\n# Theme Tailwind plugin\n\n`@plugin 'entasis/tailwind-plugin/theme'` generates color variables for each named theme. The declaration\nmarked `default: true` also registers the shared utility vocabulary, variants, spinner styles,\nand keyframes.\n\n```css\n@import 'tailwindcss';\n\n@plugin 'entasis/tailwind-plugin/theme' {\n\tname: light;\n\tdefault: true;\n\tcolorscheme: light;\n\tprimary: #5f62ef;\n\tsecondary: #e4e4e7;\n\tsurface: #fafafa;\n\tneutral: #18181b;\n}\n\n@plugin 'entasis/tailwind-plugin/theme' {\n\tname: dark;\n\tcolorscheme: dark;\n\tprimary: #5f62ef;\n\tsecondary: #27272a;\n\tsurface: #09090b;\n\tneutral: #fafafa;\n}\n```\n\n## Identity\n\n- `name: string` scopes variables to `html[data-theme=\"<name>\"]` and `.<name>`.\n- `default: boolean` also applies the palette to bare `html` and installs the shared engine.\n- `colorscheme: 'light' | 'dark'` controls mode-aware color defaults.\n- `prefersDark: boolean` also emits the palette under the dark system media query.\n\n## Palette inputs\n\nBase semantic colors are `primary`, `secondary`, `danger`, `success`, `warning`, `info`,\nand `neutral`. `surface` seeds the elevation ladder: `surface-recessed`,\n`surface-canvas`, `surface`, `surface-raised`, and `surface-floating`.\n\nEach semantic color supports explicit `-light`, `-lighter`, `-dark`, `-muted`,\n`-contrast`, `-readable`, and `-muted-readable` overrides. Missing variants are generated.\n`luminance` and `saturation` adjust the generated palette.\n\n`state-hover-opacity` and `state-pressed-opacity` calibrate the CSS variables consumed by\n`.state-layer`. They default to 0.05/0.10 in light mode and 0.16/0.32 in dark mode.\n`state-selected-opacity` (0.07 light, 0.10 dark) is the alpha `bg-selected-muted` composites the\nselected role at: the soft selection fill is a translucent tint, not an opaque colour, so it reads\nthe same on `surface`, `surface-raised` and `surface-floating`.\n\n## Runtime boundary\n\nSpacing, radius, typography scale, raised borders, `defaultColor` and the four state roles\n(`focusColor`, `selectedColor`, `hoverColor`, `pressedColor`) are not plugin options.\nConfigure them with the `designTokens` prop on `Theme`. Tailwind still discovers and compiles\nthe finite utility names; runtime theming changes the CSS variables those utilities consume.\n\nThe public spacing vocabulary is `xs | sm | md | lg | xl`, available through named gap, padding,\nand margin utilities such as `gap-md` and `px-lg`. The `micro` and `layout-*` values are\ninternal component-recipe tokens. Generated interfaces should prefer Stack/Grid gaps and must not\nemit arbitrary spacing or unsupported radius utilities.\n\nColor variables can also be overridden directly at runtime:\n\n```css\nhtml[data-theme='light'] {\n\t--color-primary: oklab(0.21 0.01 -0.03);\n}\n```\n";
134
+ readonly 'theme-tailwind-plugin': "\n# Theme Tailwind plugin\n\n`@plugin 'entasis/tailwind-plugin/theme'` generates color variables for each named theme. The declaration\nmarked `default: true` also registers the shared utility vocabulary, variants, spinner styles,\nand keyframes.\n\n```css\n@import 'tailwindcss';\n\n@plugin 'entasis/tailwind-plugin/theme' {\n\tname: light;\n\tdefault: true;\n\tcolorscheme: light;\n\tprimary: #5f62ef;\n\tsecondary: #e4e4e7;\n\tsurface: #fafafa;\n\tneutral: #18181b;\n}\n\n@plugin 'entasis/tailwind-plugin/theme' {\n\tname: dark;\n\tcolorscheme: dark;\n\tprimary: #5f62ef;\n\tsecondary: #27272a;\n\tsurface: #09090b;\n\tneutral: #fafafa;\n}\n```\n\n## Identity\n\n- `name: string` scopes variables to `html[data-theme=\"<name>\"]` and `.<name>`.\n- `default: boolean` also applies the palette to bare `html` and installs the shared engine.\n- `colorscheme: 'light' | 'dark'` controls mode-aware color defaults.\n- `prefersDark: boolean` also emits the palette under the dark system media query.\n\n## Palette inputs\n\nBase semantic colors are `primary`, `secondary`, `danger`, `success`, `warning`, `info`,\nand `neutral`. `surface` seeds the elevation ladder: `surface-recessed`,\n`surface-canvas`, `surface`, `surface-raised`, and `surface-floating`.\n\nEach semantic color supports explicit `-light`, `-lighter`, `-dark`, `-muted`,\n`-contrast`, `-readable`, and `-muted-readable` overrides. Missing variants are generated.\n`luminance` and `saturation` adjust the generated palette.\n\n`state-hover-opacity` and `state-pressed-opacity` calibrate the CSS variables consumed by\n`.state-layer`. They default to 0.05/0.10 in light mode and 0.16/0.32 in dark mode. `state-layer-none` switches that overlay off on one element.\n`state-selected-opacity` (0.07 light, 0.10 dark) is the alpha `bg-selected-muted` composites the\nselected role at: the soft selection fill is a translucent tint, not an opaque colour, so it reads\nthe same on `surface`, `surface-raised` and `surface-floating`.\n\n## Runtime boundary\n\nSpacing, radius, typography scale, raised borders, `defaultColor` and the four state roles\n(`focusColor`, `selectedColor`, `hoverColor`, `pressedColor`) are not plugin options.\nConfigure them with the `designTokens` prop on `Theme`. Tailwind still discovers and compiles\nthe finite utility names; runtime theming changes the CSS variables those utilities consume.\n\nThe public spacing vocabulary is `xs | sm | md | lg | xl`, available through named gap, padding,\nand margin utilities such as `gap-md` and `px-lg`. The `micro` and `layout-*` values are\ninternal component-recipe tokens. Generated interfaces should prefer Stack/Grid gaps and must not\nemit arbitrary spacing or unsupported radius utilities.\n\nColor variables can also be overridden directly at runtime:\n\n```css\nhtml[data-theme='light'] {\n\t--color-primary: oklab(0.21 0.01 -0.03);\n}\n```\n";
135
135
  readonly types: "\n# Shared theme types\n\nImport from `entasis/types`.\n\nColors names semantic palette roles. Sizes selects small, normal, or large component geometry. Density uses a separate compact/normal/comfortable scale for internal whitespace, so a density value can never be passed where a size is expected. The module also exports theme color paths, typography paths, transition easing, style types, and deepMerge for composing nested theme values.\n";
136
- readonly cva: "\n# Component variants\n\nImport from `entasis/cva`.\n\ncva defines class variants and defaults. cx joins class values; compose composes variants. setComponentTheme and useComponentTheme connect component theme definitions to the Svelte theme context. VariantProps and InferComponentTheme derive the corresponding public types. Keep component CVA definitions beside their owner in a .theme.ts file.\n";
136
+ readonly cva: "\n# Component variants\n\nImport from `entasis/cva`.\n\ncva defines class variants and defaults. cx joins class values; compose composes variants. setComponentTheme and useComponentTheme connect component theme definitions to the Svelte theme context. A resolver takes an optional second argument, the shared variant values, and then returns every class slot already bound to them, so a template calls `slots.root()` instead of passing the same props to each slot. VariantProps and InferComponentTheme derive the corresponding public types. Keep component CVA definitions beside their owner in a .theme.ts file.\n";
137
137
  readonly scheduling: "\n# Scheduling layout\n\nImport from `entasis/scheduling`.\n\npackSchedulingLanes and packSchedulingOverlaps compute placements for scheduling intervals. SchedulingInterval, SchedulingLaneInterval, the lane placement and layout types, and the overlap placement and layout types describe their inputs and results. EventCalendar and GanttChart share these layout algorithms.\n";
138
138
  readonly icons: "\n\n## Available Icons\n\nThis library includes 1513 icons. Each icon has 6 variants: regular, bold, duotone, fill, light, and thin.\n\n### Icon List\n\nacorn, addressBook, addressBookTabs, airplane, airplaneInFlight, airplaneLanding, airplaneTakeoff, airplaneTaxiing, airplaneTilt, airplay, airTrafficControl, alarm, alien, alignBottom, alignBottomSimple, alignCenterHorizontal, alignCenterHorizontalSimple, alignCenterVertical, alignCenterVerticalSimple, alignLeft, alignLeftSimple, alignRight, alignRightSimple, alignTop, alignTopSimple, amazonLogo, ambulance, anchor, anchorSimple, androidLogo, angle, angularLogo, aperture, appleLogo, applePodcastsLogo, approximateEquals, appStoreLogo, appWindow, archive, armchair, arrowArcLeft, arrowArcRight, arrowBendDoubleUpLeft, arrowBendDoubleUpRight, arrowBendDownLeft, arrowBendDownRight, arrowBendLeftDown, arrowBendLeftUp, arrowBendRightDown, arrowBendRightUp, arrowBendUpLeft, arrowBendUpRight, arrowCircleDown, arrowCircleDownLeft, arrowCircleDownRight, arrowCircleLeft, arrowCircleRight, arrowCircleUp, arrowCircleUpLeft, arrowCircleUpRight, arrowClockwise, arrowCounterClockwise, arrowDown, arrowDownLeft, arrowDownRight, arrowElbowDownLeft, arrowElbowDownRight, arrowElbowLeft, arrowElbowLeftDown, arrowElbowLeftUp, arrowElbowRight, arrowElbowRightDown, arrowElbowRightUp, arrowElbowUpLeft, arrowElbowUpRight, arrowFatDown, arrowFatLeft, arrowFatLineDown, arrowFatLineLeft, arrowFatLineRight, arrowFatLinesDown, arrowFatLinesLeft, arrowFatLinesRight, arrowFatLinesUp, arrowFatLineUp, arrowFatRight, arrowFatUp, arrowLeft, arrowLineDown, arrowLineDownLeft, arrowLineDownRight, arrowLineLeft, arrowLineRight, arrowLineUp, arrowLineUpLeft, arrowLineUpRight, arrowRight, arrowsClockwise, arrowsCounterClockwise, arrowsDownUp, arrowsHorizontal, arrowsIn, arrowsInCardinal, arrowsInLineHorizontal, arrowsInLineVertical, arrowsInSimple, arrowsLeftRight, arrowsMerge, arrowsOut, arrowsOutCardinal, arrowsOutLineHorizontal, arrowsOutLineVertical, arrowsOutSimple, arrowSquareDown, arrowSquareDownLeft, arrowSquareDownRight, arrowSquareIn, arrowSquareLeft, arrowSquareOut, arrowSquareRight, arrowSquareUp, arrowSquareUpLeft, arrowSquareUpRight, arrowsSplit, arrowsVertical, arrowUDownLeft, arrowUDownRight, arrowULeftDown, arrowULeftUp, arrowUp, arrowUpLeft, arrowUpRight, arrowURightDown, arrowURightUp, arrowUUpLeft, arrowUUpRight, article, articleMedium, articleNyTimes, asclepius, asterisk, asteriskSimple, at, atom, avocado, axe, baby, babyCarriage, backpack, backspace, bag, bagSimple, balloon, bandaids, bank, barbell, barcode, barn, barricade, baseball, baseballCap, baseballHelmet, basket, basketball, bathtub, batteryCharging, batteryChargingVertical, batteryEmpty, batteryFull, batteryHigh, batteryLow, batteryMedium, batteryPlus, batteryPlusVertical, batteryVerticalEmpty, batteryVerticalFull, batteryVerticalHigh, batteryVerticalLow, batteryVerticalMedium, batteryWarning, batteryWarningVertical, beachBall, beanie, bed, beerBottle, beerStein, behanceLogo, bell, bellRinging, bellSimple, bellSimpleRinging, bellSimpleSlash, bellSimpleZ, bellSlash, bellZ, belt, bezierCurve, bicycle, binary, binoculars, biohazard, bird, blueprint, bluetooth, bluetoothConnected, bluetoothSlash, bluetoothX, boat, bomb, bone, book, bookBookmark, bookmark, bookmarks, bookmarkSimple, bookmarksSimple, bookOpen, bookOpenText, bookOpenUser, books, bookUser, boot, boules, boundingBox, bowlFood, bowlingBall, bowlSteam, boxArrowDown, boxArrowUp, boxingGlove, bracketsAngle, bracketsCurly, bracketsRound, bracketsSquare, brain, brandy, bread, bridge, briefcase, briefcaseMetal, broadcast, broom, browser, browsers, bug, bugBeetle, bugDroid, building, buildingApartment, buildingOffice, buildings, bulldozer, bus, butterfly, cableCar, cactus, cake, calculator, calendar, calendarBlank, calendarCheck, calendarDot, calendarDots, calendarHeart, calendarMinus, calendarPlus, calendarSlash, calendarStar, calendarX, callBell, camera, cameraPlus, cameraRotate, cameraSlash, campfire, car, carBattery, cardholder, cards, cardsThree, caretCircleDoubleDown, caretCircleDoubleLeft, caretCircleDoubleRight, caretCircleDoubleUp, caretCircleDown, caretCircleLeft, caretCircleRight, caretCircleUp, caretCircleUpDown, caretDoubleDown, caretDoubleLeft, caretDoubleRight, caretDoubleUp, caretDown, caretLeft, caretLineDown, caretLineLeft, caretLineRight, caretLineUp, caretRight, caretUp, caretUpDown, carProfile, carrot, carSimple, cashRegister, cassetteTape, castleTurret, cat, cellSignalFull, cellSignalHigh, cellSignalLow, cellSignalMedium, cellSignalNone, cellSignalSlash, cellSignalX, cellTower, certificate, chair, chalkboard, chalkboardSimple, chalkboardTeacher, champagne, chargingStation, chartBar, chartBarHorizontal, chartDonut, chartLine, chartLineDown, chartLineUp, chartPie, chartPieSlice, chartPolar, chartScatter, chat, chatCentered, chatCenteredDots, chatCenteredSlash, chatCenteredText, chatCircle, chatCircleDots, chatCircleSlash, chatCircleText, chatDots, chats, chatsCircle, chatSlash, chatsTeardrop, chatTeardrop, chatTeardropDots, chatTeardropSlash, chatTeardropText, chatText, check, checkCircle, checkerboard, checkFat, checks, checkSquare, checkSquareOffset, cheers, cheese, chefHat, cherries, church, cigarette, cigaretteSlash, circle, circleDashed, circleHalf, circleHalfTilt, circleNotch, circlesFour, circlesThree, circlesThreePlus, circuitry, city, clipboard, clipboardText, clock, clockAfternoon, clockClockwise, clockCountdown, clockCounterClockwise, clockUser, closedCaptioning, cloud, cloudArrowDown, cloudArrowUp, cloudCheck, cloudFog, cloudLightning, cloudMoon, cloudRain, cloudSlash, cloudSnow, cloudSun, cloudWarning, cloudX, clover, club, coatHanger, codaLogo, code, codeBlock, codepenLogo, codesandboxLogo, codeSimple, coffee, coffeeBean, coin, coins, coinVertical, columns, columnsPlusLeft, columnsPlusRight, command, compass, compassRose, compassTool, computerTower, confetti, contactlessPayment, control, cookie, cookingPot, copy, copyleft, copyright, copySimple, cornersIn, cornersOut, couch, courtBasketball, cow, cowboyHat, cpu, crane, craneTower, creditCard, cricket, crop, cross, crosshair, crosshairSimple, crown, crownCross, crownSimple, cube, cubeFocus, cubeTransparent, currencyBtc, currencyCircleDollar, currencyCny, currencyDollar, currencyDollarSimple, currencyEth, currencyEur, currencyGbp, currencyInr, currencyJpy, currencyKrw, currencyKzt, currencyNgn, currencyRub, cursor, cursorClick, cursorText, cylinder, database, desk, desktop, desktopTower, detective, deviceMobile, deviceMobileCamera, deviceMobileSlash, deviceMobileSpeaker, deviceRotate, devices, deviceTablet, deviceTabletCamera, deviceTabletSpeaker, devToLogo, diamond, diamondsFour, diceFive, diceFour, diceOne, diceSix, diceThree, diceTwo, disc, discoBall, discordLogo, divide, dna, dog, door, doorOpen, dot, dotOutline, dotsNine, dotsSix, dotsSixVertical, dotsThree, dotsThreeCircle, dotsThreeCircleVertical, dotsThreeOutline, dotsThreeOutlineVertical, dotsThreeVertical, download, downloadSimple, dress, dresser, dribbbleLogo, drone, drop, dropboxLogo, dropHalf, dropHalfBottom, dropSimple, dropSlash, ear, earSlash, egg, eggCrack, eject, ejectSimple, elevator, empty, engine, envelope, envelopeOpen, envelopeSimple, envelopeSimpleOpen, equalizer, equals, eraser, escalatorDown, escalatorUp, exam, exclamationMark, exclude, excludeSquare, export, eye, eyeClosed, eyedropper, eyedropperSample, eyeglasses, eyes, eyeSlash, facebookLogo, faceMask, factory, faders, fadersHorizontal, falloutShelter, fan, farm, fastForward, fastForwardCircle, feather, fediverseLogo, figmaLogo, file, fileArchive, fileArrowDown, fileArrowUp, fileAudio, fileC, fileCloud, fileCode, fileCpp, fileCSharp, fileCss, fileCsv, fileDashed, fileDoc, fileHtml, fileImage, fileIni, fileJpg, fileJs, fileJsx, fileLock, fileMagnifyingGlass, fileMd, fileMinus, filePdf, filePlus, filePng, filePpt, filePy, fileRs, files, fileSql, fileSvg, fileText, fileTs, fileTsx, fileTxt, fileVideo, fileVue, fileX, fileXls, fileZip, filmReel, filmScript, filmSlate, filmStrip, fingerprint, fingerprintSimple, finnTheHuman, fire, fireExtinguisher, fireSimple, fireTruck, firstAid, firstAidKit, fish, fishSimple, flag, flagBanner, flagBannerFold, flagCheckered, flagPennant, flame, flashlight, flask, flipHorizontal, flipVertical, floppyDisk, floppyDiskBack, flowArrow, flower, flowerLotus, flowerTulip, flyingSaucer, folder, folderDashed, folderLock, folderMinus, folderOpen, folderPlus, folders, folderSimple, folderSimpleDashed, folderSimpleLock, folderSimpleMinus, folderSimplePlus, folderSimpleStar, folderSimpleUser, folderStar, folderUser, football, footballHelmet, footprints, forkKnife, fourK, frameCorners, framerLogo, function, funnel, funnelSimple, funnelSimpleX, funnelX, gameController, garage, gasCan, gasPump, gauge, gavel, gear, gearFine, gearSix, genderFemale, genderIntersex, genderMale, genderNeuter, genderNonbinary, genderTransgender, ghost, gif, gift, gitBranch, gitCommit, gitDiff, gitFork, githubLogo, gitlabLogo, gitlabLogoSimple, gitMerge, gitPullRequest, globe, globeHemisphereEast, globeHemisphereWest, globeSimple, globeSimpleX, globeStand, globeX, goggles, golf, goodreadsLogo, googleCardboardLogo, googleChromeLogo, googleDriveLogo, googleLogo, googlePhotosLogo, googlePlayLogo, googlePodcastsLogo, gps, gpsFix, gpsSlash, gradient, graduationCap, grains, grainsSlash, graph, graphicsCard, greaterThan, greaterThanOrEqual, gridFour, gridNine, guitar, hairDryer, hamburger, hammer, hand, handArrowDown, handArrowUp, handbag, handbagSimple, handCoins, handDeposit, handEye, handFist, handGrabbing, handHeart, handPalm, handPeace, handPointing, handsClapping, handshake, handSoap, handsPraying, handSwipeLeft, handSwipeRight, handTap, handWaving, handWithdraw, hardDrive, hardDrives, hardHat, hash, hashStraight, headCircuit, headlights, headphones, headset, heart, heartbeat, heartBreak, heartHalf, heartStraight, heartStraightBreak, hexagon, highDefinition, highHeel, highlighter, highlighterCircle, hockey, hoodie, horse, hospital, hourglass, hourglassHigh, hourglassLow, hourglassMedium, hourglassSimple, hourglassSimpleHigh, hourglassSimpleLow, hourglassSimpleMedium, house, houseLine, houseSimple, hurricane, iceCream, identificationBadge, identificationCard, image, imageBroken, images, imageSquare, imagesSquare, infinity, info, instagramLogo, intersect, intersection, intersectSquare, intersectThree, invoice, island, jar, jarLabel, jeep, joystick, kanban, key, keyboard, keyhole, keyReturn, knife, ladder, ladderSimple, lamp, lampPendant, laptop, lasso, lastfmLogo, layout, leaf, lectern, lego, legoSmiley, lessThan, lessThanOrEqual, letterCircleH, letterCircleP, letterCircleV, lifebuoy, lightbulb, lightbulbFilament, lighthouse, lightning, lightningA, lightningSlash, lineSegment, lineSegments, lineVertical, link, linkBreak, linkedinLogo, linkSimple, linkSimpleBreak, linkSimpleHorizontal, linkSimpleHorizontalBreak, linktreeLogo, linuxLogo, list, listBullets, listChecks, listDashes, listHeart, listMagnifyingGlass, listNumbers, listPlus, listStar, lock, lockers, lockKey, lockKeyOpen, lockLaminated, lockLaminatedOpen, lockOpen, lockSimple, lockSimpleOpen, log, magicWand, magnet, magnetStraight, magnifyingGlass, magnifyingGlassMinus, magnifyingGlassPlus, mailbox, mapPin, mapPinArea, mapPinLine, mapPinPlus, mapPinSimple, mapPinSimpleArea, mapPinSimpleLine, mapTrifold, markdownLogo, markerCircle, martini, maskHappy, maskSad, mastodonLogo, mathOperations, matrixLogo, medal, medalMilitary, mediumLogo, megaphone, megaphoneSimple, memberOf, memory, messengerLogo, metaLogo, meteor, metronome, microphone, microphoneSlash, microphoneStage, microscope, microsoftExcelLogo, microsoftOutlookLogo, microsoftPowerpointLogo, microsoftTeamsLogo, microsoftWordLogo, minus, minusCircle, minusSquare, money, moneyWavy, monitor, monitorArrowUp, monitorPlay, moon, moonStars, moped, mopedFront, mosque, motorcycle, mountains, mouse, mouseLeftClick, mouseMiddleClick, mouseRightClick, mouseScroll, mouseSimple, musicNote, musicNotes, musicNoteSimple, musicNotesMinus, musicNotesPlus, musicNotesSimple, navigationArrow, needle, network, networkSlash, networkX, newspaper, newspaperClipping, notches, note, noteBlank, notebook, notepad, notePencil, notEquals, notification, notionLogo, notMemberOf, notSubsetOf, notSupersetOf, nuclearPlant, numberCircleEight, numberCircleFive, numberCircleFour, numberCircleNine, numberCircleOne, numberCircleSeven, numberCircleSix, numberCircleThree, numberCircleTwo, numberCircleZero, numberEight, numberFive, numberFour, numberNine, numberOne, numberSeven, numberSix, numberSquareEight, numberSquareFive, numberSquareFour, numberSquareNine, numberSquareOne, numberSquareSeven, numberSquareSix, numberSquareThree, numberSquareTwo, numberSquareZero, numberThree, numberTwo, numberZero, numpad, nut, nyTimesLogo, octagon, officeChair, onigiri, openAiLogo, option, orange, orangeSlice, oven, package, paintBrush, paintBrushBroad, paintBrushHousehold, paintBucket, paintRoller, palette, panorama, pants, paperclip, paperclipHorizontal, paperPlane, paperPlaneRight, paperPlaneTilt, parachute, paragraph, parallelogram, park, password, path, patreonLogo, pause, pauseCircle, pawPrint, paypalLogo, peace, pen, pencil, pencilCircle, pencilLine, pencilRuler, pencilSimple, pencilSimpleLine, pencilSimpleSlash, pencilSlash, penNib, penNibStraight, pentagon, pentagram, pepper, percent, person, personArmsSpread, personSimple, personSimpleBike, personSimpleCircle, personSimpleHike, personSimpleRun, personSimpleSki, personSimpleSnowboard, personSimpleSwim, personSimpleTaiChi, personSimpleThrow, personSimpleWalk, perspective, phone, phoneCall, phoneDisconnect, phoneIncoming, phoneList, phoneOutgoing, phonePause, phonePlus, phoneSlash, phoneTransfer, phoneX, phosphorLogo, pi, pianoKeys, picnicTable, pictureInPicture, piggyBank, pill, pingPong, pinterestLogo, pintGlass, pinwheel, pipe, pipeWrench, pixLogo, pizza, placeholder, planet, plant, play, playCircle, playlist, playPause, plug, plugCharging, plugs, plugsConnected, plus, plusCircle, plusMinus, plusSquare, pokerChip, policeCar, polygon, popcorn, popsicle, pottedPlant, power, prescription, presentation, presentationChart, printer, prohibit, prohibitInset, projectorScreen, projectorScreenChart, pulse, pushPin, pushPinSimple, pushPinSimpleSlash, pushPinSlash, puzzlePiece, qrCode, question, questionMark, queue, quotes, rabbit, racquet, radical, radio, radioactive, radioButton, rainbow, rainbowCloud, ranking, readCvLogo, receipt, receiptX, record, rectangle, rectangleDashed, recycle, redditLogo, repeat, repeatOnce, replitLogo, resize, rewind, rewindCircle, roadHorizon, robot, rocket, rocketLaunch, rows, rowsPlusBottom, rowsPlusTop, rss, rssSimple, rug, ruler, sailboat, scales, scan, scanSmiley, scissors, scooter, screencast, screwdriver, scribble, scribbleLoop, scroll, seal, sealCheck, sealPercent, sealQuestion, sealWarning, seat, seatbelt, securityCamera, selection, selectionAll, selectionBackground, selectionForeground, selectionInverse, selectionPlus, selectionSlash, shapes, share, shareFat, shareNetwork, shield, shieldCheck, shieldCheckered, shieldChevron, shieldPlus, shieldSlash, shieldStar, shieldWarning, shippingContainer, shirtFolded, shootingStar, shoppingBag, shoppingBagOpen, shoppingCart, shoppingCartSimple, shovel, shower, shrimp, shuffle, shuffleAngular, shuffleSimple, sidebar, sidebarSimple, sigma, signature, signIn, signOut, signpost, simCard, siren, sketchLogo, skipBack, skipBackCircle, skipForward, skipForwardCircle, skull, skypeLogo, slackLogo, sliders, slidersHorizontal, slideshow, smiley, smileyAngry, smileyBlank, smileyMeh, smileyMelting, smileyNervous, smileySad, smileySticker, smileyWink, smileyXEyes, snapchatLogo, sneaker, sneakerMove, snowflake, soccerBall, sock, solarPanel, solarRoof, sortAscending, sortDescending, soundcloudLogo, spade, sparkle, speakerHifi, speakerHigh, speakerLow, speakerNone, speakerSimpleHigh, speakerSimpleLow, speakerSimpleNone, speakerSimpleSlash, speakerSimpleX, speakerSlash, speakerX, speedometer, sphere, spinner, spinnerBall, spinnerGap, spiral, splitHorizontal, splitVertical, spotifyLogo, sprayBottle, square, squareHalf, squareHalfBottom, squareLogo, squaresFour, squareSplitHorizontal, squareSplitVertical, stack, stackMinus, stackOverflowLogo, stackPlus, stackSimple, stairs, stamp, standardDefinition, star, starAndCrescent, starFour, starHalf, starOfDavid, steamLogo, steeringWheel, steps, stethoscope, sticker, stool, stop, stopCircle, storefront, strategy, stripeLogo, student, subsetOf, subsetProperOf, subtitles, subtitlesSlash, subtract, subtractSquare, subway, suitcase, suitcaseRolling, suitcaseSimple, sun, sunDim, sunglasses, sunHorizon, supersetOf, supersetProperOf, swap, swatches, swimmingPool, sword, synagogue, syringe, table, tabs, tag, tagChevron, tagSimple, target, taxi, teaBag, telegramLogo, television, televisionSimple, tennisBall, tent, terminal, terminalWindow, testTube, textAa, textAlignCenter, textAlignJustify, textAlignLeft, textAlignRight, textAUnderline, textB, textbox, textColumns, textH, textHFive, textHFour, textHOne, textHSix, textHThree, textHTwo, textIndent, textItalic, textOutdent, textStrikethrough, textSubscript, textSuperscript, textT, textTSlash, textUnderline, thermometer, thermometerCold, thermometerHot, thermometerSimple, threadsLogo, threeD, thumbsDown, thumbsUp, ticket, tidalLogo, tiktokLogo, tilde, timer, tipi, tipJar, tire, toggleLeft, toggleRight, toilet, toiletPaper, toolbox, tooth, tornado, tote, toteSimple, towel, tractor, trademark, trademarkRegistered, trafficCone, trafficSign, trafficSignal, train, trainRegional, trainSimple, tram, translate, trash, trashSimple, tray, trayArrowDown, trayArrowUp, treasureChest, tree, treeEvergreen, treePalm, treeStructure, treeView, trendDown, trendUp, triangle, triangleDashed, trolley, trolleySuitcase, trophy, truck, truckTrailer, tShirt, tumblrLogo, twitchLogo, twitterLogo, umbrella, umbrellaSimple, union, unite, uniteSquare, upload, uploadSimple, usb, user, userCheck, userCircle, userCircleCheck, userCircleDashed, userCircleGear, userCircleMinus, userCirclePlus, userFocus, userGear, userList, userMinus, userPlus, userRectangle, users, usersFour, userSound, userSquare, usersThree, userSwitch, van, vault, vectorThree, vectorTwo, vibrate, video, videoCamera, videoCameraSlash, videoConference, vignette, vinylRecord, virtualReality, virus, visor, voicemail, volleyball, wall, wallet, warehouse, warning, warningCircle, warningDiamond, warningOctagon, washingMachine, watch, waveform, waveformSlash, waves, waveSawtooth, waveSine, waveSquare, waveTriangle, webcam, webcamSlash, webhooksLogo, wechatLogo, whatsappLogo, wheelchair, wheelchairMotion, wifiHigh, wifiLow, wifiMedium, wifiNone, wifiSlash, wifiX, wind, windmill, windowsLogo, wine, wrench, x, xCircle, xLogo, xSquare, yarn, yinYang, youtubeLogo\n\n\n## Usage \nImport icons with the following pattern \"import { iconNameIcon, iconName[Variant]Icon } from \"entasis/icons/iconName\"\nThen use them as svelte 5 snippets. \nThey can receive the following props : \n```ts\ntype IconProps = {\n\tsize: number | string;\n\tmirrored?: boolean;\n\tcolor?: Colors | string; // primary, secondary, danger, success, warning, info, neutral, or a hex color\n} & SVGAttributes<SVGSVGElement>;\n```\n\n```svelte\n<script> \n import { houseIcon } from \"entasis/icons/house\";\n</script>\n {@render houseIcon({ size: 24, color: 'primary' })}\n```\n\n### Passing Icons to Components with Default Props\n\nWhen passing icons to components that accept snippet props (like `prefix` or `suffix`), you can use the `withProps` method to set default props. This avoids writing snippet markup.\n\n**Using `withProps` (Recommended):**\n```svelte\n<script>\n import { eyeClosedIcon } from \"entasis/icons/eyeClosed\";\n import { Button } from \"entasis/button\";\n</script>\n\n<Button prefix={eyeClosedIcon.withProps({ color: \"danger\" })}>\n Click me\n</Button>\n```\n\n**Without `withProps` (Verbose):**\n```svelte\n<script>\n import { eyeClosedIcon } from \"entasis/icons/eyeClosed\";\n import { Button } from \"entasis/button\";\n</script>\n\n<Button>\n {#snippet prefix()}\n {@render eyeClosedIcon({ color: \"danger\" })}\n {/snippet}\n Click me\n</Button>\n```\n\nThe `withProps` method creates a new snippet with default props, making it cleaner and more concise when passing icons to components.\n\n## Customization\n\nIcons inherit the current text color and can be styled with CSS\nIcons by default have a size of 1lh so their size is consistent with other stuff on the same line.\nIt is therefore not mandatory to use either the size or the color props unless in case of a very specific use case.\n\n## Best Practices\n1. **Consistent Sizing**: Use consistent icon sizes within the same interface\n2. **Semantic Usage**: Choose icons that clearly represent their function\n4. **Performance**: Import only the icons you need to reduce bundle size\n5. **Variants**: Use appropriate variants for visual hierarchy and emphasis\n";
139
139
  readonly 'spinner-overlay': "\n# Spinner overlay\n\nImport from `entasis/spinner-overlay`.\n\nspinnerOverlay creates a Svelte attachment that displays a loading indicator over its element. SpinnerOverlayOptions configures loading, text, class, semantic color, semantic size, and spinner variant. setSpinnerOverlayTheme and useSpinnerOverlayTheme customize the overlay, indicator, and text parts. The attachment reads the nearest Theme context for the default spinner variant.\n";
@@ -462,7 +462,13 @@ export const generateColorPalette = (opts) => {
462
462
  const baseColor = opts.neutral
463
463
  ? adjustColor(color.DEFAULT)
464
464
  : setPerceptualLightness(surface.DEFAULT, isDark ? 0.96 : 0.22);
465
- const muted = color.muted || mutedOn(baseColor, baseSurface);
465
+ // `neutral-muted` is the kit's edge colour (rings, borders, `--raised-border`), so it must
466
+ // clear the lightest surface it can sit on. In light mode the surfaces climb toward white
467
+ // while the tint drops below the base, so the base is the right anchor. In dark mode both
468
+ // climb: a tint 0.06 above the base lands exactly on `surface-floating` (0.24) and 0.04
469
+ // above `surface-raised`, which is why a card's ring and a popover's edge vanished. Anchor
470
+ // it on the floating surface instead, so the step is measured from the top of the stack.
471
+ const muted = color.muted || mutedOn(baseColor, isDark ? surfacePalette.floating : baseSurface);
466
472
  return {
467
473
  DEFAULT: baseColor,
468
474
  dark: color.dark || darken(baseColor, 2),