@sovereignfs/ui 0.54.0 → 0.83.1

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 (277) hide show
  1. package/dist/Accordion.module.css +1 -1
  2. package/dist/Alert.module.css +1 -1
  3. package/dist/AppsLauncher.module.css +96 -0
  4. package/dist/Avatar.module.css +1 -1
  5. package/dist/Badge.module.css +30 -7
  6. package/dist/BalanceChip.module.css +1 -1
  7. package/dist/Button.module.css +18 -2
  8. package/dist/Card.module.css +1 -1
  9. package/dist/CardTile.module.css +181 -0
  10. package/dist/CodeTextarea.module.css +1 -1
  11. package/dist/Collapsible.module.css +1 -1
  12. package/dist/ColorPicker.module.css +132 -0
  13. package/dist/Combobox.module.css +2 -2
  14. package/dist/Command.module.css +1 -1
  15. package/dist/ConfirmDialog.module.css +2 -2
  16. package/dist/ConsentPrompt.module.css +21 -0
  17. package/dist/DatePicker.module.css +1 -1
  18. package/dist/Dialog.module.css +130 -21
  19. package/dist/Drawer.module.css +36 -7
  20. package/dist/Header.module.css +62 -0
  21. package/dist/HeaderFooterLayout.module.css +21 -0
  22. package/dist/IconPicker.module.css +1 -1
  23. package/dist/Input.module.css +1 -1
  24. package/dist/Kbd.module.css +1 -1
  25. package/dist/Markdown.module.css +24 -0
  26. package/dist/Menu.module.css +1 -0
  27. package/dist/Message.module.css +1 -1
  28. package/dist/MessageScroller.module.css +12 -1
  29. package/dist/MobileAppsDrawer.module.css +10 -9
  30. package/dist/MobileFooter.module.css +1 -1
  31. package/dist/MobileHeader.module.css +14 -1
  32. package/dist/NavList.module.css +130 -0
  33. package/dist/NavTabs.module.css +1 -1
  34. package/dist/NotificationsPanel.module.css +258 -0
  35. package/dist/OverlayHeader.module.css +1 -1
  36. package/dist/PageContainer.module.css +62 -0
  37. package/dist/PageHeader.module.css +54 -0
  38. package/dist/PageLayout.module.css +51 -0
  39. package/dist/Popover.module.css +1 -1
  40. package/dist/QuantityStepper.module.css +1 -1
  41. package/dist/Resizable.module.css +3 -3
  42. package/dist/RootLayout.module.css +12 -0
  43. package/dist/SegmentedControl.module.css +1 -1
  44. package/dist/Select.module.css +1 -1
  45. package/dist/Sheet.module.css +4 -1
  46. package/dist/SplitPane.module.css +4 -4
  47. package/dist/StatusBadge.module.css +1 -1
  48. package/dist/StepStrip.module.css +53 -0
  49. package/dist/SuggestionInput.module.css +2 -2
  50. package/dist/SwipableMobileCarousel.module.css +12 -3
  51. package/dist/SwipableMobileCarouselDots.module.css +15 -0
  52. package/dist/SwipeStack.module.css +101 -0
  53. package/dist/SystemBanner.module.css +10 -0
  54. package/dist/Table.module.css +2 -2
  55. package/dist/Tabs.module.css +1 -1
  56. package/dist/TagInput.module.css +2 -2
  57. package/dist/Textarea.module.css +9 -1
  58. package/dist/ThreeColumnLayout.module.css +35 -0
  59. package/dist/Toast.module.css +62 -3
  60. package/dist/Tooltip.module.css +1 -1
  61. package/dist/UserMenu.module.css +90 -0
  62. package/dist/index.d.ts +1047 -45
  63. package/dist/index.js +3908 -1456
  64. package/dist/tokens/primitives.css +11 -0
  65. package/dist/tokens/semantic.css +32 -0
  66. package/dist/tokens/theme-presets.css +33 -0
  67. package/package.json +25 -9
  68. package/src/__tests__/package-json.test.ts +8 -0
  69. package/src/components/Accordion/Accordion.module.css +1 -1
  70. package/src/components/Alert/Alert.module.css +1 -1
  71. package/src/components/AppsLauncher/AppsLauncher.module.css +96 -0
  72. package/src/components/AppsLauncher/AppsLauncher.stories.tsx +58 -0
  73. package/src/components/AppsLauncher/AppsLauncher.tsx +117 -0
  74. package/src/components/AppsLauncher/__tests__/AppsLauncher.test.tsx +52 -0
  75. package/src/components/Avatar/Avatar.module.css +1 -1
  76. package/src/components/Badge/Badge.module.css +30 -7
  77. package/src/components/Badge/Badge.stories.tsx +16 -4
  78. package/src/components/Badge/Badge.tsx +7 -4
  79. package/src/components/Badge/__tests__/Badge.test.tsx +4 -2
  80. package/src/components/BalanceChip/BalanceChip.module.css +1 -1
  81. package/src/components/Button/Button.module.css +18 -2
  82. package/src/components/Card/Card.module.css +1 -1
  83. package/src/components/CardTile/CardTile.module.css +181 -0
  84. package/src/components/CardTile/CardTile.stories.tsx +86 -0
  85. package/src/components/CardTile/CardTile.tsx +128 -0
  86. package/src/components/CardTile/__tests__/CardTile.test.tsx +56 -0
  87. package/src/components/CodeTextarea/CodeTextarea.module.css +1 -1
  88. package/src/components/Collapsible/Collapsible.module.css +1 -1
  89. package/src/components/ColorPicker/ColorPicker.module.css +132 -0
  90. package/src/components/ColorPicker/ColorPicker.stories.tsx +80 -0
  91. package/src/components/ColorPicker/ColorPicker.tsx +157 -0
  92. package/src/components/ColorPicker/__tests__/ColorPicker.test.tsx +117 -0
  93. package/src/components/Combobox/Combobox.module.css +2 -2
  94. package/src/components/Command/Command.module.css +1 -1
  95. package/src/components/ConfirmDialog/ConfirmDialog.module.css +2 -2
  96. package/src/components/ConfirmDialog/ConfirmDialog.tsx +28 -2
  97. package/src/components/ConfirmDialog/__tests__/ConfirmDialog.test.tsx +71 -3
  98. package/src/components/ConsentPrompt/ConsentPrompt.module.css +21 -0
  99. package/src/components/ConsentPrompt/ConsentPrompt.stories.tsx +31 -0
  100. package/src/components/ConsentPrompt/ConsentPrompt.tsx +66 -0
  101. package/src/components/ContextMenu/ContextMenu.tsx +1 -1
  102. package/src/components/DatePicker/DatePicker.module.css +1 -1
  103. package/src/components/Dialog/Dialog.module.css +130 -21
  104. package/src/components/Dialog/Dialog.stories.tsx +179 -2
  105. package/src/components/Dialog/Dialog.tsx +129 -35
  106. package/src/components/Dialog/__tests__/Dialog.test.tsx +190 -9
  107. package/src/components/DragHandleRow/DragHandleRow.tsx +2 -21
  108. package/src/components/Drawer/Drawer.module.css +36 -7
  109. package/src/components/Drawer/Drawer.tsx +9 -10
  110. package/src/components/Drawer/__tests__/Drawer.test.tsx +33 -6
  111. package/src/components/GripIcon/GripIcon.tsx +27 -0
  112. package/src/components/Header/Header.module.css +62 -0
  113. package/src/components/Header/Header.stories.tsx +452 -0
  114. package/src/components/Header/Header.tsx +102 -0
  115. package/src/components/Header/__tests__/Header.test.tsx +104 -0
  116. package/src/components/HeaderFooterLayout/HeaderFooterLayout.module.css +21 -0
  117. package/src/components/HeaderFooterLayout/HeaderFooterLayout.stories.tsx +111 -0
  118. package/src/components/HeaderFooterLayout/HeaderFooterLayout.tsx +54 -0
  119. package/src/components/HeaderFooterLayout/__tests__/HeaderFooterLayout.test.tsx +58 -0
  120. package/src/components/Icon/icons/arrow-left-right.tsx +23 -0
  121. package/src/components/Icon/icons/bold.tsx +20 -0
  122. package/src/components/Icon/icons/calendar.tsx +4 -4
  123. package/src/components/Icon/icons/carrot.tsx +3 -3
  124. package/src/components/Icon/icons/circle-chevron-left.tsx +21 -0
  125. package/src/components/Icon/icons/code.tsx +21 -0
  126. package/src/components/Icon/icons/copy.tsx +21 -0
  127. package/src/components/Icon/icons/credit-card.tsx +21 -0
  128. package/src/components/Icon/icons/database.tsx +22 -0
  129. package/src/components/Icon/icons/download.tsx +22 -0
  130. package/src/components/Icon/icons/file-text.tsx +24 -0
  131. package/src/components/Icon/icons/folder-closed.tsx +21 -0
  132. package/src/components/Icon/icons/folder-open.tsx +20 -0
  133. package/src/components/Icon/icons/folder.tsx +20 -0
  134. package/src/components/Icon/icons/folders.tsx +21 -0
  135. package/src/components/Icon/icons/hat-glasses.tsx +24 -0
  136. package/src/components/Icon/icons/history.tsx +22 -0
  137. package/src/components/Icon/icons/inbox.tsx +21 -0
  138. package/src/components/Icon/icons/index.ts +161 -1
  139. package/src/components/Icon/icons/italic.tsx +22 -0
  140. package/src/components/Icon/icons/layers.tsx +22 -0
  141. package/src/components/Icon/icons/layout-dashboard.tsx +23 -0
  142. package/src/components/Icon/icons/layout-grid.tsx +23 -0
  143. package/src/components/Icon/icons/link.tsx +21 -0
  144. package/src/components/Icon/icons/list-ordered.tsx +25 -0
  145. package/src/components/Icon/icons/list.tsx +25 -0
  146. package/src/components/Icon/icons/luggage.tsx +24 -0
  147. package/src/components/Icon/icons/map-pin.tsx +21 -0
  148. package/src/components/Icon/icons/minus.tsx +20 -0
  149. package/src/components/Icon/icons/paint-bucket.tsx +23 -0
  150. package/src/components/Icon/icons/panel-left.tsx +21 -0
  151. package/src/components/Icon/icons/pin.tsx +21 -0
  152. package/src/components/Icon/icons/rectangle-ellipsis.tsx +23 -0
  153. package/src/components/Icon/icons/refresh-cw.tsx +23 -0
  154. package/src/components/Icon/icons/rotate-cw.tsx +21 -0
  155. package/src/components/Icon/icons/route.tsx +22 -0
  156. package/src/components/Icon/icons/send.tsx +21 -0
  157. package/src/components/Icon/icons/share-2.tsx +24 -0
  158. package/src/components/Icon/icons/sheet.tsx +24 -0
  159. package/src/components/Icon/icons/square-kanban.tsx +23 -0
  160. package/src/components/Icon/icons/table.tsx +23 -0
  161. package/src/components/Icon/icons/user-round-plus.tsx +23 -0
  162. package/src/components/Icon/icons/users.tsx +23 -0
  163. package/src/components/IconPicker/IconPicker.module.css +1 -1
  164. package/src/components/Input/Input.module.css +1 -1
  165. package/src/components/Input/Input.tsx +8 -2
  166. package/src/components/Kbd/Kbd.module.css +1 -1
  167. package/src/components/Markdown/Markdown.module.css +24 -0
  168. package/src/components/Markdown/Markdown.stories.tsx +10 -0
  169. package/src/components/Markdown/Markdown.tsx +166 -29
  170. package/src/components/Markdown/__tests__/Markdown.test.tsx +144 -0
  171. package/src/components/Menu/Menu.module.css +1 -0
  172. package/src/components/Menu/Menu.tsx +72 -22
  173. package/src/components/Menu/__tests__/Menu.test.tsx +30 -0
  174. package/src/components/Menubar/Menubar.tsx +1 -1
  175. package/src/components/Message/Message.module.css +1 -1
  176. package/src/components/MessageScroller/MessageScroller.module.css +12 -1
  177. package/src/components/MessageScroller/MessageScroller.tsx +12 -0
  178. package/src/components/MobileAppsDrawer/MobileAppsDrawer.module.css +10 -9
  179. package/src/components/MobileFooter/MobileFooter.module.css +1 -1
  180. package/src/components/MobileFooter/MobileFooter.tsx +15 -2
  181. package/src/components/MobileFooter/__tests__/MobileFooter.test.tsx +58 -0
  182. package/src/components/MobileHeader/MobileHeader.module.css +14 -1
  183. package/src/components/MobileHeader/MobileHeader.tsx +15 -2
  184. package/src/components/MobileHeader/__tests__/MobileHeader.test.tsx +56 -1
  185. package/src/components/NavList/NavList.module.css +130 -0
  186. package/src/components/NavList/NavList.tsx +136 -0
  187. package/src/components/NavList/__tests__/NavList.test.tsx +109 -0
  188. package/src/components/NavTabs/NavTabs.module.css +1 -1
  189. package/src/components/NotificationsPanel/NotificationsPanel.module.css +258 -0
  190. package/src/components/NotificationsPanel/NotificationsPanel.stories.tsx +61 -0
  191. package/src/components/NotificationsPanel/NotificationsPanel.tsx +187 -0
  192. package/src/components/NotificationsPanel/__tests__/NotificationsPanel.test.tsx +78 -0
  193. package/src/components/OverlayHeader/OverlayHeader.module.css +1 -1
  194. package/src/components/OverlayHeader/OverlayHeader.tsx +19 -4
  195. package/src/components/OverlayHeader/__tests__/OverlayHeader.test.tsx +18 -0
  196. package/src/components/PageContainer/PageContainer.module.css +62 -0
  197. package/src/components/PageContainer/PageContainer.tsx +37 -4
  198. package/src/components/PageContainer/__tests__/PageContainer.test.tsx +41 -8
  199. package/src/components/PageHeader/PageHeader.module.css +54 -0
  200. package/src/components/PageHeader/PageHeader.tsx +146 -5
  201. package/src/components/PageHeader/__tests__/PageHeader.test.tsx +103 -0
  202. package/src/components/PageLayout/PageLayout.module.css +51 -0
  203. package/src/components/PageLayout/PageLayout.stories.tsx +73 -0
  204. package/src/components/PageLayout/PageLayout.tsx +51 -0
  205. package/src/components/PageLayout/__tests__/PageLayout.test.tsx +34 -0
  206. package/src/components/Popover/Popover.module.css +1 -1
  207. package/src/components/Popover/Popover.tsx +86 -4
  208. package/src/components/Popover/__tests__/Popover.test.tsx +165 -0
  209. package/src/components/QuantityStepper/QuantityStepper.module.css +1 -1
  210. package/src/components/Resizable/Resizable.module.css +3 -3
  211. package/src/components/RootLayout/RootLayout.module.css +12 -0
  212. package/src/components/RootLayout/RootLayout.stories.tsx +125 -0
  213. package/src/components/RootLayout/RootLayout.tsx +185 -0
  214. package/src/components/RootLayout/__tests__/RootLayout.test.tsx +161 -0
  215. package/src/components/SegmentedControl/SegmentedControl.module.css +1 -1
  216. package/src/components/Select/Select.module.css +1 -1
  217. package/src/components/Sheet/Sheet.module.css +4 -1
  218. package/src/components/Sheet/Sheet.tsx +5 -5
  219. package/src/components/SplitPane/SplitPane.module.css +4 -4
  220. package/src/components/StatusBadge/StatusBadge.module.css +1 -1
  221. package/src/components/StepStrip/StepStrip.module.css +53 -0
  222. package/src/components/StepStrip/StepStrip.tsx +74 -0
  223. package/src/components/SuggestionInput/SuggestionInput.module.css +2 -2
  224. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.module.css +12 -3
  225. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.tsx +25 -9
  226. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarousel.test.tsx +81 -0
  227. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.module.css +15 -0
  228. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.tsx +12 -1
  229. package/src/components/SwipeStack/SwipeStack.module.css +101 -0
  230. package/src/components/SwipeStack/SwipeStack.tsx +199 -0
  231. package/src/components/SwipeStack/SwipeStackCard.tsx +22 -0
  232. package/src/components/SwipeStack/__tests__/SwipeStack.test.tsx +169 -0
  233. package/src/components/SystemBanner/SystemBanner.module.css +10 -0
  234. package/src/components/Table/Table.module.css +2 -2
  235. package/src/components/Tabs/Tabs.module.css +1 -1
  236. package/src/components/TagInput/TagInput.module.css +2 -2
  237. package/src/components/Textarea/Textarea.module.css +9 -1
  238. package/src/components/Textarea/Textarea.tsx +28 -5
  239. package/src/components/Textarea/__tests__/Textarea.test.tsx +23 -1
  240. package/src/components/ThreeColumnLayout/ThreeColumnLayout.module.css +35 -0
  241. package/src/components/ThreeColumnLayout/ThreeColumnLayout.stories.tsx +152 -0
  242. package/src/components/ThreeColumnLayout/ThreeColumnLayout.tsx +87 -0
  243. package/src/components/ThreeColumnLayout/__tests__/ThreeColumnLayout.test.tsx +78 -0
  244. package/src/components/Toast/Toast.module.css +62 -3
  245. package/src/components/Toast/Toast.stories.tsx +1 -1
  246. package/src/components/Tooltip/Tooltip.module.css +1 -1
  247. package/src/components/UserMenu/UserMenu.module.css +90 -0
  248. package/src/components/UserMenu/UserMenu.stories.tsx +49 -0
  249. package/src/components/UserMenu/UserMenu.tsx +132 -0
  250. package/src/components/UserMenu/__tests__/UserMenu.test.tsx +77 -0
  251. package/src/hooks/__tests__/usePublishShellChromeHeight.test.tsx +118 -0
  252. package/src/hooks/__tests__/useReorderSensors.test.ts +26 -0
  253. package/src/hooks/__tests__/useSnapCarousel.test.tsx +82 -0
  254. package/src/hooks/__tests__/useSwipeStack.test.tsx +155 -0
  255. package/src/hooks/index.ts +9 -0
  256. package/src/hooks/usePublishShellChromeHeight.ts +96 -0
  257. package/src/hooks/useReorderSensors.ts +88 -0
  258. package/src/hooks/useSnapCarousel.ts +211 -6
  259. package/src/hooks/useSwipeStack.ts +235 -0
  260. package/src/index.ts +61 -1
  261. package/src/overlay-shell.ts +65 -0
  262. package/src/stories/DesignSystemOverview.stories.tsx +617 -11
  263. package/src/stories/GripIcon.stories.tsx +29 -0
  264. package/src/stories/LayoutSystem.stories.tsx +639 -0
  265. package/src/stories/MenuEntries.stories.tsx +86 -0
  266. package/src/stories/NavList.stories.tsx +147 -0
  267. package/src/stories/PageContainer.stories.tsx +52 -7
  268. package/src/stories/PageHeader.stories.tsx +54 -1
  269. package/src/stories/StepStrip.stories.tsx +76 -0
  270. package/src/stories/SwipableMobileCarousel.stories.tsx +58 -0
  271. package/src/stories/SwipeStack.stories.tsx +200 -0
  272. package/src/stories/Textarea.stories.tsx +12 -0
  273. package/src/stories/TokenGallery.stories.tsx +50 -0
  274. package/src/tokens/primitives.css +11 -0
  275. package/src/tokens/semantic.css +32 -0
  276. package/src/tokens/theme-presets.css +33 -0
  277. package/src/tokens/theme-presets.ts +72 -0
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as react from 'react';
2
- import { ReactNode, ButtonHTMLAttributes, SelectHTMLAttributes, ReactElement, CSSProperties, InputHTMLAttributes, TextareaHTMLAttributes, HTMLAttributes, TdHTMLAttributes, ThHTMLAttributes, LabelHTMLAttributes, ElementType, PointerEvent, KeyboardEvent, MouseEvent, RefObject } from 'react';
2
+ import { ReactNode, ButtonHTMLAttributes, SelectHTMLAttributes, ReactElement, CSSProperties, InputHTMLAttributes, Ref, TextareaHTMLAttributes, HTMLAttributes, TdHTMLAttributes, ThHTMLAttributes, LabelHTMLAttributes, ElementType, PointerEvent, KeyboardEvent, MouseEvent, RefObject } from 'react';
3
+ import * as _dnd_kit_core from '@dnd-kit/core';
3
4
 
4
5
  interface LegalLinksProps {
5
6
  privacyHref?: string;
@@ -14,30 +15,82 @@ interface LegalLinksProps {
14
15
  }
15
16
  declare function LegalLinks({ privacyHref, tosHref, renderLink, className, }: LegalLinksProps): react.JSX.Element;
16
17
 
18
+ interface ConsentPromptProps {
19
+ /** The plugin requesting access. */
20
+ consumerName: string;
21
+ /** The plugin whose data would be read. */
22
+ providerName: string;
23
+ /** The named contract being requested (e.g. `"expenses"`). */
24
+ contract: string;
25
+ /**
26
+ * The provider's own manifest-declared explanation of what this contract
27
+ * exposes (`data.provides[].description`) — never caller-supplied at
28
+ * request time, so a consuming plugin can't write its own persuasive copy
29
+ * for what it's asking to read.
30
+ */
31
+ description?: string | null;
32
+ onAllow: () => void;
33
+ onDeny?: () => void;
34
+ allowLabel?: string;
35
+ denyLabel?: string;
36
+ /** Disables both buttons and shows a busy state on Allow while a request is in flight. */
37
+ pending?: boolean;
38
+ className?: string;
39
+ }
40
+ /**
41
+ * The consent screen shown before one plugin is allowed to read another
42
+ * plugin's data (RFC 0002 §4) — the step that was previously missing between
43
+ * a `ConsentRequiredError` and a grant actually being created. Presentational
44
+ * only: holds no state of its own, so it renders identically wherever it's
45
+ * used (currently Account → Data's pending-requests list).
46
+ */
47
+ declare function ConsentPrompt({ consumerName, providerName, contract, description, onAllow, onDeny, allowLabel, denyLabel, pending, className, }: ConsentPromptProps): react.JSX.Element;
48
+
17
49
  interface MarkdownProps {
18
- /** Raw markdown source. Supports the subset used by Sovereign's own
19
- * long-form content pages: headings (#/##/###), paragraphs, **bold**,
20
- * *italic*, `code`, [links](url), unordered lists (-), and blockquotes
21
- * (>), including soft-wrapped continuation lines within a paragraph or
22
- * list item. Not a general-purpose CommonMark parser — no tables,
23
- * images, ordered lists, or nested blocks. */
50
+ /** Raw markdown source. Supports: headings (#/##/###), paragraphs,
51
+ * **bold**, *italic*, `code`, [links](url), unordered lists (-), ordered
52
+ * lists (1. / 1)), fenced code blocks (```), and blockquotes (>),
53
+ * including soft-wrapped continuation lines within a paragraph or list
54
+ * item. Not a general-purpose CommonMark parser — no tables, images, or
55
+ * nested blocks. */
24
56
  content: string;
57
+ /** Renders every line within a paragraph on its own visual line (a
58
+ * `<br>` between them) instead of the default CommonMark-style soft-wrap
59
+ * (consecutive lines joined with a single space, requiring a blank line
60
+ * for a new paragraph). Off by default — the soft-wrap behavior is
61
+ * correct for this component's primary use (long-form, first-party
62
+ * content authored *as* markdown, where a hard line break is a
63
+ * deliberate `\` ` or blank-line choice). Turn this on when rendering
64
+ * plain, user-typed multi-line text that happens to be passed through
65
+ * this component (e.g. a card description or comment body edited in an
66
+ * ordinary `<textarea>`) — there, every Enter press is a real,
67
+ * intentional line break the user typed, and silently collapsing it
68
+ * into one run-on paragraph reads as broken, not as "markdown
69
+ * formatting applied." */
70
+ preserveLineBreaks?: boolean;
25
71
  className?: string;
26
72
  }
27
73
  /** Renders a constrained markdown subset (see MarkdownProps) as styled React
28
- * elements built from Typography — no HTML string injection. Meant for
29
- * long-form, first-party content pages (privacy policy, terms of service)
30
- * sourced from a single markdown file, not for rendering arbitrary or
31
- * user-supplied markdown. */
32
- declare function Markdown({ content, className }: MarkdownProps): react.JSX.Element;
74
+ * elements built from Typography — no HTML string injection. Primarily
75
+ * meant for long-form, first-party content pages (privacy policy, terms of
76
+ * service) sourced from a single markdown file — not a general-purpose
77
+ * CommonMark renderer for arbitrary markdown. Also fine for plain,
78
+ * user-typed multi-line text (a card description, a comment body) edited
79
+ * in an ordinary `<textarea>` and passed through unchanged, as long as
80
+ * `preserveLineBreaks` is set — see that prop's own doc comment for why it
81
+ * isn't the default. */
82
+ declare function Markdown({ content, preserveLineBreaks, className }: MarkdownProps): react.JSX.Element;
33
83
 
34
84
  type BadgeVariant = 'role' | 'status' | 'mono';
35
- type BadgeSize = 'sm' | 'md' | 'lg';
85
+ type BadgeSize = 'xs' | 'sm' | 'md' | 'lg';
36
86
  type BadgeStatus = 'active' | 'enabled' | 'deactivated' | 'failed' | 'invited' | 'pending' | 'neutral';
37
87
  interface BadgeProps {
38
88
  variant?: BadgeVariant;
39
- /** 'sm' | 'md' (default) | 'lg'. 'md' is the badge's original — and until
40
- * now, only — size, so the default renders unchanged. */
89
+ /** 'xs' | 'sm' | 'md' (default) | 'lg'. 'md' is the badge's original — and
90
+ * until now, only — size, so the default renders unchanged. 'xs' is the
91
+ * smallest tier (`--sv-font-size-2xs`, 10px) — for a badge sitting inline
92
+ * next to larger text (e.g. a status chip beside a card's headline value)
93
+ * where even 'sm' still reads oversized next to it. */
41
94
  size?: BadgeSize;
42
95
  /** Only relevant when variant="status" — determines the dot colour. */
43
96
  status?: BadgeStatus;
@@ -55,12 +108,12 @@ interface BadgeProps {
55
108
  * - `status` tinted chip with leading colour dot — for Active / Deactivated / etc.
56
109
  * - `mono` monospace font, neutral surface — for platform / community / v0.1.0
57
110
  *
58
- * Three sizes (`sm`/`md`/`lg`, default `md`). ALL CAPS by default
111
+ * Four sizes (`xs`/`sm`/`md`/`lg`, default `md`). ALL CAPS by default
59
112
  * (`uppercase`) — set `uppercase={false}` for a title-case badge instead.
60
113
  */
61
114
  declare function Badge({ variant, size, status, uppercase, children, }: BadgeProps): react.JSX.Element;
62
115
 
63
- type IconName = 'house' | 'settings' | 'log-out' | 'smartphone' | 'chevron-right' | 'chevron-left' | 'chevron-down' | 'chevron-up' | 'menu' | 'x' | 'check' | 'plus' | 'trash-2' | 'pencil' | 'rotate-ccw' | 'search' | 'user' | 'shield' | 'lock' | 'eye' | 'eye-off' | 'mail' | 'bell' | 'activity' | 'package' | 'grid-2x2' | 'info' | 'alert-triangle' | 'circle-check' | 'circle-x' | 'calendar' | 'sliders-horizontal' | 'ellipsis-vertical' | 'file' | 'upload' | 'external-link' | 'banana' | 'apple' | 'carrot' | 'egg' | 'beef' | 'fish' | 'coffee' | 'wine' | 'beer' | 'cookie' | 'pizza' | 'candy' | 'salad' | 'milk' | 'drumstick' | 'croissant' | 'cup-soda' | 'spray-can' | 'snowflake' | 'shopping-basket';
116
+ type IconName = 'house' | 'settings' | 'log-out' | 'smartphone' | 'chevron-right' | 'chevron-left' | 'chevron-down' | 'chevron-up' | 'circle-chevron-left' | 'menu' | 'x' | 'check' | 'plus' | 'trash-2' | 'pencil' | 'rotate-ccw' | 'search' | 'copy' | 'user' | 'users' | 'user-round-plus' | 'shield' | 'lock' | 'eye' | 'eye-off' | 'hat-glasses' | 'mail' | 'bell' | 'inbox' | 'activity' | 'package' | 'database' | 'layers' | 'grid-2x2' | 'layout-dashboard' | 'layout-grid' | 'square-kanban' | 'info' | 'alert-triangle' | 'circle-check' | 'circle-x' | 'calendar' | 'sliders-horizontal' | 'ellipsis-vertical' | 'rectangle-ellipsis' | 'file' | 'folder' | 'upload' | 'download' | 'external-link' | 'arrow-left-right' | 'send' | 'list' | 'list-ordered' | 'link' | 'code' | 'rotate-cw' | 'refresh-cw' | 'history' | 'minus' | 'table' | 'sheet' | 'folders' | 'folder-closed' | 'file-text' | 'folder-open' | 'share-2' | 'luggage' | 'map-pin' | 'route' | 'bold' | 'italic' | 'paint-bucket' | 'banana' | 'apple' | 'carrot' | 'egg' | 'beef' | 'fish' | 'coffee' | 'wine' | 'beer' | 'cookie' | 'pizza' | 'candy' | 'salad' | 'milk' | 'drumstick' | 'croissant' | 'cup-soda' | 'spray-can' | 'snowflake' | 'shopping-basket' | 'panel-left' | 'pin' | 'credit-card';
64
117
 
65
118
  /** Decorative icon — visually meaningful but described by surrounding text. */
66
119
  type DecorativeProps = {
@@ -207,6 +260,17 @@ interface PopoverProps {
207
260
  * regardless of CSS module load order, unlike passing an extra className.
208
261
  */
209
262
  panelStyle?: CSSProperties;
263
+ /**
264
+ * Class applied to the popover's own wrapper around `trigger` — the
265
+ * element that participates in the caller's layout.
266
+ *
267
+ * Mostly needed for flex sizing: the wrapper is an `inline-flex` box with
268
+ * the default `min-width: auto`, which pins it to the trigger's content
269
+ * width. Inside a flex row that has to shrink, that stops a truncatable
270
+ * trigger from ever giving up space, and pushes its siblings out of the
271
+ * container instead. Pass a class setting `min-width: 0` there.
272
+ */
273
+ className?: string;
210
274
  'aria-label': string;
211
275
  children: ReactNode;
212
276
  }
@@ -233,7 +297,7 @@ interface PopoverProps {
233
297
  *
234
298
  * Closes on outside click or Escape. Does not trap focus (it is non-modal).
235
299
  */
236
- declare function Popover({ trigger, open, onClose, align, width, panelStyle, 'aria-label': ariaLabel, children, }: PopoverProps): react.JSX.Element;
300
+ declare function Popover({ trigger, open, onClose, align, width, panelStyle, className, 'aria-label': ariaLabel, children, }: PopoverProps): react.JSX.Element;
237
301
 
238
302
  type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'destructive';
239
303
  type ButtonSize = 'sm' | 'md' | 'lg';
@@ -252,7 +316,13 @@ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
252
316
  */
253
317
  declare function Button({ variant, size, type, loading, disabled, className, children, ...rest }: ButtonProps): react.JSX.Element;
254
318
 
255
- type InputProps = InputHTMLAttributes<HTMLInputElement>;
319
+ type InputProps = InputHTMLAttributes<HTMLInputElement> & {
320
+ /** React 19 ref-as-prop — no `forwardRef` needed. Not part of
321
+ * `InputHTMLAttributes` (refs aren't a DOM attribute), so it's added
322
+ * explicitly here; left out of the destructure below so it flows through
323
+ * `...rest` straight onto the underlying `<input>`. */
324
+ ref?: Ref<HTMLInputElement>;
325
+ };
256
326
  /**
257
327
  * Input — the primitive text field. Presentational and RSC-safe: it forwards
258
328
  * all native input props to the underlying `<input>`. Styling references
@@ -260,14 +330,23 @@ type InputProps = InputHTMLAttributes<HTMLInputElement>;
260
330
  */
261
331
  declare function Input({ type, className, ...rest }: InputProps): react.JSX.Element;
262
332
 
263
- type TextareaProps = TextareaHTMLAttributes<HTMLTextAreaElement>;
333
+ interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
334
+ /** Grows the field's own height to fit its content as it's typed, instead
335
+ * of scrolling internally or leaving the user to drag-resize — e.g. an
336
+ * editable title that should read as a heading, not a fixed-size form
337
+ * field. Disables manual resize (`resize: none`) since a height driven by
338
+ * content and a user-draggable height would fight each other. `rows` is
339
+ * still honoured as the starting/minimum height. */
340
+ autoGrow?: boolean;
341
+ }
264
342
  /**
265
343
  * Textarea — the primitive multi-line text field. Presentational and
266
- * RSC-safe: it forwards all native textarea props to the underlying
344
+ * RSC-safe unless `autoGrow` is used (client-only, needs a layout
345
+ * measurement). Forwards all native textarea props to the underlying
267
346
  * `<textarea>`. Styling references `--sv-*` tokens via CSS Modules; there
268
347
  * are no hardcoded values.
269
348
  */
270
- declare function Textarea({ className, rows, ...rest }: TextareaProps): react.JSX.Element;
349
+ declare function Textarea({ className, rows, autoGrow, ...rest }: TextareaProps): react.JSX.Element;
271
350
 
272
351
  interface CodeTextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
273
352
  invalid?: boolean;
@@ -338,11 +417,13 @@ declare function TagInput({ value, onChange, id, name, placeholder, disabled, re
338
417
  /**
339
418
  * Lets content deep inside a `Dialog` (e.g. a plugin's own route layout,
340
419
  * rendered several levels below wherever the `Dialog` itself is
341
- * instantiated) supply the second-row content of the Dialog's mobile
342
- * `OverlayHeader` — typically a tab strip. Solves the "double header"
343
- * problem: without this, a plugin's own tab strip has no way to reach the
344
- * Dialog's header and ends up rendered a second time, as its own sticky bar,
345
- * inside the scrolling content area.
420
+ * instantiated) supply the second-row content of the Dialog's `OverlayHeader`
421
+ * — typically a tab strip. Solves the "double header" problem: without this,
422
+ * a plugin's own tab strip has no way to reach the Dialog's header and ends
423
+ * up rendered a second time, as its own sticky bar, inside the scrolling
424
+ * content area. Reaches the header regardless of whether it's showing via
425
+ * the `header` prop (both breakpoints) or the default `title`-driven mobile
426
+ * bar (mobile only) — see `DialogProps.header`'s own doc comment.
346
427
  *
347
428
  * A no-op when there is no enclosing `Dialog` (e.g. the same plugin layout
348
429
  * also rendered on a plain, non-overlay route) — safe to call unconditionally.
@@ -359,7 +440,7 @@ declare function TagInput({ value, onChange, id, name, placeholder, disabled, re
359
440
  * ```
360
441
  */
361
442
  declare function useOverlaySecondRow(node: ReactNode | null): boolean;
362
- type DialogSize = 'sm' | 'md' | 'lg' | 'full';
443
+ type DialogSize = 'sm' | 'md' | 'lg' | 'auto' | 'fixed';
363
444
  interface DialogProps {
364
445
  /** Whether the dialog is shown. When false, nothing renders. */
365
446
  open: boolean;
@@ -367,11 +448,42 @@ interface DialogProps {
367
448
  onClose: () => void;
368
449
  /** Panel size on desktop. Mobile always renders as a full-screen sheet. */
369
450
  size?: DialogSize;
370
- /** Accessible name for the dialog (sets `aria-label` on the panel). */
451
+ /** Accessible name for the dialog (sets `aria-label` on the panel). Falls
452
+ * back to `title` when omitted — this still applies even when `header` is
453
+ * used instead of `title` for the visible header (see `header`'s own doc
454
+ * comment), so pass `aria-label` explicitly in that case if `title` is
455
+ * also omitted. */
371
456
  'aria-label'?: string;
372
- /** On mobile: shown in the top bar alongside the close button so the title
373
- * and dismiss affordance occupy the same row instead of stacking. */
457
+ /** Shown in the top bar alongside the close button, on mobile only —
458
+ * desktop has no header row by default (see `header` for that). Ignored
459
+ * as visible content when `header` is provided; still used as the
460
+ * `aria-label` fallback either way. */
374
461
  title?: string;
462
+ /** Renders a persistent header row (via the same `OverlayHeader` component
463
+ * `title` alone only shows on mobile) on **both** desktop and mobile —
464
+ * the "Header + Body" / "Header + Body + Footer" shapes. Supersedes
465
+ * `title` for visible content when provided; `title` remains the
466
+ * `aria-label` fallback if `aria-label` is also omitted. Omitting both
467
+ * `header` and `footer` is "Body only" — today's default, unchanged. */
468
+ header?: ReactNode;
469
+ /** Renders a persistent footer row below the scrollable body — pinned on
470
+ * both desktop and mobile the same way `header`/the mobile title bar are
471
+ * (a non-scrolling flex sibling, not `position: sticky`): only the region
472
+ * between header and footer scrolls. Typically action buttons (Save/
473
+ * Cancel). Omit for no footer — today's default, where any actions live
474
+ * inside `children` and scroll with the rest of the body. Layout-agnostic
475
+ * (no built-in button alignment) — arrange the footer's own content as
476
+ * needed, same as `children`. */
477
+ footer?: ReactNode;
478
+ /** Forwarded to the active `OverlayHeader` instance's own `rowClassName`
479
+ * (whichever is showing — `header` or the mobile `title` bar) — restyle
480
+ * the title row (e.g. tighter padding to match a consumer's own compact
481
+ * header elsewhere) without changing its title/close layout. */
482
+ rowClassName?: string;
483
+ /** Forwarded to the active `OverlayHeader` instance's own `titleClassName`
484
+ * — restyle the title text (e.g. a smaller font size to match a
485
+ * consumer's own compact header elsewhere). */
486
+ titleClassName?: string;
375
487
  children: ReactNode;
376
488
  }
377
489
  /**
@@ -389,8 +501,14 @@ interface DialogProps {
389
501
  * `onClose` API is unchanged — closing still stays mounted internally for the
390
502
  * exit transition before actually unmounting; `prefers-reduced-motion: reduce`
391
503
  * collapses both to near-instant.
504
+ *
505
+ * Three composition shapes, chosen by which of `header`/`footer` are passed:
506
+ * Body only (both omitted — today's default), Header + Body (`header` only),
507
+ * Header + Body + Footer (`header` and `footer`). Whichever of header/footer
508
+ * are present render as non-scrolling flex siblings around `.content`, which
509
+ * stays the only scrollable region in every shape.
392
510
  */
393
- declare function Dialog({ open, onClose, size, 'aria-label': ariaLabel, title, children, }: DialogProps): react.JSX.Element | null;
511
+ declare function Dialog({ open, onClose, size, 'aria-label': ariaLabel, title, header, footer, rowClassName, titleClassName, children, }: DialogProps): react.JSX.Element | null;
394
512
 
395
513
  interface DrawerProps {
396
514
  /** Whether the drawer is shown. When false, nothing renders. */
@@ -439,8 +557,12 @@ declare function Drawer({ open, onClose, 'aria-label': ariaLabel, snapHeight, ti
439
557
  interface OverlayHeaderProps {
440
558
  /** Overlay title, shown between the optional back button and the trailing
441
559
  * slots. Optional — some consumers (e.g. `Dialog`'s mobile bar) need the
442
- * row's close button present even when no title applies. */
443
- title?: string;
560
+ * row's close button present even when no title applies. Accepts any
561
+ * `ReactNode`, not just a string — e.g. `Dialog`'s `header` prop passes
562
+ * arbitrary content through here (an icon next to text, etc.); the
563
+ * row's title slot still assumes single-line content sized like text
564
+ * (see the component's own doc comment for the line this doesn't cross). */
565
+ title?: ReactNode;
444
566
  /** Always renders a close button; called on click. */
445
567
  onClose: () => void;
446
568
  /** When provided, renders a back-chevron button before the title (for
@@ -452,6 +574,15 @@ interface OverlayHeaderProps {
452
574
  /** A second row below the title row — e.g. a tab strip. */
453
575
  secondRow?: ReactNode;
454
576
  className?: string;
577
+ /** Override the title row's own className (e.g. tighter padding to match
578
+ * a consumer's own compact header elsewhere in the same surface) — the
579
+ * row keeps its standard title/back/action/close layout, just restyled.
580
+ * For a genuinely different shape, don't use `OverlayHeader` at all (see
581
+ * this component's own doc comment). */
582
+ rowClassName?: string;
583
+ /** Override the title text's own className (e.g. a smaller font size to
584
+ * match a consumer's own compact header elsewhere in the same surface). */
585
+ titleClassName?: string;
455
586
  }
456
587
  /**
457
588
  * OverlayHeader — the shared fixed secondary header for `Dialog`'s mobile
@@ -467,7 +598,7 @@ interface OverlayHeaderProps {
467
598
  * component — render its own header row instead; `Sheet`'s `title` prop is
468
599
  * optional specifically to leave that escape hatch open.
469
600
  */
470
- declare function OverlayHeader({ title, onClose, onBack, action, secondRow, className, }: OverlayHeaderProps): react.JSX.Element;
601
+ declare function OverlayHeader({ title, onClose, onBack, action, secondRow, className, rowClassName, titleClassName, }: OverlayHeaderProps): react.JSX.Element;
471
602
 
472
603
  interface SheetProps {
473
604
  /** Whether the sheet is shown. When false, nothing renders. */
@@ -562,7 +693,16 @@ declare function ConfirmDialog({ open, onClose, title, message, onConfirm, confi
562
693
  interface MenuItem {
563
694
  type?: 'item';
564
695
  label: string;
565
- onSelect: () => void;
696
+ /** Optional when `href` is provided (a pure navigation entry needs no
697
+ * extra callback) — required otherwise. Called before the surface closes
698
+ * is the caller's job to avoid; `Menu`'s own wiring always closes first,
699
+ * then calls this. */
700
+ onSelect?: () => void;
701
+ /** Renders the entry as a link (`<a href>`, `role="menuitem"`) instead of
702
+ * a `<button>` — same href-vs-onClick convention as `MobileAppsDrawer`'s
703
+ * items. Framework-agnostic (a plain anchor, not `next/link`), matching
704
+ * every other `packages/ui` href slot. */
705
+ href?: string;
566
706
  icon?: IconName;
567
707
  /** Styles the item as a destructive action (e.g. "Delete list"). */
568
708
  destructive?: boolean;
@@ -598,6 +738,15 @@ interface MenuProps {
598
738
  /** Forwarded to `Popover` on desktop. Has no effect on mobile, where the
599
739
  * menu is always a full-width `Drawer`. */
600
740
  align?: 'left' | 'right';
741
+ /** Forwarded to `Popover` on desktop (same default: 288). Has no effect
742
+ * on mobile. Narrow this when the trigger lives inside a column
743
+ * narrower than the default width — e.g. a per-row "⋯" menu in a
744
+ * sidebar list — so the panel fits within that column's own bounds
745
+ * instead of overflowing past its edge, where a scrollable ancestor's
746
+ * `overflow-y: auto` (which the CSS Overflow spec computes the paired
747
+ * `overflow-x` to `auto` as well, not `visible`, once either axis is
748
+ * set) would clip it. */
749
+ width?: number | 'trigger';
601
750
  }
602
751
  /**
603
752
  * Menu — an adaptive action menu: `Popover` on desktop, a bottom-sheet
@@ -628,7 +777,148 @@ declare function MenuEntries({ items, onSelect, }: {
628
777
  /** Called after an item's own onSelect — typically the surface's onClose. */
629
778
  onSelect: (entry: MenuItem) => void;
630
779
  }): react.JSX.Element;
631
- declare function Menu({ trigger, open, onClose, items, 'aria-label': ariaLabel, align }: MenuProps): react.JSX.Element;
780
+ declare function Menu({ trigger, open, onClose, items, 'aria-label': ariaLabel, align, width, }: MenuProps): react.JSX.Element;
781
+
782
+ interface UserMenuItem {
783
+ label: string;
784
+ icon: IconName;
785
+ /** Optional when `href` is provided (a pure navigation entry needs no
786
+ * extra callback). Required otherwise (e.g. "Sign out"). */
787
+ onSelect?: () => void;
788
+ /** Renders the entry as a link (`<a href>`) instead of a button — same
789
+ * href-vs-onClick convention as `MobileAppsDrawer`'s items. */
790
+ href?: string;
791
+ destructive?: boolean;
792
+ }
793
+ interface UserMenuProps {
794
+ name?: string;
795
+ email?: string;
796
+ avatarUrl?: string;
797
+ items: UserMenuItem[];
798
+ /** Trigger button's accessible label. Defaults to "Account". */
799
+ 'aria-label'?: string;
800
+ align?: 'left' | 'right';
801
+ /** Trigger avatar size: `'md'` (36px) matches the platform sidebar's own
802
+ * `.avatar` exactly — the default, for that context. `'sm'` (32px) suits
803
+ * the more compact `Header` top-bar context instead. The panel's own
804
+ * user-info avatar (38px) is unaffected either way — only the trigger
805
+ * scales. */
806
+ size?: 'sm' | 'md';
807
+ }
808
+ /**
809
+ * UserMenu — the account avatar trigger + dropdown, generalized from the
810
+ * runtime shell's own `AccountMenu.tsx` (the real, currently-shipped
811
+ * component that every `shell: minimal` plugin would otherwise have to
812
+ * hand-rebuild locally instead of importing). Same visual structure and
813
+ * copy: an accent-filled avatar trigger (36px, matching the sidebar's own
814
+ * `.avatar`), a name+email header block (38px avatar) above a divider, then
815
+ * a plain item list.
816
+ *
817
+ * Presentational only — no auth/session/routing logic of its own. The
818
+ * consumer supplies `items`, each with its own `onSelect` and/or `href`,
819
+ * matching `MobileHeader`'s "consumer wires it up" boundary; a real
820
+ * "Sign out" is just an item whose `onSelect` does whatever the consuming
821
+ * app's sign-out actually requires. Built on the shared `Popover` primitive
822
+ * (self-contained open state, matching the original's own architecture)
823
+ * rather than a hand-rolled outside-click/Escape listener — the original
824
+ * `AccountMenu` and every plugin-local rebuild of it independently re-derive
825
+ * that same logic; one primitive here means one implementation to get
826
+ * right. Always a small anchored dropdown, never a full-width sheet —
827
+ * this is deliberately not built on the adaptive `Menu` component (which
828
+ * becomes a bottom `Drawer` on mobile): the real account menu is a compact
829
+ * floating panel on every surface, mobile included.
830
+ */
831
+ declare function UserMenu({ name, email, avatarUrl, items, 'aria-label': ariaLabel, align, size, }: UserMenuProps): react.JSX.Element;
832
+
833
+ interface AppsLauncherItem {
834
+ /** Stable identity for this tile — used as the React key. */
835
+ key: string;
836
+ icon: ReactNode;
837
+ label: string;
838
+ /** Renders an `<a>` when set; otherwise a `<button>` calling `onClick` —
839
+ * same dual-mode convention as `MobileAppsDrawer`'s items. */
840
+ href?: string;
841
+ onClick?: () => void;
842
+ }
843
+ interface AppsLauncherProps {
844
+ items: AppsLauncherItem[];
845
+ /** Shows a spinner in place of the grid — e.g. while the tile list is
846
+ * still being fetched. */
847
+ loading?: boolean;
848
+ /** Shows an error message in place of the grid. */
849
+ error?: boolean;
850
+ errorMessage?: string;
851
+ /** Trigger button's icon. Defaults to a generic grid glyph — pass the
852
+ * real Launcher plugin's own icon for pixel parity with the platform. */
853
+ triggerIcon?: ReactNode;
854
+ /** Trigger button's accessible label, and the popover's own. Defaults to "Apps". */
855
+ 'aria-label'?: string;
856
+ align?: 'left' | 'right';
857
+ }
858
+ /**
859
+ * AppsLauncher — the desktop "Apps" switcher: a 28px grid-icon trigger that
860
+ * opens a `Popover` with a 3-column tile grid. The desktop counterpart to
861
+ * `MobileAppsDrawer` — same `items` shape (`key`/`icon`/`label`/`href`/
862
+ * `onClick`), different chrome (floating panel vs. bottom sheet), matching
863
+ * how `Header`/`MobileHeader` already split the same way.
864
+ *
865
+ * Presentational only — no plugin-list fetching of its own. The consumer
866
+ * supplies `items` already resolved (and `loading`/`error` while it isn't
867
+ * yet), matching `MobileAppsDrawer`'s own boundary.
868
+ */
869
+ declare function AppsLauncher({ items, loading, error, errorMessage, triggerIcon, 'aria-label': ariaLabel, align, }: AppsLauncherProps): react.JSX.Element;
870
+
871
+ interface NotificationsPanelItem {
872
+ id: string;
873
+ /** Category icon, already resolved (sized + colored) by the consumer —
874
+ * this component doesn't own category → color mapping. */
875
+ icon: ReactNode;
876
+ title: string;
877
+ /** Pre-formatted relative time (e.g. "2d ago") — formatting stays
878
+ * consumer-side so this component needs no Date/clock dependency. */
879
+ timeLabel: string;
880
+ read: boolean;
881
+ /** Renders the title as a link when set. */
882
+ href?: string;
883
+ /** Called when the title is clicked/tapped — typically "mark as read". */
884
+ onOpen?: () => void;
885
+ onDismiss: () => void;
886
+ }
887
+ interface NotificationsPanelProps {
888
+ items: NotificationsPanelItem[];
889
+ unreadCount: number;
890
+ onMarkAllRead?: () => void;
891
+ onClearAll?: () => void;
892
+ emptyMessage?: string;
893
+ /** Trigger button's accessible label base — the unread count is appended
894
+ * automatically, matching the real NotificationBell. Defaults to
895
+ * "Notifications". */
896
+ 'aria-label'?: string;
897
+ align?: 'left' | 'right';
898
+ /** Optional footer link (e.g. to the consumer's own full notification
899
+ * list/detail view — RFC 0048) — mirrors the real `NotificationBell`'s
900
+ * "View all" link. Omit to render no footer, matching this component's
901
+ * behavior before this prop existed. */
902
+ viewAllHref?: string;
903
+ }
904
+ /**
905
+ * NotificationsPanel — the bell trigger + dropdown, generalized from the
906
+ * runtime shell's own `NotificationBell.tsx` visual structure and copy
907
+ * (title / Mark all read / Clear all / close, then a list of category-icon +
908
+ * title + time + unread-dot + dismiss rows, or an empty state).
909
+ *
910
+ * Deliberately **presentational only** — no fetch/SSE/polling, no
911
+ * category → color mapping, no mark-read/dismiss networking. The real
912
+ * `NotificationBell` owns real platform data (`/api/account/notifications`,
913
+ * a shared cross-instance store); this component can't and shouldn't know
914
+ * about that (SDK boundary). The consumer supplies `items` already resolved
915
+ * and wires `onOpen`/`onDismiss`/`onMarkAllRead`/`onClearAll` to whatever
916
+ * its own data layer needs, against a shared panel instead of a
917
+ * `shell: minimal` plugin hand-rebuilding one locally. Built on the shared
918
+ * `Popover` primitive (self-contained open state) rather than the
919
+ * original's hand-rolled outside-click/Escape listener.
920
+ */
921
+ declare function NotificationsPanel({ items, unreadCount, onMarkAllRead, onClearAll, emptyMessage, 'aria-label': ariaLabel, align, viewAllHref, }: NotificationsPanelProps): react.JSX.Element;
632
922
 
633
923
  interface ToastItem {
634
924
  id: string;
@@ -660,6 +950,64 @@ interface CardProps extends HTMLAttributes<HTMLElement> {
660
950
  }
661
951
  declare function Card({ as: Tag, interactive, padding, className, children, ...rest }: CardProps): react.JSX.Element;
662
952
 
953
+ interface CardTileGridProps {
954
+ children: ReactNode;
955
+ /** Minimum tile width (px) before the grid wraps to fewer columns. */
956
+ minTileWidth?: number;
957
+ className?: string;
958
+ /**
959
+ * Tight spacing with tiles that keep their natural width instead of
960
+ * stretching to fill the row — for small `variant="icon"` tiles (e.g. a
961
+ * folder grid), where the default grid's spacious gap and `1fr`-stretched
962
+ * columns leave a lot of empty space around a tile that's really just an
963
+ * icon + short label.
964
+ */
965
+ dense?: boolean;
966
+ }
967
+ /** Responsive grid of `CardTile`/`NewCardTile` children — `repeat(auto-fill, minmax(minTileWidth, 1fr))`, or `minmax(minTileWidth, max-content)` with a tighter gap when `dense`. */
968
+ declare function CardTileGrid({ children, minTileWidth, className, dense, }: CardTileGridProps): react.JSX.Element;
969
+ interface CardTileProps extends HTMLAttributes<HTMLDivElement> {
970
+ /** Content centered in the tile's full-bleed top banner — typically an `<Icon>`. Omit for a plain strip. */
971
+ banner?: ReactNode;
972
+ /** Banner background color (applied inline). Falls back to a neutral sunken-surface strip when omitted. Ignored by `variant="icon"`, which has no banner box. */
973
+ bannerColor?: string;
974
+ /** Tile footer content — typically the item's name. */
975
+ children: ReactNode;
976
+ /**
977
+ * `"card"` (default): a bordered card with a colored/iconed banner strip
978
+ * over a footer label. `"icon"`: a plain "Finder icon" tile — no card
979
+ * chrome at all, just a large centered icon with a label beneath it. Use
980
+ * `"icon"` for entities that read as a single glyph + name (e.g. a
981
+ * folder), where a bordered card reads as heavier than the content needs.
982
+ */
983
+ variant?: 'card' | 'icon';
984
+ }
985
+ /**
986
+ * A colored/iconed banner over a footer label — a card shape `Card` can't
987
+ * express, since `Card`'s `padding` prop always pads its single box with no
988
+ * way for a top region to bleed to the edges. Not link-aware: wrap it in the
989
+ * host framework's own link component (e.g. Next's `<Link>`) to make it
990
+ * navigable, same as every existing consumer of this pattern does.
991
+ */
992
+ declare function CardTile({ banner, bannerColor, children, className, variant, ...rest }: CardTileProps): react.JSX.Element;
993
+ interface NewCardTileProps extends ButtonHTMLAttributes<HTMLButtonElement> {
994
+ /** Icon shown beside the label (`"card"`) or alone (`"icon"`). Defaults to `"plus"`. */
995
+ icon?: IconName;
996
+ /** Visible next to the icon for `"card"`. For `"icon"`, not rendered as text — used as the button's `aria-label` instead, since the tile is icon-only. */
997
+ label: string;
998
+ /**
999
+ * `"card"` (default): a dashed box matching a `variant="card"` `CardTile`'s
1000
+ * footprint — icon beside a visible label. `"icon"`: matches a
1001
+ * `variant="icon"` `CardTile`'s footprint instead, but icon-only, no
1002
+ * visible label — a plain "+" reads as self-explanatory once every
1003
+ * sibling tile in the same `dense` grid is already an unlabeled icon
1004
+ * (the dashed border alone marks it as the "add new" affordance).
1005
+ */
1006
+ variant?: 'card' | 'icon';
1007
+ }
1008
+ /** Dashed ghost tile matching a real `CardTile`'s footprint — the grid's own "add new" affordance. */
1009
+ declare function NewCardTile({ icon, label, type, variant, className, ...rest }: NewCardTileProps): react.JSX.Element;
1010
+
663
1011
  /** Props to spread onto the field's actual form control. */
664
1012
  interface FormFieldRenderProps {
665
1013
  id: string;
@@ -690,23 +1038,127 @@ declare function FormField({ label, hint, error, id, required, className, childr
690
1038
  interface PageHeaderProps {
691
1039
  title: string;
692
1040
  description?: string;
1041
+ /** Optional icon rendered inline before the title text, on both breakpoints — e.g. `folder-open` next to a folder's name. */
1042
+ icon?: IconName;
1043
+ /**
1044
+ * Page-level controls — anywhere from one button to a whole toolbar.
1045
+ * Renders on both breakpoints unchanged; if it needs to look different on
1046
+ * mobile (e.g. collapsing into its own "⋮" trigger), that's the action
1047
+ * content's own responsibility — same pattern Shopper's `ListHeaderActions`
1048
+ * already follows (it calls `useIsMobile()` internally). `PageHeader`
1049
+ * itself has no opinion on what's inside this slot.
1050
+ */
693
1051
  action?: ReactNode;
694
1052
  className?: string;
695
1053
  /** Heading level for the title. Defaults to `1` for standalone use; pass
696
1054
  * `2` or `3` when the page already sits under a shell/plugin `<h1>`, to
697
1055
  * avoid a duplicate top-level heading. Visual style is unchanged at every
698
- * level — only the rendered tag changes. */
1056
+ * level — only the rendered tag changes. Applies on both breakpoints. */
699
1057
  headingLevel?: 1 | 2 | 3;
1058
+ /** Mobile only — shows a back button (calling this) to the left of the
1059
+ * title when provided. Omit it to render without one. */
1060
+ onBack?: () => void;
1061
+ /** Mobile only — shows a vertical-ellipsis icon button (calling this) at
1062
+ * the far right when provided, typically to open a drawer/menu. PageHeader
1063
+ * has no opinion on what that menu contains — it only renders the trigger
1064
+ * and calls back. Separate from `action`, which renders identically on
1065
+ * both breakpoints; this is a mobile-only affordance with no web
1066
+ * equivalent. */
1067
+ onMenuClick?: () => void;
700
1068
  }
701
- declare function PageHeader({ title, description, action, className, headingLevel, }: PageHeaderProps): react.JSX.Element;
1069
+ /**
1070
+ * PageHeader — a page's title section. Web: title + description on the
1071
+ * left, action on the right. Mobile: an optional back button, a single-line
1072
+ * title, and the same action slot — a compact single row, matching Kanban's
1073
+ * own hand-rolled MobileBoardHeader this was generalized from. The
1074
+ * web/mobile fork is `ResponsiveSurface` — only one tree is ever mounted.
1075
+ */
1076
+ declare function PageHeader({ title, description, icon, action, className, headingLevel, onBack, onMenuClick, }: PageHeaderProps): react.JSX.Element;
702
1077
 
703
1078
  interface PageContainerProps extends HTMLAttributes<HTMLDivElement> {
704
- /** Constrains and centers content width. Adds no padding of its own — the
705
- * runtime shell already pads plugin content. Defaults to 'md'. */
1079
+ /**
1080
+ * Constrains and centers content width. The bound includes `padding`
1081
+ * (the container is `border-box`). Defaults to `'full'` — narrowing is
1082
+ * opt-in, so wrapping a page in `PageContainer` never silently clamps it.
1083
+ */
706
1084
  maxWidth?: 'sm' | 'md' | 'lg' | 'full';
1085
+ /**
1086
+ * The page gutter. Responsive — each step is tighter at ≤768px. Defaults
1087
+ * to `'md'`, which is exactly what the runtime shell used to apply
1088
+ * (`--sv-space-8` desktop / `--sv-space-4` mobile), so a bare
1089
+ * `<PageContainer>` is the correct wrapper for a plugin that previously
1090
+ * relied on the shell for its padding.
1091
+ *
1092
+ * Use `'none'` when an ancestor already supplies the gutter — inside a
1093
+ * `Dialog`, whose own content region is padded.
1094
+ */
1095
+ padding?: 'none' | 'sm' | 'md' | 'lg';
707
1096
  children: ReactNode;
708
1097
  }
709
- declare function PageContainer({ maxWidth, className, children, ...rest }: PageContainerProps): react.JSX.Element;
1098
+ /**
1099
+ * The shared page wrapper every plugin's own layout or page renders through.
1100
+ *
1101
+ * A plugin owns its page gutter; the runtime shell does not impose one
1102
+ * (task 9.25). The shell still reserves space for chrome a plugin cannot
1103
+ * know about — the offline banner's height and the mobile footer's — but it
1104
+ * contributes no inset of its own, so this component is the single place a
1105
+ * plugin's four-sided padding comes from.
1106
+ */
1107
+ declare function PageContainer({ maxWidth, padding, className, children, ...rest }: PageContainerProps): react.JSX.Element;
1108
+
1109
+ interface HeaderPlugin {
1110
+ /** Plugin display name, rendered next to its icon. */
1111
+ name: string;
1112
+ /** Plugin icon — already sized (28px) and built by the consumer (typically
1113
+ * an `<img src="/plugin-icons/<id>.svg">`), matching `MobileHeader`'s own
1114
+ * router-agnostic convention for icon-shaped slots. */
1115
+ icon?: ReactNode;
1116
+ /** Where the plugin name/icon links to — typically the plugin's own
1117
+ * `routePrefix`. Omit to render plain (non-interactive) text instead of a
1118
+ * link — e.g. a plugin's own home page linking to itself would be a no-op. */
1119
+ href?: string;
1120
+ }
1121
+ interface HeaderProps extends HTMLAttributes<HTMLElement> {
1122
+ /** Instance name — derives the brand badge's initial (its first character,
1123
+ * uppercased) and the badge's accessible label. Does not render as text
1124
+ * anywhere in this component (unlike `MobileHeader`'s optional `title`). */
1125
+ instanceName: string;
1126
+ /** Optional instance logo image; falls back to `instanceName`'s initial
1127
+ * (matching the runtime shell's own sidebar/mobile-header fallback). */
1128
+ instanceLogoUrl?: string;
1129
+ /** Where the brand badge links — typically the Launcher plugin's route. */
1130
+ homeHref: string;
1131
+ /** The active plugin, rendered next to the brand badge. Omit for a page
1132
+ * with no single active plugin (e.g. the Launcher itself). */
1133
+ plugin?: HeaderPlugin;
1134
+ /** Apps launcher trigger — already wired by the consumer (icon button plus
1135
+ * whatever popover/drawer it opens). Always rendered, matching
1136
+ * `MobileHeader`'s bell/avatarMenu boundary: this component owns layout
1137
+ * only, never launcher/notification/account interaction logic. */
1138
+ launcher: ReactNode;
1139
+ /** Notification bell trigger — always rendered; not overridable. Same
1140
+ * "just an icon slot" boundary as `MobileHeader`'s own `bell` prop. */
1141
+ notifications: ReactNode;
1142
+ /** Avatar / account menu trigger — always rendered; not overridable. */
1143
+ avatarMenu: ReactNode;
1144
+ }
1145
+ /**
1146
+ * The web top-bar header: brand badge (+ optional active plugin) on the
1147
+ * left, launcher · notifications · avatar menu on the right. This is the
1148
+ * `shell: minimal` counterpart to the runtime shell's own sidebar — a plugin
1149
+ * that owns its whole viewport (no platform sidebar) renders this instead,
1150
+ * the same way it renders `MobileHeader` in place of the platform's mobile
1151
+ * chrome. Extracted into a shared component so a `shell: minimal` plugin
1152
+ * doesn't have to hand-roll its own top bar from scratch.
1153
+ *
1154
+ * Presentational only — no data fetching, no account/notification/launcher
1155
+ * logic of its own. `launcher`/`notifications`/`avatarMenu` are supplied
1156
+ * fully built, exactly like `MobileHeader`'s `bell`/`avatarMenu`: this
1157
+ * component stays router-agnostic and interaction-agnostic, and never
1158
+ * duplicates a real `AccountMenu`/notification-panel/apps-switcher
1159
+ * implementation.
1160
+ */
1161
+ declare function Header({ instanceName, instanceLogoUrl, homeHref, plugin, launcher, notifications, avatarMenu, className, ...rest }: HeaderProps): react.JSX.Element;
710
1162
 
711
1163
  interface MobileHeaderProps extends HTMLAttributes<HTMLDivElement> {
712
1164
  /** The brand/logo element — already a complete, clickable link home (e.g. an
@@ -744,6 +1196,13 @@ interface MobileHeaderProps extends HTMLAttributes<HTMLDivElement> {
744
1196
  * consumer's responsibility, matching the reference implementation in the
745
1197
  * runtime shell). See RFC 0088 for the immutable/overridable boundary this
746
1198
  * enforces.
1199
+ *
1200
+ * Self-measures its own rendered height and publishes it as
1201
+ * `--sv-shell-header-height` on the shell root — see
1202
+ * `usePublishShellChromeHeight`'s own doc comment for why this exists (it's
1203
+ * what makes a self-rendered header, the `shellConfig.mobileHeader: false`
1204
+ * pattern, correctly position `Dialog`'s inset and any other consumer of
1205
+ * that variable instead of being overlapped by it).
747
1206
  */
748
1207
  declare function MobileHeader({ logo, title, bell, avatarMenu, className, ...rest }: MobileHeaderProps): react.JSX.Element;
749
1208
 
@@ -782,6 +1241,13 @@ interface MobileFooterProps extends HTMLAttributes<HTMLElement> {
782
1241
  * Presentational only — no data fetching; the consumer owns the
783
1242
  * drawer/overlay `onOpenApps` opens. See RFC 0088 for the
784
1243
  * immutable/overridable boundary this enforces.
1244
+ *
1245
+ * Self-measures its own rendered height and publishes it as
1246
+ * `--sv-shell-footer-height` on the shell root — see
1247
+ * `usePublishShellChromeHeight`'s own doc comment for why this exists (it's
1248
+ * what makes a self-rendered footer, the `shellConfig.mobileFooter: false`
1249
+ * pattern, correctly clear `Sheet`/`Drawer`/`Dialog` instead of being
1250
+ * overlapped by them).
785
1251
  */
786
1252
  declare function MobileFooter({ onOpenApps, launcherIcon, launcherOpen, leftIcons, rightIcons, className, ...rest }: MobileFooterProps): react.JSX.Element;
787
1253
 
@@ -1331,6 +1797,17 @@ interface MessageScrollerProps {
1331
1797
  * content does not yank them back down — a "New messages" button appears
1332
1798
  * instead, matching the pattern every chat product (Slack, Discord,
1333
1799
  * ChatGPT) already uses.
1800
+ *
1801
+ * A short conversation is bottom-anchored, not left floating at the top of
1802
+ * the container with empty space below it — a leading flex-grow spacer
1803
+ * absorbs the leftover space and collapses to nothing once messages
1804
+ * overflow. Deliberately not `justify-content: flex-end` on the scroll
1805
+ * container itself: Chromium miscomputes `scrollHeight` as equal to
1806
+ * `clientHeight` for an overflowing flex-end-packed column, which makes the
1807
+ * container look fully scrolled to the bottom and permanently hides the
1808
+ * start of a long conversation (confirmed live before choosing this
1809
+ * approach). The spacer keeps `justify-content` at its default, so overflow
1810
+ * scrolling is unaffected.
1334
1811
  */
1335
1812
  declare function MessageScroller({ children, className }: MessageScrollerProps): react.JSX.Element;
1336
1813
 
@@ -1601,6 +2078,48 @@ interface DragHandleRowProps extends HTMLAttributes<HTMLDivElement> {
1601
2078
  */
1602
2079
  declare function DragHandleRow({ children, handleProps, isDragging, className, ...rest }: DragHandleRowProps): react.JSX.Element;
1603
2080
 
2081
+ interface GripIconProps {
2082
+ size?: number;
2083
+ className?: string;
2084
+ }
2085
+ /** Six-dot drag-handle affordance. No baked-in pointer-events or color —
2086
+ * a consumer that needs `pointer-events: none` (e.g. a button wrapping it)
2087
+ * or a specific color passes those via `className`/`currentColor`. */
2088
+ declare function GripIcon({ size, className }: GripIconProps): react.JSX.Element;
2089
+
2090
+ interface StepStripItem {
2091
+ id: string;
2092
+ }
2093
+ interface StepStripProps<T extends StepStripItem> {
2094
+ items: T[];
2095
+ activeId: string | null;
2096
+ /** Full control over each chip's content, click handling, and (if needed) drag-reorder wiring. */
2097
+ renderItem: (item: T, state: {
2098
+ isActive: boolean;
2099
+ index: number;
2100
+ }) => ReactNode;
2101
+ /** Trailing dashed "add" chip — omit to render the strip with no add affordance. */
2102
+ onAdd?: () => void;
2103
+ addLabel?: string;
2104
+ className?: string;
2105
+ 'aria-label'?: string;
2106
+ }
2107
+ /**
2108
+ * StepStrip — a horizontal, connected sequence of steps (a route or
2109
+ * itinerary strip): ordered chips joined by a thin connector line, with an
2110
+ * optional trailing dashed "add" chip. Purely presentational — it owns
2111
+ * layout and the connector lines, nothing else.
2112
+ *
2113
+ * Each chip's content, active styling, and click handling are entirely up
2114
+ * to `renderItem`; if a consumer needs drag-reorder, `renderItem` attaches
2115
+ * its own dnd-kit `useSortable` ref/listeners to whatever it returns. This
2116
+ * mirrors `DragHandleRow`'s existing split (DS owns chrome, consumer wires
2117
+ * dnd-kit via passed-through props) generalized for a horizontal,
2118
+ * handle-less strip where the whole rendered item — not a separate handle
2119
+ * icon — is both the click target and the drag surface.
2120
+ */
2121
+ declare function StepStrip<T extends StepStripItem>({ items, activeId, renderItem, onAdd, addLabel, className, 'aria-label': ariaLabel, }: StepStripProps<T>): react.JSX.Element;
2122
+
1604
2123
  interface FileDropzoneProps {
1605
2124
  /** Native `<input type="file">` `name` attribute — set this to submit the
1606
2125
  * file as part of a native `<form action={...}>` (Server Action) request. */
@@ -1749,6 +2268,63 @@ interface IconPickerProps {
1749
2268
  */
1750
2269
  declare function IconPicker({ value, onChange, options, 'aria-label': ariaLabel, triggerLabel, disabled, className, }: IconPickerProps): react.JSX.Element;
1751
2270
 
2271
+ interface ColorPickerSwatch {
2272
+ /** Accessible name and tooltip, e.g. "Sky". */
2273
+ label: string;
2274
+ /** 6-digit hex, e.g. "#b5c9e8". */
2275
+ value: string;
2276
+ }
2277
+ interface ColorPickerProps {
2278
+ /** Curated quick-pick suggestions, in display order. */
2279
+ swatches: readonly ColorPickerSwatch[];
2280
+ /** Current hex value, or `null` for no color. Compared case-insensitively
2281
+ * against `swatches` — a value that doesn't match any swatch renders as
2282
+ * the active "custom" selection instead. */
2283
+ value: string | null;
2284
+ onChange: (value: string | null) => void;
2285
+ /**
2286
+ * Fires once after a discrete, complete pick — a swatch click or the "no
2287
+ * color" click. Optional; most callers don't need it. Deliberately NOT
2288
+ * fired from the native custom-color `<input type="color">`'s `onChange`
2289
+ * — that can fire repeatedly while the user is still dragging inside the
2290
+ * browser's own color dialog, so a caller using this to auto-close a
2291
+ * wrapping `Popover` would otherwise slam it shut mid-adjustment.
2292
+ */
2293
+ onSelectionComplete?: () => void;
2294
+ /** Shows a leading "no color" option. Off by default — most consumers
2295
+ * (anything painting a fixed-size chip) always need a real color; only
2296
+ * a board canvas-style consumer typically wants "none" as a real choice. */
2297
+ allowNone?: boolean;
2298
+ noneLabel?: string;
2299
+ /** Accessible name for the native color-input trigger that lets a user
2300
+ * pick any color, not just a curated swatch. */
2301
+ customLabel?: string;
2302
+ disabled?: boolean;
2303
+ 'aria-label': string;
2304
+ className?: string;
2305
+ }
2306
+ /**
2307
+ * ColorPicker — a row of curated swatch suggestions plus a native
2308
+ * `<input type="color">` trigger for picking any color, not just the
2309
+ * curated set. The native color input is deliberately not a custom-built
2310
+ * hue/saturation picker: it already gives every browser's own full-spectrum
2311
+ * picker (with an eyedropper tool in most), guarantees valid hex output, and
2312
+ * needs no bespoke a11y work of its own.
2313
+ *
2314
+ * `value` drives which affordance reads as selected: a hex matching a
2315
+ * swatch highlights that swatch; a hex matching none of them highlights the
2316
+ * custom trigger instead (its own dial shows that color); `null` (only
2317
+ * meaningful with `allowNone`) highlights the "no color" option.
2318
+ *
2319
+ * The custom trigger shows a plain "+" on a neutral dashed box until a
2320
+ * genuinely custom color is active — it never previews an arbitrary dial
2321
+ * color the user hasn't actually chosen. The underlying native color input
2322
+ * still needs *some* real hex to hold internally at all times (it has no
2323
+ * true empty state), so that starting value stays invisible (`opacity: 0`
2324
+ * on the input itself) rather than painted as this trigger's own swatch.
2325
+ */
2326
+ declare function ColorPicker({ swatches, value, onChange, onSelectionComplete, allowNone, noneLabel, customLabel, disabled, 'aria-label': ariaLabel, className, }: ColorPickerProps): react.JSX.Element;
2327
+
1752
2328
  interface QuantityStepperProps {
1753
2329
  value: number;
1754
2330
  onChange: (value: number) => void;
@@ -2132,12 +2708,25 @@ interface UseSnapCarouselOptions {
2132
2708
  * extracted from. Debounced rather than keyed to the `scrollend` event,
2133
2709
  * which pre-17.4 iOS Safari/WKWebView doesn't support. */
2134
2710
  debounceMs?: number;
2711
+ /** The index to seed `liveIndex` with before any scroll event has fired —
2712
+ * must match whatever the caller initially scrolls/renders to (typically
2713
+ * the same value used for `SwipableMobileCarousel`'s `activeIndex`).
2714
+ * Without this, `liveIndex` would start at 0 regardless of where the
2715
+ * carousel actually opens (e.g. a deep link straight to slide 8),
2716
+ * briefly unmounting every slide except the first few until the first
2717
+ * scroll event arrives to correct it. */
2718
+ initialIndex?: number;
2135
2719
  }
2136
2720
  interface UseSnapCarouselResult {
2137
2721
  /** Attach to the `scroll-snap-type: x` scroll container. */
2138
2722
  scrollRef: RefObject<HTMLDivElement | null>;
2139
2723
  /** Imperatively scrolls the container to a slide index. */
2140
2724
  scrollToIndex: (index: number, behavior?: ScrollBehavior) => void;
2725
+ /** The slide index nearest the container's *current* scroll position,
2726
+ * updated synchronously on every `scroll` event — not debounced, and not
2727
+ * the same thing as the last-reported `onSettle` index. See its own
2728
+ * assignment below for why a consumer needs both. */
2729
+ liveIndex: number;
2141
2730
  }
2142
2731
  /**
2143
2732
  * useSnapCarousel — debounced "settled slide" detection over a native
@@ -2147,7 +2736,7 @@ interface UseSnapCarouselResult {
2147
2736
  * Gives swipe-between-slides physics for free via native scroll-snap, with
2148
2737
  * this hook only handling "which slide did we land on."
2149
2738
  */
2150
- declare function useSnapCarousel({ itemCount, onSettle, debounceMs, }: UseSnapCarouselOptions): UseSnapCarouselResult;
2739
+ declare function useSnapCarousel({ itemCount, onSettle, debounceMs, initialIndex, }: UseSnapCarouselOptions): UseSnapCarouselResult;
2151
2740
 
2152
2741
  interface UseResponsiveLayoutOptions<TWeb, TMobile> {
2153
2742
  web: TWeb;
@@ -2212,6 +2801,89 @@ interface UseCarouselRouteSyncResult {
2212
2801
  */
2213
2802
  declare function useCarouselRouteSync({ indexForPathname, pathForIndex, pathname, onNavigate, }: UseCarouselRouteSyncOptions): UseCarouselRouteSyncResult;
2214
2803
 
2804
+ /**
2805
+ * True when a drag should be allowed to start from `target`. Refused when
2806
+ * `target` sits inside an element marked `data-no-dnd` — a nested control
2807
+ * (e.g. a visibility toggle) opts out so tapping it fires its own handler
2808
+ * instead of lifting the row. Exported standalone so it's unit-testable
2809
+ * without spinning up dnd-kit.
2810
+ */
2811
+ declare function shouldHandleDndEvent(target: EventTarget | null): boolean;
2812
+ interface UseReorderSensorsOptions {
2813
+ mouseActivationDistancePx?: number;
2814
+ touchActivationDelayMs?: number;
2815
+ touchActivationTolerancePx?: number;
2816
+ }
2817
+ /**
2818
+ * Sensor set for a `data-no-dnd`-aware drag-reorder list — MouseSensor for
2819
+ * desktop's handle-initiated drag, TouchSensor for mobile's long-press lift
2820
+ * (fixes reordering being unusable on iOS PWA/Safari, which never implements
2821
+ * the native HTML5 Drag-and-Drop API for touch input), KeyboardSensor
2822
+ * unchanged. A bare call keeps the historical 8px/300ms/8px defaults.
2823
+ */
2824
+ declare function useReorderSensors(options?: UseReorderSensorsOptions): _dnd_kit_core.SensorDescriptor<_dnd_kit_core.SensorOptions>[];
2825
+
2826
+ type SwipeDirection = 'left' | 'right' | 'up' | 'down';
2827
+ /** Duration (ms) of both the commit fling-out and the spring-back-under-
2828
+ * threshold transition. Exported so SwipeStack can hold a just-committed
2829
+ * card in place for exactly this long before advancing to the next one. */
2830
+ declare const SWIPE_STACK_TRANSITION_MS = 220;
2831
+ interface UseSwipeStackOptions {
2832
+ /** Directions this drag can move toward and resolve to. A direction left
2833
+ * out of this list is a wall, not just an unreachable outcome — the card
2834
+ * will not visually move that way at all (see clampToLiveDirections). */
2835
+ directions: readonly SwipeDirection[];
2836
+ /** Effective distance (px) a drag must cross before release commits to
2837
+ * that direction instead of springing back. No velocity component — a
2838
+ * fast short flick under this distance still springs back. */
2839
+ threshold?: number;
2840
+ /** Fires once, synchronously, when a drag (or triggerCommit) resolves to
2841
+ * a live direction past threshold. This hook has already started the
2842
+ * fling-out animation on cardRef's element by the time this is called —
2843
+ * the caller only needs to react to the outcome, not drive the motion. */
2844
+ onCommit: (direction: SwipeDirection) => void;
2845
+ /** Disables both the drag and triggerCommit — e.g. while there is no
2846
+ * current card to act on. */
2847
+ disabled?: boolean;
2848
+ }
2849
+ interface UseSwipeStackHandlers {
2850
+ onPointerDown: (e: PointerEvent) => void;
2851
+ onPointerMove: (e: PointerEvent) => void;
2852
+ onPointerUp: (e: PointerEvent) => void;
2853
+ onPointerCancel: (e: PointerEvent) => void;
2854
+ }
2855
+ interface UseSwipeStackResult {
2856
+ /** Attach to the card element that should translate/rotate with the drag. */
2857
+ cardRef: RefObject<HTMLDivElement | null>;
2858
+ /** Attach to the ancestor of both the card and any direction-stamp
2859
+ * overlays. The hook writes live drag progress here as CSS custom
2860
+ * properties (--sv-stack-progress-left/right/up/down, each 0–1) so
2861
+ * stamps — siblings of the card, not the card itself — can react without
2862
+ * a re-render per pointermove. */
2863
+ wrapRef: RefObject<HTMLDivElement | null>;
2864
+ handlers: UseSwipeStackHandlers;
2865
+ /** CSS touch-action for the card, derived from which directions are live
2866
+ * — an axis with nothing configured on it stays native (pan-x/pan-y) so
2867
+ * a page can still scroll through a stack that only uses the other axis;
2868
+ * `none` only once both axes are actually needed. */
2869
+ touchAction: string;
2870
+ /** Programmatically commits a direction — the same fling animation and
2871
+ * onCommit call a real drag past threshold would produce. Backs the
2872
+ * non-gesture fallback buttons: they are not a separate code path, just
2873
+ * a different way to call this. No-ops if the direction isn't live or
2874
+ * the hook is disabled. */
2875
+ triggerCommit: (direction: SwipeDirection) => void;
2876
+ }
2877
+ /**
2878
+ * useSwipeStack — hand-rolled 4-directional free drag, extending
2879
+ * useSwipeReveal's pattern (raw Pointer Events, a deadzone, transform
2880
+ * written straight to a ref, resolved only on release) from one axis with
2881
+ * two outcomes to four directions with a tilt. Threshold-only on purpose,
2882
+ * matching useSwipeReveal — no velocity tracking, so a fast short flick
2883
+ * under `threshold` still springs back.
2884
+ */
2885
+ declare function useSwipeStack({ directions, threshold, onCommit, disabled, }: UseSwipeStackOptions): UseSwipeStackResult;
2886
+
2215
2887
  interface ResponsiveSurfaceProps {
2216
2888
  web: ReactNode;
2217
2889
  mobile: ReactNode;
@@ -2240,6 +2912,14 @@ interface SwipableMobileCarouselDotsProps {
2240
2912
  /** Labels the whole group — required, no generic fallback (mirrors
2241
2913
  * SwipableMobileCarousel's own required aria-label). */
2242
2914
  'aria-label': string;
2915
+ /** `'compact'` halves the gap between dots (`--sv-space-2` → `--sv-space-1`)
2916
+ * and shrinks each dot's own hit target (20px → 16px) — for a carousel
2917
+ * with enough slides that even the reduced gap alone still reads as too
2918
+ * wide on a narrow viewport (e.g. a many-list mobile app). The visible
2919
+ * 6px dot itself is unchanged; only its surrounding tap-target box
2920
+ * shrinks. Defaults to `'default'` — every existing consumer's spacing is
2921
+ * unaffected unless it opts in. */
2922
+ density?: 'default' | 'compact';
2243
2923
  className?: string;
2244
2924
  }
2245
2925
  /**
@@ -2255,7 +2935,7 @@ interface SwipableMobileCarouselDotsProps {
2255
2935
  * other `role="tablist"` component) has none either, so this stays
2256
2936
  * consistent with it rather than gold-plating past its sibling.
2257
2937
  */
2258
- declare function SwipableMobileCarouselDots({ count, activeIndex, onJump, labels, 'aria-label': ariaLabel, className, }: SwipableMobileCarouselDotsProps): react.JSX.Element;
2938
+ declare function SwipableMobileCarouselDots({ count, activeIndex, onJump, labels, 'aria-label': ariaLabel, density, className, }: SwipableMobileCarouselDotsProps): react.JSX.Element;
2259
2939
 
2260
2940
  interface SwipableMobileCarouselIndicatorProps {
2261
2941
  count: number;
@@ -2387,4 +3067,326 @@ interface SwipableMobileCarouselSlideFooterProps {
2387
3067
  */
2388
3068
  declare function SwipableMobileCarouselSlideFooter({ children, className, }: SwipableMobileCarouselSlideFooterProps): react.JSX.Element;
2389
3069
 
2390
- export { Accordion, type AccordionItem, type AccordionProps, Alert, type AlertProps, type AlertVariant, AspectRatio, type AspectRatioProps, Avatar, type AvatarProps, Badge, type BadgeProps, type BadgeStatus, type BadgeVariant, BalanceChip, type BalanceChipProps, type BannerVariant, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, type ButtonSize, type ButtonVariant, Calendar, type CalendarProps, Card, type CardProps, CheckableListRow, type CheckableListRowProps, Checkbox, type CheckboxProps, CodeTextarea, type CodeTextareaProps, Collapsible, type CollapsibleProps, Combobox, type ComboboxOption, type ComboboxProps, Command, type CommandItem, type CommandProps, type CommitOnEnterOrBlurHandlers, ConfirmDialog, type ConfirmDialogProps, ContextMenu, type ContextMenuProps, CurrencyInput, type CurrencyInputProps, DataTable, type DataTableColumn, type DataTableProps, DatePicker, type DatePickerProps, DeviceOnlyGate, type DeviceOnlyGateProps, DeviceStorageKeyGate, type DeviceStorageKeyGateProps, type DeviceStorageKeyGateStatus, Dialog, type DialogProps, type DialogSize, DragHandleRow, type DragHandleRowProps, Drawer, type DrawerProps, EmptyState, type EmptyStateProps, FileDropzone, type FileDropzoneProps, type FooterIcon, FormField, type FormFieldProps, type FormFieldRenderProps, HoverCard, type HoverCardProps, Icon, type IconName, IconPicker, type IconPickerProps, type IconProps, Input, type InputProps, Item, type ItemProps, Kbd, type KbdProps, Label, type LabelProps, LegalLinks, type LegalLinksProps, type LongPressHandlers, MOBILE_BREAKPOINT_PX, Markdown, type MarkdownProps, Marker, type MarkerProps, MemberMultiSelect, type MemberMultiSelectOption, type MemberMultiSelectProps, Menu, MenuEntries, type MenuEntry, type MenuItem, type MenuLabel, type MenuProps, type MenuSeparator, Menubar, type MenubarMenu, type MenubarProps, Message, type MessageProps, MessageScroller, type MessageScrollerProps, type MessageSender, MobileAppsDrawer, type MobileAppsDrawerItem, type MobileAppsDrawerProps, MobileFooter, type MobileFooterProps, MobileHeader, type MobileHeaderProps, type NavTabItem, type NavTabLinkProps, NavTabs, type NavTabsProps, NavigationMenu, type NavigationMenuItem, type NavigationMenuProps, OfflineGate, type OfflineGateProps, type OfflineTileState, OverlayHeader, type OverlayHeaderProps, PageContainer, type PageContainerProps, PageHeader, type PageHeaderProps, Pagination, type PaginationProps, Popover, type PopoverProps, Progress, type ProgressProps, QuantityStepper, type QuantityStepperProps, RadioGroup, type RadioGroupItem, type RadioGroupProps, type ResizableDirection, ResizableHandle, type ResizableHandleProps, ResizablePanel, ResizablePanelGroup, type ResizablePanelGroupProps, type ResizablePanelProps, ResponsiveSurface, type ResponsiveSurfaceProps, ScrollArea, type ScrollAreaProps, SegmentedControl, type SegmentedControlProps, type SegmentedOption, Select, type SelectProps, Sheet, type SheetProps, Slider, type SliderProps, type SortDirection, Spinner, type SpinnerProps, type SplitMethod, SplitMethodSelector, type SplitMethodSelectorProps, SplitPane, type SplitPaneProps, StatusBadge, type StatusBadgeProps, type StatusBadgeStatus, SuggestionInput, type SuggestionInputProps, type SuggestionOption, SwipableMobileCarousel, SwipableMobileCarouselDots, type SwipableMobileCarouselDotsProps, type SwipableMobileCarouselIndicatorProps, type SwipableMobileCarouselProps, SwipableMobileCarouselSlide, SwipableMobileCarouselSlideBody, type SwipableMobileCarouselSlideBodyProps, SwipableMobileCarouselSlideFooter, type SwipableMobileCarouselSlideFooterProps, SwipableMobileCarouselSlideHeader, type SwipableMobileCarouselSlideHeaderProps, type SwipableMobileCarouselSlideProps, SystemBanner, type SystemBannerProps, type TabItem, Table, TableBody, TableCell, TableHead, TableHeaderCell, type TableProps, TableRow, Tabs, type TabsProps, TagInput, type TagInputProps, Textarea, type TextareaProps, type ToastContextValue, type ToastItem, ToastProvider, Toggle, type ToggleProps, Tooltip, type TooltipProps, Typography, type TypographyProps, type TypographyVariant, type UseCarouselRouteSyncOptions, type UseCarouselRouteSyncResult, type UseLongPressOptions, type UseResponsiveLayoutOptions, type UseResponsiveLayoutResult, type UseSnapCarouselOptions, type UseSnapCarouselResult, type UseSwipeRevealHandlers, type UseSwipeRevealOptions, type UseSwipeRevealResult, useCarouselRouteSync, useCommitOnEnterOrBlur, useDoubleTapHandler, useIsMobile, useIsOffline, useLongPress, useOfflineTileState, useOverlaySecondRow, useResponsiveLayout, useSingleOrDoubleTap, useSnapCarousel, useSwipeReveal, useToast };
3070
+ interface SwipeDirectionMeta {
3071
+ /** Visible text on the fallback button and the in-drag stamp. */
3072
+ label: string;
3073
+ icon?: IconName;
3074
+ }
3075
+ interface SwipeStackProps {
3076
+ /** Required — labels the swipeable region for assistive tech. No generic
3077
+ * fallback, since one would be wrong for every actual consumer. */
3078
+ 'aria-label': string;
3079
+ /** Which of the 4 directions are live, and what each is called. A
3080
+ * direction absent here cannot be dragged toward at all (useSwipeStack
3081
+ * treats it as a wall) and gets no fallback button or stamp. SwipeStack
3082
+ * itself has no opinion on what a direction *means* — that vocabulary
3083
+ * belongs entirely to the caller. */
3084
+ directions: Partial<Record<SwipeDirection, SwipeDirectionMeta>>;
3085
+ /** Fires once a drag (or a fallback button) commits to a direction. Every
3086
+ * configured direction behaves the same way: the card leaves for good —
3087
+ * there is no reversible "go back" state. SwipeStack has no opinion on
3088
+ * where card data lives; the caller is responsible for eventually no
3089
+ * longer including this cardId in children (e.g. once a mutation lands). */
3090
+ onSwipe: (direction: SwipeDirection, cardId: string) => void;
3091
+ /** Effective drag distance (px) required to commit. Passed straight
3092
+ * through to useSwipeStack. */
3093
+ threshold?: number;
3094
+ className?: string;
3095
+ /** Must be SwipeStackCard elements (nullish/boolean children are safely
3096
+ * skipped for conditional cards). A dev-mode warning is logged for any
3097
+ * other child type — see resolveCards below. */
3098
+ children: ReactNode;
3099
+ }
3100
+ /**
3101
+ * SwipeStack — a compound component for triaging one card at a time by
3102
+ * dragging it left/right/up/down (wrapping useSwipeStack), plus an
3103
+ * always-visible non-gesture fallback: a button per configured direction,
3104
+ * wired to the identical commit path and exit animation as a real drag.
3105
+ *
3106
+ * Every direction is independently optional and behaves the same way once
3107
+ * triggered — the card leaves for good, there is no reversible "go back".
3108
+ * SwipeStack owns rendering, drag physics, and the stamp/fallback UI only;
3109
+ * it has no opinion on where card data lives or what a direction means —
3110
+ * see SwipeStackProps.onSwipe.
3111
+ */
3112
+ declare function SwipeStack({ 'aria-label': ariaLabel, directions, onSwipe, threshold, className, children, }: SwipeStackProps): react.JSX.Element;
3113
+
3114
+ interface SwipeStackCardProps {
3115
+ /** Stable identity for this card, independent of its position among
3116
+ * siblings — required. This is what SwipeStack reads (via child.props,
3117
+ * not React's own `key`, which a component can't see on itself) to know
3118
+ * which card is on top and what id to report through onSwipe. Reuse
3119
+ * whatever id the caller already keys their `.map()` on. */
3120
+ cardId: string;
3121
+ children: ReactNode;
3122
+ }
3123
+ /**
3124
+ * SwipeStackCard — a single card of a SwipeStack. Unlike
3125
+ * SwipableMobileCarouselSlide, this has no mount-window logic of its own:
3126
+ * SwipeStack only ever renders the top two cards' elements at all (there is
3127
+ * no scroll-position reason to keep every sibling in the DOM the way the
3128
+ * carousel's scroll-snap track does), so there is nothing here to gate.
3129
+ */
3130
+ declare function SwipeStackCard({ children }: SwipeStackCardProps): react.JSX.Element;
3131
+
3132
+ interface ThreeColumnLayoutProps {
3133
+ /**
3134
+ * Exactly 2 (sidebar, main) or 3 (sidebar, main, detail) elements. Omit
3135
+ * the third child entirely to render two columns — e.g.
3136
+ * `{selected && <Detail />}` — React.Children.toArray drops falsy
3137
+ * children, so no separate `detail` prop is needed to make that
3138
+ * conditional.
3139
+ */
3140
+ children: ReactNode;
3141
+ /** px. Fixed width of the first (leftmost) column. Default 280. */
3142
+ sidebarWidth?: number;
3143
+ /** px. Fixed width of the third column, when present. Default 360. */
3144
+ detailWidth?: number;
3145
+ /**
3146
+ * Hides the sidebar column entirely — no width, no border, no layout box
3147
+ * — while keeping it mounted and every sibling in its own stable position.
3148
+ *
3149
+ * Prefer this over conditionally omitting the sidebar child, or swapping
3150
+ * to a different wrapper when collapsed. Omitting it shifts `main` into
3151
+ * the sidebar slot, and swapping the surrounding element type unmounts
3152
+ * `main`'s entire subtree — silently discarding its React state (a live
3153
+ * stream, unsent composer text, an in-memory-only conversation) on every
3154
+ * collapse toggle. Found live in Warden, whose chat column lost all of
3155
+ * that each time the sidebar was shown or hidden.
3156
+ */
3157
+ sidebarHidden?: boolean;
3158
+ className?: string;
3159
+ }
3160
+ /**
3161
+ * ThreeColumnLayout — sidebar + main + optional detail column, for the
3162
+ * common "list app" shape (a list sidebar, a primary content list, and a
3163
+ * detail pane that only takes up space once something is selected).
3164
+ *
3165
+ * Purely positional and structural — it has no awareness of what's inside
3166
+ * each slot (no injected landmarks/labels; those belong to the children
3167
+ * themselves) and no responsive behavior of its own. Collapsing further at
3168
+ * narrow desktop/tablet widths (e.g. swapping the detail column for an
3169
+ * overlay) is the consuming plugin's decision; below the mobile breakpoint,
3170
+ * compose with ResponsiveSurface to fork to a different tree entirely.
3171
+ */
3172
+ declare function ThreeColumnLayout({ children, sidebarWidth, detailWidth, sidebarHidden, className, }: ThreeColumnLayoutProps): react.JSX.Element;
3173
+
3174
+ interface HeaderFooterLayoutProps {
3175
+ /** Main content — required, always fills whatever height header/footer don't claim. */
3176
+ children: ReactNode;
3177
+ header?: ReactNode;
3178
+ footer?: ReactNode;
3179
+ /** px. Fixed height of the header, when present. Default 60 (matches
3180
+ * MobileHeader/--sv-shell-header-height's own default). */
3181
+ headerHeight?: number;
3182
+ /** px. Fixed height of the footer, when present. Default 60 (matches
3183
+ * MobileFooter/--sv-shell-footer-height's own default). */
3184
+ footerHeight?: number;
3185
+ className?: string;
3186
+ }
3187
+ /**
3188
+ * HeaderFooterLayout — header + main + optional footer, both fixed-height
3189
+ * and independently optional, with main always claiming the remaining
3190
+ * height. The vertical counterpart to ThreeColumnLayout: same purely
3191
+ * structural approach (no color/background opinions, no awareness of what's
3192
+ * inside each slot, no responsive behavior of its own — a plain flex
3193
+ * column), just rotated. "Footer always at the bottom" falls out of flex
3194
+ * layout alone; there is no position: fixed or safe-area handling here, so
3195
+ * a caller composing this with the platform shell's own chrome still owns
3196
+ * that separately.
3197
+ */
3198
+ declare function HeaderFooterLayout({ children, header, footer, headerHeight, footerHeight, className, }: HeaderFooterLayoutProps): react.JSX.Element;
3199
+
3200
+ type RootLayoutVariant = 'plain' | 'sidebar' | 'header' | 'shell';
3201
+ interface RootLayoutProps {
3202
+ /**
3203
+ * Which chrome shape this page uses. Children are positional and their
3204
+ * count is fixed per variant:
3205
+ * - `'plain'` — 1 child: `[main]`. No chrome on either breakpoint.
3206
+ * - `'sidebar'` — 2 children: `[sidebar, main]`. Sidebar + main on web
3207
+ * only — on mobile, sidebar is dropped and only main renders.
3208
+ * - `'header'` — 2 children: `[header, main]`. Header + main on both
3209
+ * breakpoints — same structure, but the header's own height differs
3210
+ * per breakpoint (`headerHeight` on web, `mobileHeaderHeight` on
3211
+ * mobile), matching how real `shell: minimal` plugins actually do
3212
+ * this (a compact web top bar vs. the platform's mobile chrome
3213
+ * height).
3214
+ * - `'shell'` — 3 children: `[header, main, footer]`. Header + main +
3215
+ * footer on mobile only — on web, header/footer are dropped and only
3216
+ * main renders.
3217
+ * Default `'plain'`.
3218
+ */
3219
+ variant?: RootLayoutVariant;
3220
+ children: ReactNode;
3221
+ /** px. Default 64 — matches the platform's own persistent nav rail
3222
+ * (`--sv-shell-sidebar-width`, runtime/app/(platform)/shell.module.css).
3223
+ * Only used by `'sidebar'`. */
3224
+ sidebarWidth?: number;
3225
+ /** px. Default 48 — matches a real `shell: minimal` plugin's own compact
3226
+ * web header (e.g. Kanban's `KanbanHeader`, deliberately not the
3227
+ * platform's 60px shell header since a `shell: minimal` plugin owns its
3228
+ * whole viewport). Web only — used by `'header'` on web. */
3229
+ headerHeight?: number;
3230
+ /** px. Default 60 — matches the platform's own mobile chrome
3231
+ * (`--sv-shell-header-height`, `MobileHeader`'s default). Mobile only —
3232
+ * used by `'header'` and `'shell'` on mobile. */
3233
+ mobileHeaderHeight?: number;
3234
+ /** px. Default 60 — matches the platform's own mobile chrome
3235
+ * (`--sv-shell-footer-height`, `MobileFooter`'s default). Mobile only —
3236
+ * used by `'shell'`. */
3237
+ footerHeight?: number;
3238
+ className?: string;
3239
+ }
3240
+ /**
3241
+ * RootLayout — the root-level layout a plugin's page tree sits in. Enforces
3242
+ * only structure and dimensions (`width: 100%; height: 100%`, filling
3243
+ * whatever real height the platform shell's own ancestor chain already
3244
+ * establishes — not viewport units, since a plugin isn't alone on the
3245
+ * page). A definite height, not min-height: ThreeColumnLayout/
3246
+ * HeaderFooterLayout's own .shell need one to resolve their own height:
3247
+ * 100% against (see RootLayout.module.css's comment). All content comes
3248
+ * from children; RootLayout has no opinion on what's inside any region.
3249
+ *
3250
+ * The web/mobile fork is `ResponsiveSurface` — only one of
3251
+ * `RootLayoutWeb`/`RootLayoutMobile` is ever mounted, never a CSS squeeze of
3252
+ * the same tree. Each variant's actual shape is delegated entirely to
3253
+ * `ThreeColumnLayout`/`HeaderFooterLayout`; RootLayout itself contains no
3254
+ * media queries.
3255
+ */
3256
+ declare function RootLayout({ variant, children, sidebarWidth, headerHeight, mobileHeaderHeight, footerHeight, className, }: RootLayoutProps): react.JSX.Element;
3257
+
3258
+ type PageLayoutPadding = 'none' | 'sm' | 'md' | 'lg';
3259
+ interface PageLayoutProps {
3260
+ /**
3261
+ * A page-specific header — e.g. a board title + search/share toolbar.
3262
+ * Not the app-level header (that's `RootLayout`'s `header`/`shell`
3263
+ * variants) — this is a second, contextual row scoped to this one page.
3264
+ * Renders edge-to-edge above the padded content, outside `padding`.
3265
+ */
3266
+ header?: ReactNode;
3267
+ /** The page gutter. Default `'none'` — unlike `PageContainer`, a bare
3268
+ * `PageLayout` applies no padding at all; opt in per page. Same four-step
3269
+ * scale and `--sv-page-gutter` stand-down hook as `PageContainer` (steps
3270
+ * down at the same 768px breakpoint `Dialog`/`MobileHeader` use). */
3271
+ padding?: PageLayoutPadding;
3272
+ children: ReactNode;
3273
+ className?: string;
3274
+ }
3275
+ /**
3276
+ * PageLayout — a single page's content area within a plugin (nested inside
3277
+ * `RootLayout`'s `main` slot, not a replacement for it). Enforces only
3278
+ * structure and dimensions; content always comes from props/children.
3279
+ *
3280
+ * `min-width: 100%; min-height: 100%` — safe here (unlike `RootLayout`'s own
3281
+ * root) because `PageLayout` is always nested inside an already
3282
+ * flex-stretched region (`ThreeColumnLayout`/`HeaderFooterLayout`'s
3283
+ * `.main`), and a stretched flex item's cross-size is definite for its
3284
+ * descendants' percentage resolution, so no separate height-cascading fix
3285
+ * is needed the way `RootLayout`'s root required one.
3286
+ */
3287
+ declare function PageLayout({ header, padding, children, className }: PageLayoutProps): react.JSX.Element;
3288
+
3289
+ interface NavListItem {
3290
+ id: string;
3291
+ label: string;
3292
+ href: string;
3293
+ icon: IconName;
3294
+ /** Trailing content, e.g. a count — reserved for a future consumer, not used by `variant="drilldown"`'s own chevron slot. */
3295
+ badge?: ReactNode;
3296
+ /**
3297
+ * Only meaningful for `variant="static"` — whether this row represents the
3298
+ * current page. Computed by the consumer (e.g. via `usePathname()` plus a
3299
+ * longest-prefix match against every item's `href`), since this package
3300
+ * doesn't depend on `next/navigation` — same reasoning as `NavTabs`.
3301
+ */
3302
+ active?: boolean;
3303
+ }
3304
+ interface NavListGroup {
3305
+ id: string;
3306
+ /** Omit for an ungrouped leading item/group — e.g. a pinned "Overview" row above the grouped sections. */
3307
+ label?: string;
3308
+ items: NavListItem[];
3309
+ }
3310
+ /** Props to spread onto a consumer-supplied link element — mirrors `NavTabs`' `NavTabLinkProps`. */
3311
+ interface NavListLinkProps {
3312
+ href: string;
3313
+ className: string;
3314
+ 'aria-current': 'page' | undefined;
3315
+ children: ReactNode;
3316
+ }
3317
+ interface NavListProps {
3318
+ groups: NavListGroup[];
3319
+ /**
3320
+ * `"static"`: active row highlighted via `item.active`, no chevron — a
3321
+ * persistent sidebar nav. `"drilldown"`: every row gets a trailing chevron
3322
+ * and no active-state, tapping navigates to a full-screen section — a
3323
+ * native Settings-app style index.
3324
+ */
3325
+ variant: 'static' | 'drilldown';
3326
+ /**
3327
+ * `"default"`: each row is a full `--sv-touch-target-min` tall tap target
3328
+ * — the right choice for `variant="drilldown"`'s mobile index, and for any
3329
+ * `static` sidebar list long enough that scanability matters more than
3330
+ * density. `"compact"` shrinks row height/padding for a short, always-
3331
+ * visible `static` list (e.g. 2-4 items above a longer scrollable list of
3332
+ * something else) where the default's touch-target height reads as
3333
+ * needlessly spaced out. Only meaningful for `variant="static"` —
3334
+ * `drilldown` rows stay full-height regardless, since that variant is
3335
+ * mobile-only and touch-target size there isn't optional. Defaults to
3336
+ * `"default"` so every existing consumer (e.g. Console's own sidebar) is
3337
+ * visually unchanged.
3338
+ */
3339
+ density?: 'default' | 'compact';
3340
+ 'aria-label': string;
3341
+ className?: string;
3342
+ /**
3343
+ * Render a row as something other than a plain `<a href>` — e.g. Next's
3344
+ * `<Link>`. Receives the item plus the class name/aria attributes NavList
3345
+ * would otherwise apply, matching `NavTabs`' `renderLink` contract.
3346
+ */
3347
+ renderLink?: (item: NavListItem, linkProps: NavListLinkProps) => ReactNode;
3348
+ }
3349
+ /**
3350
+ * NavList — a vertical list of icon+label rows, optionally grouped under
3351
+ * section headers. Two presentations of the same `groups` data: `static` (a
3352
+ * persistent sidebar, active item highlighted) and `drilldown` (a
3353
+ * native-Settings-app style index, every row navigates to a full section).
3354
+ *
3355
+ * Framework-agnostic like `NavTabs` — no `next/navigation`/`next/link`
3356
+ * import, no internal pathname reading. Active state and navigation behavior
3357
+ * are supplied by the consumer via `item.active` and `renderLink`.
3358
+ */
3359
+ declare function NavList({ groups, variant, density, 'aria-label': ariaLabel, className, renderLink, }: NavListProps): react.JSX.Element;
3360
+
3361
+ /**
3362
+ * Sovereign Design System — theme presets (RFC 0094).
3363
+ *
3364
+ * The single source of truth for every built-in theme preset's token
3365
+ * overrides. Deliberately plain data (no CSS-in-JS, no build dependency) so
3366
+ * it can be consumed two ways with zero duplication:
3367
+ * - `scripts/generate-theme-presets-css.ts` (`pnpm generate:theme-presets`)
3368
+ * reads this file and emits `theme-presets.css` for Storybook/standalone
3369
+ * consumers.
3370
+ * - `runtime/src/instance-style.ts` (RFC 0095) imports `THEME_PRESETS`
3371
+ * directly and flattens the selected preset into the existing
3372
+ * `:root { ... }` instance-style injection — no CSS parsing, no second
3373
+ * copy of these values to drift out of sync.
3374
+ *
3375
+ * Presets are closed and built-in (RFC 0094's "Alternatives considered") —
3376
+ * add a new one here and re-run the generator, never accept arbitrary
3377
+ * operator-supplied values into this shape.
3378
+ *
3379
+ * `'default'` MUST stay `{ light: {}, dark: {} }` — an empty override set is
3380
+ * what guarantees today's look stays byte-identical for every instance that
3381
+ * never opts into a different preset.
3382
+ */
3383
+ type ThemePresetName = 'default' | 'neobrutalism';
3384
+ declare const THEME_PRESET_NAMES: readonly ThemePresetName[];
3385
+ interface ThemePresetTokens {
3386
+ /** Sparse — only tokens this preset overrides. Everything else falls through to the default. */
3387
+ light: Record<string, string>;
3388
+ dark: Record<string, string>;
3389
+ }
3390
+ declare const THEME_PRESETS: Record<ThemePresetName, ThemePresetTokens>;
3391
+
3392
+ export { Accordion, type AccordionItem, type AccordionProps, Alert, type AlertProps, type AlertVariant, AppsLauncher, type AppsLauncherItem, type AppsLauncherProps, AspectRatio, type AspectRatioProps, Avatar, type AvatarProps, Badge, type BadgeProps, type BadgeStatus, type BadgeVariant, BalanceChip, type BalanceChipProps, type BannerVariant, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, type ButtonSize, type ButtonVariant, Calendar, type CalendarProps, Card, type CardProps, CardTile, CardTileGrid, type CardTileGridProps, type CardTileProps, CheckableListRow, type CheckableListRowProps, Checkbox, type CheckboxProps, CodeTextarea, type CodeTextareaProps, Collapsible, type CollapsibleProps, ColorPicker, type ColorPickerProps, type ColorPickerSwatch, Combobox, type ComboboxOption, type ComboboxProps, Command, type CommandItem, type CommandProps, type CommitOnEnterOrBlurHandlers, ConfirmDialog, type ConfirmDialogProps, ConsentPrompt, type ConsentPromptProps, ContextMenu, type ContextMenuProps, CurrencyInput, type CurrencyInputProps, DataTable, type DataTableColumn, type DataTableProps, DatePicker, type DatePickerProps, DeviceOnlyGate, type DeviceOnlyGateProps, DeviceStorageKeyGate, type DeviceStorageKeyGateProps, type DeviceStorageKeyGateStatus, Dialog, type DialogProps, type DialogSize, DragHandleRow, type DragHandleRowProps, Drawer, type DrawerProps, EmptyState, type EmptyStateProps, FileDropzone, type FileDropzoneProps, type FooterIcon, FormField, type FormFieldProps, type FormFieldRenderProps, GripIcon, type GripIconProps, Header, HeaderFooterLayout, type HeaderFooterLayoutProps, type HeaderPlugin, type HeaderProps, HoverCard, type HoverCardProps, Icon, type IconName, IconPicker, type IconPickerProps, type IconProps, Input, type InputProps, Item, type ItemProps, Kbd, type KbdProps, Label, type LabelProps, LegalLinks, type LegalLinksProps, type LongPressHandlers, MOBILE_BREAKPOINT_PX, Markdown, type MarkdownProps, Marker, type MarkerProps, MemberMultiSelect, type MemberMultiSelectOption, type MemberMultiSelectProps, Menu, MenuEntries, type MenuEntry, type MenuItem, type MenuLabel, type MenuProps, type MenuSeparator, Menubar, type MenubarMenu, type MenubarProps, Message, type MessageProps, MessageScroller, type MessageScrollerProps, type MessageSender, MobileAppsDrawer, type MobileAppsDrawerItem, type MobileAppsDrawerProps, MobileFooter, type MobileFooterProps, MobileHeader, type MobileHeaderProps, NavList, type NavListGroup, type NavListItem, type NavListLinkProps, type NavListProps, type NavTabItem, type NavTabLinkProps, NavTabs, type NavTabsProps, NavigationMenu, type NavigationMenuItem, type NavigationMenuProps, NewCardTile, type NewCardTileProps, NotificationsPanel, type NotificationsPanelItem, type NotificationsPanelProps, OfflineGate, type OfflineGateProps, type OfflineTileState, OverlayHeader, type OverlayHeaderProps, PageContainer, type PageContainerProps, PageHeader, type PageHeaderProps, PageLayout, type PageLayoutPadding, type PageLayoutProps, Pagination, type PaginationProps, Popover, type PopoverProps, Progress, type ProgressProps, QuantityStepper, type QuantityStepperProps, RadioGroup, type RadioGroupItem, type RadioGroupProps, type ResizableDirection, ResizableHandle, type ResizableHandleProps, ResizablePanel, ResizablePanelGroup, type ResizablePanelGroupProps, type ResizablePanelProps, ResponsiveSurface, type ResponsiveSurfaceProps, RootLayout, type RootLayoutProps, type RootLayoutVariant, SWIPE_STACK_TRANSITION_MS, ScrollArea, type ScrollAreaProps, SegmentedControl, type SegmentedControlProps, type SegmentedOption, Select, type SelectProps, Sheet, type SheetProps, Slider, type SliderProps, type SortDirection, Spinner, type SpinnerProps, type SplitMethod, SplitMethodSelector, type SplitMethodSelectorProps, SplitPane, type SplitPaneProps, StatusBadge, type StatusBadgeProps, type StatusBadgeStatus, StepStrip, type StepStripItem, type StepStripProps, SuggestionInput, type SuggestionInputProps, type SuggestionOption, SwipableMobileCarousel, SwipableMobileCarouselDots, type SwipableMobileCarouselDotsProps, type SwipableMobileCarouselIndicatorProps, type SwipableMobileCarouselProps, SwipableMobileCarouselSlide, SwipableMobileCarouselSlideBody, type SwipableMobileCarouselSlideBodyProps, SwipableMobileCarouselSlideFooter, type SwipableMobileCarouselSlideFooterProps, SwipableMobileCarouselSlideHeader, type SwipableMobileCarouselSlideHeaderProps, type SwipableMobileCarouselSlideProps, type SwipeDirection, type SwipeDirectionMeta, SwipeStack, SwipeStackCard, type SwipeStackCardProps, type SwipeStackProps, SystemBanner, type SystemBannerProps, THEME_PRESETS, THEME_PRESET_NAMES, type TabItem, Table, TableBody, TableCell, TableHead, TableHeaderCell, type TableProps, TableRow, Tabs, type TabsProps, TagInput, type TagInputProps, Textarea, type TextareaProps, type ThemePresetName, type ThemePresetTokens, ThreeColumnLayout, type ThreeColumnLayoutProps, type ToastContextValue, type ToastItem, ToastProvider, Toggle, type ToggleProps, Tooltip, type TooltipProps, Typography, type TypographyProps, type TypographyVariant, type UseCarouselRouteSyncOptions, type UseCarouselRouteSyncResult, type UseLongPressOptions, type UseReorderSensorsOptions, type UseResponsiveLayoutOptions, type UseResponsiveLayoutResult, type UseSnapCarouselOptions, type UseSnapCarouselResult, type UseSwipeRevealHandlers, type UseSwipeRevealOptions, type UseSwipeRevealResult, type UseSwipeStackHandlers, type UseSwipeStackOptions, type UseSwipeStackResult, UserMenu, type UserMenuItem, type UserMenuProps, shouldHandleDndEvent, useCarouselRouteSync, useCommitOnEnterOrBlur, useDoubleTapHandler, useIsMobile, useIsOffline, useLongPress, useOfflineTileState, useOverlaySecondRow, useReorderSensors, useResponsiveLayout, useSingleOrDoubleTap, useSnapCarousel, useSwipeReveal, useSwipeStack, useToast };