@sovereignfs/ui 0.45.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 (323) 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/LegalLinks.module.css +24 -0
  26. package/dist/Markdown.module.css +73 -0
  27. package/dist/Menu.module.css +1 -0
  28. package/dist/Message.module.css +1 -1
  29. package/dist/MessageScroller.module.css +12 -1
  30. package/dist/MobileAppsDrawer.module.css +82 -0
  31. package/dist/MobileFooter.module.css +73 -0
  32. package/dist/MobileHeader.module.css +76 -0
  33. package/dist/NavList.module.css +130 -0
  34. package/dist/NavTabs.module.css +1 -1
  35. package/dist/NotificationsPanel.module.css +258 -0
  36. package/dist/OverlayHeader.module.css +1 -1
  37. package/dist/PageContainer.module.css +82 -0
  38. package/dist/PageHeader.module.css +54 -0
  39. package/dist/PageLayout.module.css +51 -0
  40. package/dist/Popover.module.css +1 -1
  41. package/dist/QuantityStepper.module.css +1 -1
  42. package/dist/Resizable.module.css +3 -3
  43. package/dist/RootLayout.module.css +12 -0
  44. package/dist/SegmentedControl.module.css +1 -1
  45. package/dist/Select.module.css +1 -1
  46. package/dist/Sheet.module.css +4 -1
  47. package/dist/SplitPane.module.css +4 -4
  48. package/dist/StatusBadge.module.css +1 -1
  49. package/dist/StepStrip.module.css +53 -0
  50. package/dist/SuggestionInput.module.css +2 -2
  51. package/dist/SwipableMobileCarousel.module.css +64 -0
  52. package/dist/SwipableMobileCarouselDots.module.css +64 -0
  53. package/dist/SwipableMobileCarouselSlideParts.module.css +29 -0
  54. package/dist/SwipeStack.module.css +101 -0
  55. package/dist/SystemBanner.module.css +10 -0
  56. package/dist/Table.module.css +2 -2
  57. package/dist/Tabs.module.css +1 -1
  58. package/dist/TagInput.module.css +2 -2
  59. package/dist/Textarea.module.css +9 -1
  60. package/dist/ThreeColumnLayout.module.css +35 -0
  61. package/dist/Toast.module.css +62 -3
  62. package/dist/Tooltip.module.css +1 -1
  63. package/dist/UserMenu.module.css +90 -0
  64. package/dist/index.d.ts +1680 -30
  65. package/dist/index.js +4618 -1443
  66. package/dist/tokens/primitives.css +36 -0
  67. package/dist/tokens/semantic.css +32 -0
  68. package/dist/tokens/theme-presets.css +33 -0
  69. package/package.json +32 -12
  70. package/src/__tests__/package-json.test.ts +8 -0
  71. package/src/components/Accordion/Accordion.module.css +1 -1
  72. package/src/components/Alert/Alert.module.css +1 -1
  73. package/src/components/AppsLauncher/AppsLauncher.module.css +96 -0
  74. package/src/components/AppsLauncher/AppsLauncher.stories.tsx +58 -0
  75. package/src/components/AppsLauncher/AppsLauncher.tsx +117 -0
  76. package/src/components/AppsLauncher/__tests__/AppsLauncher.test.tsx +52 -0
  77. package/src/components/Avatar/Avatar.module.css +1 -1
  78. package/src/components/Badge/Badge.module.css +30 -7
  79. package/src/components/Badge/Badge.stories.tsx +16 -4
  80. package/src/components/Badge/Badge.tsx +8 -11
  81. package/src/components/Badge/__tests__/Badge.test.tsx +4 -2
  82. package/src/components/BalanceChip/BalanceChip.module.css +1 -1
  83. package/src/components/Button/Button.module.css +18 -2
  84. package/src/components/Card/Card.module.css +1 -1
  85. package/src/components/CardTile/CardTile.module.css +181 -0
  86. package/src/components/CardTile/CardTile.stories.tsx +86 -0
  87. package/src/components/CardTile/CardTile.tsx +128 -0
  88. package/src/components/CardTile/__tests__/CardTile.test.tsx +56 -0
  89. package/src/components/CodeTextarea/CodeTextarea.module.css +1 -1
  90. package/src/components/Collapsible/Collapsible.module.css +1 -1
  91. package/src/components/ColorPicker/ColorPicker.module.css +132 -0
  92. package/src/components/ColorPicker/ColorPicker.stories.tsx +80 -0
  93. package/src/components/ColorPicker/ColorPicker.tsx +157 -0
  94. package/src/components/ColorPicker/__tests__/ColorPicker.test.tsx +117 -0
  95. package/src/components/Combobox/Combobox.module.css +2 -2
  96. package/src/components/Command/Command.module.css +1 -1
  97. package/src/components/ConfirmDialog/ConfirmDialog.module.css +2 -2
  98. package/src/components/ConfirmDialog/ConfirmDialog.tsx +28 -2
  99. package/src/components/ConfirmDialog/__tests__/ConfirmDialog.test.tsx +71 -3
  100. package/src/components/ConsentPrompt/ConsentPrompt.module.css +21 -0
  101. package/src/components/ConsentPrompt/ConsentPrompt.stories.tsx +31 -0
  102. package/src/components/ConsentPrompt/ConsentPrompt.tsx +66 -0
  103. package/src/components/ContextMenu/ContextMenu.tsx +1 -1
  104. package/src/components/DatePicker/DatePicker.module.css +1 -1
  105. package/src/components/DeviceOnlyGate/DeviceOnlyGate.tsx +58 -0
  106. package/src/components/DeviceOnlyGate/__tests__/DeviceOnlyGate.test.tsx +45 -0
  107. package/src/components/DeviceStorageKeyGate/DeviceStorageKeyGate.tsx +100 -0
  108. package/src/components/DeviceStorageKeyGate/__tests__/DeviceStorageKeyGate.test.tsx +119 -0
  109. package/src/components/Dialog/Dialog.module.css +130 -21
  110. package/src/components/Dialog/Dialog.stories.tsx +179 -2
  111. package/src/components/Dialog/Dialog.tsx +137 -94
  112. package/src/components/Dialog/__tests__/Dialog.test.tsx +190 -9
  113. package/src/components/DragHandleRow/DragHandleRow.tsx +2 -21
  114. package/src/components/Drawer/Drawer.module.css +36 -7
  115. package/src/components/Drawer/Drawer.stories.tsx +44 -0
  116. package/src/components/Drawer/Drawer.tsx +27 -66
  117. package/src/components/Drawer/__tests__/Drawer.test.tsx +55 -6
  118. package/src/components/GripIcon/GripIcon.tsx +27 -0
  119. package/src/components/Header/Header.module.css +62 -0
  120. package/src/components/Header/Header.stories.tsx +452 -0
  121. package/src/components/Header/Header.tsx +102 -0
  122. package/src/components/Header/__tests__/Header.test.tsx +104 -0
  123. package/src/components/HeaderFooterLayout/HeaderFooterLayout.module.css +21 -0
  124. package/src/components/HeaderFooterLayout/HeaderFooterLayout.stories.tsx +111 -0
  125. package/src/components/HeaderFooterLayout/HeaderFooterLayout.tsx +54 -0
  126. package/src/components/HeaderFooterLayout/__tests__/HeaderFooterLayout.test.tsx +58 -0
  127. package/src/components/Icon/icons/arrow-left-right.tsx +23 -0
  128. package/src/components/Icon/icons/bold.tsx +20 -0
  129. package/src/components/Icon/icons/calendar.tsx +4 -4
  130. package/src/components/Icon/icons/carrot.tsx +3 -3
  131. package/src/components/Icon/icons/circle-chevron-left.tsx +21 -0
  132. package/src/components/Icon/icons/code.tsx +21 -0
  133. package/src/components/Icon/icons/copy.tsx +21 -0
  134. package/src/components/Icon/icons/credit-card.tsx +21 -0
  135. package/src/components/Icon/icons/database.tsx +22 -0
  136. package/src/components/Icon/icons/download.tsx +22 -0
  137. package/src/components/Icon/icons/file-text.tsx +24 -0
  138. package/src/components/Icon/icons/folder-closed.tsx +21 -0
  139. package/src/components/Icon/icons/folder-open.tsx +20 -0
  140. package/src/components/Icon/icons/folder.tsx +20 -0
  141. package/src/components/Icon/icons/folders.tsx +21 -0
  142. package/src/components/Icon/icons/hat-glasses.tsx +24 -0
  143. package/src/components/Icon/icons/history.tsx +22 -0
  144. package/src/components/Icon/icons/inbox.tsx +21 -0
  145. package/src/components/Icon/icons/index.ts +169 -1
  146. package/src/components/Icon/icons/italic.tsx +22 -0
  147. package/src/components/Icon/icons/layers.tsx +22 -0
  148. package/src/components/Icon/icons/layout-dashboard.tsx +23 -0
  149. package/src/components/Icon/icons/layout-grid.tsx +23 -0
  150. package/src/components/Icon/icons/link.tsx +21 -0
  151. package/src/components/Icon/icons/list-ordered.tsx +25 -0
  152. package/src/components/Icon/icons/list.tsx +25 -0
  153. package/src/components/Icon/icons/luggage.tsx +24 -0
  154. package/src/components/Icon/icons/map-pin.tsx +21 -0
  155. package/src/components/Icon/icons/menu.tsx +22 -0
  156. package/src/components/Icon/icons/minus.tsx +20 -0
  157. package/src/components/Icon/icons/paint-bucket.tsx +23 -0
  158. package/src/components/Icon/icons/panel-left.tsx +21 -0
  159. package/src/components/Icon/icons/pin.tsx +21 -0
  160. package/src/components/Icon/icons/rectangle-ellipsis.tsx +23 -0
  161. package/src/components/Icon/icons/refresh-cw.tsx +23 -0
  162. package/src/components/Icon/icons/rotate-cw.tsx +21 -0
  163. package/src/components/Icon/icons/route.tsx +22 -0
  164. package/src/components/Icon/icons/send.tsx +21 -0
  165. package/src/components/Icon/icons/share-2.tsx +24 -0
  166. package/src/components/Icon/icons/sheet.tsx +24 -0
  167. package/src/components/Icon/icons/smartphone.tsx +21 -0
  168. package/src/components/Icon/icons/square-kanban.tsx +23 -0
  169. package/src/components/Icon/icons/table.tsx +23 -0
  170. package/src/components/Icon/icons/user-round-plus.tsx +23 -0
  171. package/src/components/Icon/icons/users.tsx +23 -0
  172. package/src/components/IconPicker/IconPicker.module.css +1 -1
  173. package/src/components/Input/Input.module.css +1 -1
  174. package/src/components/Input/Input.tsx +8 -2
  175. package/src/components/Kbd/Kbd.module.css +1 -1
  176. package/src/components/LegalLinks/LegalLinks.module.css +24 -0
  177. package/src/components/LegalLinks/LegalLinks.stories.tsx +22 -0
  178. package/src/components/LegalLinks/LegalLinks.tsx +40 -0
  179. package/src/components/Markdown/Markdown.module.css +73 -0
  180. package/src/components/Markdown/Markdown.stories.tsx +40 -0
  181. package/src/components/Markdown/Markdown.tsx +305 -0
  182. package/src/components/Markdown/__tests__/Markdown.test.tsx +144 -0
  183. package/src/components/Menu/Menu.module.css +1 -0
  184. package/src/components/Menu/Menu.tsx +72 -22
  185. package/src/components/Menu/__tests__/Menu.test.tsx +30 -0
  186. package/src/components/Menubar/Menubar.tsx +1 -1
  187. package/src/components/Message/Message.module.css +1 -1
  188. package/src/components/MessageScroller/MessageScroller.module.css +12 -1
  189. package/src/components/MessageScroller/MessageScroller.tsx +12 -0
  190. package/src/components/MobileAppsDrawer/MobileAppsDrawer.module.css +82 -0
  191. package/src/components/MobileAppsDrawer/MobileAppsDrawer.tsx +78 -0
  192. package/src/components/MobileAppsDrawer/__tests__/MobileAppsDrawer.test.tsx +80 -0
  193. package/src/components/MobileFooter/MobileFooter.module.css +73 -0
  194. package/src/components/MobileFooter/MobileFooter.stories.tsx +47 -0
  195. package/src/components/MobileFooter/MobileFooter.tsx +122 -0
  196. package/src/components/MobileFooter/__tests__/MobileFooter.test.tsx +129 -0
  197. package/src/components/MobileHeader/MobileHeader.module.css +76 -0
  198. package/src/components/MobileHeader/MobileHeader.stories.tsx +57 -0
  199. package/src/components/MobileHeader/MobileHeader.tsx +90 -0
  200. package/src/components/MobileHeader/__tests__/MobileHeader.test.tsx +113 -0
  201. package/src/components/NavList/NavList.module.css +130 -0
  202. package/src/components/NavList/NavList.tsx +136 -0
  203. package/src/components/NavList/__tests__/NavList.test.tsx +109 -0
  204. package/src/components/NavTabs/NavTabs.module.css +1 -1
  205. package/src/components/NavTabs/NavTabs.tsx +39 -11
  206. package/src/components/NotificationsPanel/NotificationsPanel.module.css +258 -0
  207. package/src/components/NotificationsPanel/NotificationsPanel.stories.tsx +61 -0
  208. package/src/components/NotificationsPanel/NotificationsPanel.tsx +187 -0
  209. package/src/components/NotificationsPanel/__tests__/NotificationsPanel.test.tsx +78 -0
  210. package/src/components/OfflineGate/OfflineGate.tsx +44 -0
  211. package/src/components/OfflineGate/__tests__/OfflineGate.test.tsx +66 -0
  212. package/src/components/OverlayHeader/OverlayHeader.module.css +1 -1
  213. package/src/components/OverlayHeader/OverlayHeader.tsx +19 -4
  214. package/src/components/OverlayHeader/__tests__/OverlayHeader.test.tsx +18 -0
  215. package/src/components/PageContainer/PageContainer.module.css +82 -0
  216. package/src/components/PageContainer/PageContainer.tsx +64 -0
  217. package/src/components/PageContainer/__tests__/PageContainer.test.tsx +70 -0
  218. package/src/components/PageHeader/PageHeader.module.css +54 -0
  219. package/src/components/PageHeader/PageHeader.tsx +157 -2
  220. package/src/components/PageHeader/__tests__/PageHeader.test.tsx +103 -0
  221. package/src/components/PageLayout/PageLayout.module.css +51 -0
  222. package/src/components/PageLayout/PageLayout.stories.tsx +73 -0
  223. package/src/components/PageLayout/PageLayout.tsx +51 -0
  224. package/src/components/PageLayout/__tests__/PageLayout.test.tsx +34 -0
  225. package/src/components/Popover/Popover.module.css +1 -1
  226. package/src/components/Popover/Popover.tsx +86 -4
  227. package/src/components/Popover/__tests__/Popover.test.tsx +165 -0
  228. package/src/components/QuantityStepper/QuantityStepper.module.css +1 -1
  229. package/src/components/Resizable/Resizable.module.css +3 -3
  230. package/src/components/ResponsiveSurface/ResponsiveSurface.tsx +24 -0
  231. package/src/components/ResponsiveSurface/__tests__/ResponsiveSurface.test.tsx +73 -0
  232. package/src/components/RootLayout/RootLayout.module.css +12 -0
  233. package/src/components/RootLayout/RootLayout.stories.tsx +125 -0
  234. package/src/components/RootLayout/RootLayout.tsx +185 -0
  235. package/src/components/RootLayout/__tests__/RootLayout.test.tsx +161 -0
  236. package/src/components/SegmentedControl/SegmentedControl.module.css +1 -1
  237. package/src/components/Select/Select.module.css +1 -1
  238. package/src/components/Sheet/Sheet.module.css +4 -1
  239. package/src/components/Sheet/Sheet.tsx +14 -56
  240. package/src/components/SplitPane/SplitPane.module.css +4 -4
  241. package/src/components/StatusBadge/StatusBadge.module.css +1 -1
  242. package/src/components/StepStrip/StepStrip.module.css +53 -0
  243. package/src/components/StepStrip/StepStrip.tsx +74 -0
  244. package/src/components/SuggestionInput/SuggestionInput.module.css +2 -2
  245. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.module.css +64 -0
  246. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.tsx +243 -0
  247. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlide.tsx +35 -0
  248. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideBody.tsx +42 -0
  249. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideFooter.tsx +18 -0
  250. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideHeader.tsx +21 -0
  251. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideParts.module.css +29 -0
  252. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarousel.test.tsx +214 -0
  253. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarouselDevGuard.test.tsx +61 -0
  254. package/src/components/SwipableMobileCarousel/context.ts +13 -0
  255. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.module.css +64 -0
  256. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.tsx +73 -0
  257. package/src/components/SwipableMobileCarouselDots/__tests__/SwipableMobileCarouselDots.test.tsx +63 -0
  258. package/src/components/SwipeStack/SwipeStack.module.css +101 -0
  259. package/src/components/SwipeStack/SwipeStack.tsx +199 -0
  260. package/src/components/SwipeStack/SwipeStackCard.tsx +22 -0
  261. package/src/components/SwipeStack/__tests__/SwipeStack.test.tsx +169 -0
  262. package/src/components/SystemBanner/SystemBanner.module.css +10 -0
  263. package/src/components/Table/Table.module.css +2 -2
  264. package/src/components/Tabs/Tabs.module.css +1 -1
  265. package/src/components/TagInput/TagInput.module.css +2 -2
  266. package/src/components/Textarea/Textarea.module.css +9 -1
  267. package/src/components/Textarea/Textarea.tsx +28 -5
  268. package/src/components/Textarea/__tests__/Textarea.test.tsx +23 -1
  269. package/src/components/ThreeColumnLayout/ThreeColumnLayout.module.css +35 -0
  270. package/src/components/ThreeColumnLayout/ThreeColumnLayout.stories.tsx +152 -0
  271. package/src/components/ThreeColumnLayout/ThreeColumnLayout.tsx +87 -0
  272. package/src/components/ThreeColumnLayout/__tests__/ThreeColumnLayout.test.tsx +78 -0
  273. package/src/components/Toast/Toast.module.css +62 -3
  274. package/src/components/Toast/Toast.stories.tsx +1 -1
  275. package/src/components/Tooltip/Tooltip.module.css +1 -1
  276. package/src/components/UserMenu/UserMenu.module.css +90 -0
  277. package/src/components/UserMenu/UserMenu.stories.tsx +49 -0
  278. package/src/components/UserMenu/UserMenu.tsx +132 -0
  279. package/src/components/UserMenu/__tests__/UserMenu.test.tsx +77 -0
  280. package/src/hooks/__tests__/useCarouselRouteSync.test.tsx +126 -0
  281. package/src/hooks/__tests__/useIsOffline.test.tsx +53 -0
  282. package/src/hooks/__tests__/useOfflineTileState.test.tsx +69 -0
  283. package/src/hooks/__tests__/usePublishShellChromeHeight.test.tsx +118 -0
  284. package/src/hooks/__tests__/useReorderSensors.test.ts +26 -0
  285. package/src/hooks/__tests__/useResponsiveLayout.test.tsx +87 -0
  286. package/src/hooks/__tests__/useSnapCarousel.test.tsx +175 -0
  287. package/src/hooks/__tests__/useSwipeReveal.test.tsx +110 -0
  288. package/src/hooks/__tests__/useSwipeStack.test.tsx +155 -0
  289. package/src/hooks/index.ts +27 -0
  290. package/src/hooks/useCarouselRouteSync.ts +92 -0
  291. package/src/hooks/useIsOffline.ts +41 -0
  292. package/src/hooks/useOfflineTileState.ts +45 -0
  293. package/src/hooks/usePublishShellChromeHeight.ts +96 -0
  294. package/src/hooks/useReorderSensors.ts +88 -0
  295. package/src/hooks/useResponsiveLayout.ts +36 -0
  296. package/src/hooks/useSnapCarousel.ts +284 -0
  297. package/src/hooks/useSwipeReveal.ts +107 -0
  298. package/src/hooks/useSwipeStack.ts +235 -0
  299. package/src/index.ts +124 -3
  300. package/src/overlay-shell.ts +159 -0
  301. package/src/stories/DesignSystemOverview.stories.tsx +933 -6
  302. package/src/stories/DeviceOnlyGate.stories.tsx +35 -0
  303. package/src/stories/DeviceStorageKeyGate.stories.tsx +57 -0
  304. package/src/stories/GripIcon.stories.tsx +29 -0
  305. package/src/stories/InteractionHooks.stories.tsx +483 -0
  306. package/src/stories/LayoutSystem.stories.tsx +639 -0
  307. package/src/stories/MenuEntries.stories.tsx +86 -0
  308. package/src/stories/MobilePatterns.stories.tsx +247 -2
  309. package/src/stories/NavList.stories.tsx +147 -0
  310. package/src/stories/NavTabs.stories.tsx +18 -0
  311. package/src/stories/OfflineGate.stories.tsx +42 -0
  312. package/src/stories/PageContainer.stories.tsx +82 -0
  313. package/src/stories/PageHeader.stories.tsx +65 -1
  314. package/src/stories/ResponsiveSurface.stories.tsx +47 -0
  315. package/src/stories/StepStrip.stories.tsx +76 -0
  316. package/src/stories/SwipableMobileCarousel.stories.tsx +362 -0
  317. package/src/stories/SwipeStack.stories.tsx +200 -0
  318. package/src/stories/Textarea.stories.tsx +12 -0
  319. package/src/stories/TokenGallery.stories.tsx +115 -0
  320. package/src/tokens/primitives.css +36 -0
  321. package/src/tokens/semantic.css +32 -0
  322. package/src/tokens/theme-presets.css +33 -0
  323. package/src/tokens/theme-presets.ts +72 -0
package/dist/index.d.ts CHANGED
@@ -1,13 +1,96 @@
1
1
  import * as react from 'react';
2
- import { ReactNode, ButtonHTMLAttributes, SelectHTMLAttributes, ReactElement, CSSProperties, InputHTMLAttributes, TextareaHTMLAttributes, HTMLAttributes, TdHTMLAttributes, ThHTMLAttributes, LabelHTMLAttributes, ElementType, PointerEvent, KeyboardEvent, MouseEvent } 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';
4
+
5
+ interface LegalLinksProps {
6
+ privacyHref?: string;
7
+ tosHref?: string;
8
+ /** Renders a linked item. Defaults to a plain `<a href>`, which causes a
9
+ * full page reload — pass Next's `<Link>` (or equivalent) to keep
10
+ * navigation client-side. Not needed for a full-reload navigation away
11
+ * from a standalone auth page, but matters if this is ever mounted inside
12
+ * an SPA-like shell. */
13
+ renderLink?: (href: string, label: string) => ReactNode;
14
+ className?: string;
15
+ }
16
+ declare function LegalLinks({ privacyHref, tosHref, renderLink, className, }: LegalLinksProps): react.JSX.Element;
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
+
49
+ interface MarkdownProps {
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. */
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;
71
+ className?: string;
72
+ }
73
+ /** Renders a constrained markdown subset (see MarkdownProps) as styled React
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;
3
83
 
4
84
  type BadgeVariant = 'role' | 'status' | 'mono';
5
- type BadgeSize = 'sm' | 'md' | 'lg';
85
+ type BadgeSize = 'xs' | 'sm' | 'md' | 'lg';
6
86
  type BadgeStatus = 'active' | 'enabled' | 'deactivated' | 'failed' | 'invited' | 'pending' | 'neutral';
7
87
  interface BadgeProps {
8
88
  variant?: BadgeVariant;
9
- /** 'sm' | 'md' (default) | 'lg'. 'md' is the badge's original — and until
10
- * 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. */
11
94
  size?: BadgeSize;
12
95
  /** Only relevant when variant="status" — determines the dot colour. */
13
96
  status?: BadgeStatus;
@@ -25,12 +108,12 @@ interface BadgeProps {
25
108
  * - `status` tinted chip with leading colour dot — for Active / Deactivated / etc.
26
109
  * - `mono` monospace font, neutral surface — for platform / community / v0.1.0
27
110
  *
28
- * Three sizes (`sm`/`md`/`lg`, default `md`). ALL CAPS by default
111
+ * Four sizes (`xs`/`sm`/`md`/`lg`, default `md`). ALL CAPS by default
29
112
  * (`uppercase`) — set `uppercase={false}` for a title-case badge instead.
30
113
  */
31
114
  declare function Badge({ variant, size, status, uppercase, children, }: BadgeProps): react.JSX.Element;
32
115
 
33
- type IconName = 'house' | 'settings' | 'log-out' | 'chevron-right' | 'chevron-left' | 'chevron-down' | 'chevron-up' | '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';
34
117
 
35
118
  /** Decorative icon — visually meaningful but described by surrounding text. */
36
119
  type DecorativeProps = {
@@ -177,6 +260,17 @@ interface PopoverProps {
177
260
  * regardless of CSS module load order, unlike passing an extra className.
178
261
  */
179
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;
180
274
  'aria-label': string;
181
275
  children: ReactNode;
182
276
  }
@@ -203,7 +297,7 @@ interface PopoverProps {
203
297
  *
204
298
  * Closes on outside click or Escape. Does not trap focus (it is non-modal).
205
299
  */
206
- 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;
207
301
 
208
302
  type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'destructive';
209
303
  type ButtonSize = 'sm' | 'md' | 'lg';
@@ -222,7 +316,13 @@ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
222
316
  */
223
317
  declare function Button({ variant, size, type, loading, disabled, className, children, ...rest }: ButtonProps): react.JSX.Element;
224
318
 
225
- 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
+ };
226
326
  /**
227
327
  * Input — the primitive text field. Presentational and RSC-safe: it forwards
228
328
  * all native input props to the underlying `<input>`. Styling references
@@ -230,14 +330,23 @@ type InputProps = InputHTMLAttributes<HTMLInputElement>;
230
330
  */
231
331
  declare function Input({ type, className, ...rest }: InputProps): react.JSX.Element;
232
332
 
233
- 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
+ }
234
342
  /**
235
343
  * Textarea — the primitive multi-line text field. Presentational and
236
- * 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
237
346
  * `<textarea>`. Styling references `--sv-*` tokens via CSS Modules; there
238
347
  * are no hardcoded values.
239
348
  */
240
- declare function Textarea({ className, rows, ...rest }: TextareaProps): react.JSX.Element;
349
+ declare function Textarea({ className, rows, autoGrow, ...rest }: TextareaProps): react.JSX.Element;
241
350
 
242
351
  interface CodeTextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
243
352
  invalid?: boolean;
@@ -308,11 +417,13 @@ declare function TagInput({ value, onChange, id, name, placeholder, disabled, re
308
417
  /**
309
418
  * Lets content deep inside a `Dialog` (e.g. a plugin's own route layout,
310
419
  * rendered several levels below wherever the `Dialog` itself is
311
- * instantiated) supply the second-row content of the Dialog's mobile
312
- * `OverlayHeader` — typically a tab strip. Solves the "double header"
313
- * problem: without this, a plugin's own tab strip has no way to reach the
314
- * Dialog's header and ends up rendered a second time, as its own sticky bar,
315
- * 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.
316
427
  *
317
428
  * A no-op when there is no enclosing `Dialog` (e.g. the same plugin layout
318
429
  * also rendered on a plain, non-overlay route) — safe to call unconditionally.
@@ -329,7 +440,7 @@ declare function TagInput({ value, onChange, id, name, placeholder, disabled, re
329
440
  * ```
330
441
  */
331
442
  declare function useOverlaySecondRow(node: ReactNode | null): boolean;
332
- type DialogSize = 'sm' | 'md' | 'lg' | 'full';
443
+ type DialogSize = 'sm' | 'md' | 'lg' | 'auto' | 'fixed';
333
444
  interface DialogProps {
334
445
  /** Whether the dialog is shown. When false, nothing renders. */
335
446
  open: boolean;
@@ -337,11 +448,42 @@ interface DialogProps {
337
448
  onClose: () => void;
338
449
  /** Panel size on desktop. Mobile always renders as a full-screen sheet. */
339
450
  size?: DialogSize;
340
- /** 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. */
341
456
  'aria-label'?: string;
342
- /** On mobile: shown in the top bar alongside the close button so the title
343
- * 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. */
344
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;
345
487
  children: ReactNode;
346
488
  }
347
489
  /**
@@ -359,8 +501,14 @@ interface DialogProps {
359
501
  * `onClose` API is unchanged — closing still stays mounted internally for the
360
502
  * exit transition before actually unmounting; `prefers-reduced-motion: reduce`
361
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.
362
510
  */
363
- 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;
364
512
 
365
513
  interface DrawerProps {
366
514
  /** Whether the drawer is shown. When false, nothing renders. */
@@ -374,6 +522,12 @@ interface DrawerProps {
374
522
  * "half screen or less" convention for Drawer, this is the only other
375
523
  * supported size; taller content should use `Sheet` instead. */
376
524
  snapHeight?: 'content' | 'half';
525
+ /** Renders a built-in `OverlayHeader` (title + close) below the grab
526
+ * handle. Omit when the content supplies its own header, or none is
527
+ * needed at all — e.g. the mobile shell's Apps drawer, whose grab handle
528
+ * and swipe-down/scrim-tap dismissal are enough on their own. Mirrors
529
+ * `Sheet`'s identical `title` prop. */
530
+ title?: string;
377
531
  children: ReactNode;
378
532
  }
379
533
  /**
@@ -398,13 +552,17 @@ interface DrawerProps {
398
552
  * scroll, the same reasoning behind the tasks plugin's edge-zone-only
399
553
  * swipe-to-reveal technique.
400
554
  */
401
- declare function Drawer({ open, onClose, 'aria-label': ariaLabel, snapHeight, children, }: DrawerProps): react.JSX.Element | null;
555
+ declare function Drawer({ open, onClose, 'aria-label': ariaLabel, snapHeight, title, children, }: DrawerProps): react.JSX.Element | null;
402
556
 
403
557
  interface OverlayHeaderProps {
404
558
  /** Overlay title, shown between the optional back button and the trailing
405
559
  * slots. Optional — some consumers (e.g. `Dialog`'s mobile bar) need the
406
- * row's close button present even when no title applies. */
407
- 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;
408
566
  /** Always renders a close button; called on click. */
409
567
  onClose: () => void;
410
568
  /** When provided, renders a back-chevron button before the title (for
@@ -416,6 +574,15 @@ interface OverlayHeaderProps {
416
574
  /** A second row below the title row — e.g. a tab strip. */
417
575
  secondRow?: ReactNode;
418
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;
419
586
  }
420
587
  /**
421
588
  * OverlayHeader — the shared fixed secondary header for `Dialog`'s mobile
@@ -431,7 +598,7 @@ interface OverlayHeaderProps {
431
598
  * component — render its own header row instead; `Sheet`'s `title` prop is
432
599
  * optional specifically to leave that escape hatch open.
433
600
  */
434
- 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;
435
602
 
436
603
  interface SheetProps {
437
604
  /** Whether the sheet is shown. When false, nothing renders. */
@@ -526,7 +693,16 @@ declare function ConfirmDialog({ open, onClose, title, message, onConfirm, confi
526
693
  interface MenuItem {
527
694
  type?: 'item';
528
695
  label: string;
529
- 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;
530
706
  icon?: IconName;
531
707
  /** Styles the item as a destructive action (e.g. "Delete list"). */
532
708
  destructive?: boolean;
@@ -562,6 +738,15 @@ interface MenuProps {
562
738
  /** Forwarded to `Popover` on desktop. Has no effect on mobile, where the
563
739
  * menu is always a full-width `Drawer`. */
564
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';
565
750
  }
566
751
  /**
567
752
  * Menu — an adaptive action menu: `Popover` on desktop, a bottom-sheet
@@ -592,7 +777,148 @@ declare function MenuEntries({ items, onSelect, }: {
592
777
  /** Called after an item's own onSelect — typically the surface's onClose. */
593
778
  onSelect: (entry: MenuItem) => void;
594
779
  }): react.JSX.Element;
595
- 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;
596
922
 
597
923
  interface ToastItem {
598
924
  id: string;
@@ -624,6 +950,64 @@ interface CardProps extends HTMLAttributes<HTMLElement> {
624
950
  }
625
951
  declare function Card({ as: Tag, interactive, padding, className, children, ...rest }: CardProps): react.JSX.Element;
626
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
+
627
1011
  /** Props to spread onto the field's actual form control. */
628
1012
  interface FormFieldRenderProps {
629
1013
  id: string;
@@ -654,10 +1038,252 @@ declare function FormField({ label, hint, error, id, required, className, childr
654
1038
  interface PageHeaderProps {
655
1039
  title: string;
656
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
+ */
657
1051
  action?: ReactNode;
658
1052
  className?: string;
1053
+ /** Heading level for the title. Defaults to `1` for standalone use; pass
1054
+ * `2` or `3` when the page already sits under a shell/plugin `<h1>`, to
1055
+ * avoid a duplicate top-level heading. Visual style is unchanged at every
1056
+ * level — only the rendered tag changes. Applies on both breakpoints. */
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;
659
1068
  }
660
- declare function PageHeader({ title, description, action, className }: 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;
1077
+
1078
+ interface PageContainerProps extends HTMLAttributes<HTMLDivElement> {
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
+ */
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';
1096
+ children: ReactNode;
1097
+ }
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;
1162
+
1163
+ interface MobileHeaderProps extends HTMLAttributes<HTMLDivElement> {
1164
+ /** The brand/logo element — already a complete, clickable link home (e.g. an
1165
+ * instance logo wrapped in the consumer's own router `Link`). Always
1166
+ * rendered. `MobileHeader` stays router-agnostic, so this is provided
1167
+ * fully built rather than as a bare icon + href. Optional — omit it to get
1168
+ * a default "S" badge (matching the runtime shell's own fallback brand
1169
+ * icon when no instance logo is configured), sized and styled to the same
1170
+ * 36px/radius-md convention a custom logo is expected to follow. */
1171
+ logo?: ReactNode;
1172
+ /** Optional contextual title rendered beside the logo (e.g. the active
1173
+ * plugin's name). Absent by default — this is the one overridable part of
1174
+ * the header. See RFC 0088. */
1175
+ title?: string;
1176
+ /** Notification bell — always rendered; not overridable.
1177
+ * TODO: this is just an icon slot today (the consumer wires up its own
1178
+ * click handler/content) — it doesn't yet accommodate a full notification
1179
+ * feature (unread badge, dropdown panel, etc. — see the runtime shell's
1180
+ * own NotificationBell). Deferred; revisit once a plugin actually needs
1181
+ * more than a bare bell icon here. */
1182
+ bell: ReactNode;
1183
+ /** Avatar / account menu trigger — always rendered; not overridable. */
1184
+ avatarMenu: ReactNode;
1185
+ }
1186
+ /**
1187
+ * The mobile header bar: brand/logo (always shown), an optional contextual
1188
+ * title, and a fixed bell + avatar-menu cluster. Owns its own chrome —
1189
+ * background, border-bottom, sticky positioning, safe-area-aware padding,
1190
+ * and a 768px max-width (so it never stretches full-bleed if mounted outside
1191
+ * an actual mobile viewport) — matching the runtime shell's own mobile
1192
+ * header exactly, since this component is meant to replace that hand-rolled
1193
+ * markup. Presentational only — no data fetching; the consumer supplies
1194
+ * `bell`/`avatarMenu` (and, optionally, `logo`) as already-wired components
1195
+ * (their own sizing — 36px logo/avatar, 44px bell tap target — is the
1196
+ * consumer's responsibility, matching the reference implementation in the
1197
+ * runtime shell). See RFC 0088 for the immutable/overridable boundary this
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).
1206
+ */
1207
+ declare function MobileHeader({ logo, title, bell, avatarMenu, className, ...rest }: MobileHeaderProps): react.JSX.Element;
1208
+
1209
+ interface FooterIcon {
1210
+ icon: ReactNode;
1211
+ label: string;
1212
+ href?: string;
1213
+ onClick?: () => void;
1214
+ active?: boolean;
1215
+ }
1216
+ interface MobileFooterProps extends HTMLAttributes<HTMLElement> {
1217
+ /** Opens the app drawer/launcher. Always rendered as the centered slot;
1218
+ * not overridable. */
1219
+ onOpenApps: () => void;
1220
+ /** Custom launcher icon (e.g. a plugin-supplied image). Defaults to a
1221
+ * generic grid icon. */
1222
+ launcherIcon?: ReactNode;
1223
+ /** Whether the launcher's own drawer is currently open (applies the
1224
+ * pressed/active visual state). */
1225
+ launcherOpen?: boolean;
1226
+ /** 1 or 2 icons rendered to the left of the centered launcher. */
1227
+ leftIcons: FooterIcon[];
1228
+ /** 1 or 2 icons rendered to the right of the centered launcher. Must match
1229
+ * `leftIcons.length` — the launcher stays visually centered, so a mismatch
1230
+ * is flagged (dev-mode only, never thrown) rather than silently allowed. */
1231
+ rightIcons: FooterIcon[];
1232
+ }
1233
+ /**
1234
+ * The mobile footer bar: a centered, fixed "Apps" launcher flanked by 1 or 2
1235
+ * overridable icons on each side (3 or 5 total, matching standard
1236
+ * iOS/Android bottom-nav conventions). Owns its own chrome — background,
1237
+ * border-top, safe-area-aware bottom padding, and a 768px max-width (so it
1238
+ * never stretches full-bleed if mounted outside an actual mobile viewport)
1239
+ * — matching the runtime shell's own mobile footer (MobileNav) exactly,
1240
+ * since this component is meant to replace that hand-rolled markup.
1241
+ * Presentational only — no data fetching; the consumer owns the
1242
+ * drawer/overlay `onOpenApps` opens. See RFC 0088 for the
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).
1251
+ */
1252
+ declare function MobileFooter({ onOpenApps, launcherIcon, launcherOpen, leftIcons, rightIcons, className, ...rest }: MobileFooterProps): react.JSX.Element;
1253
+
1254
+ interface MobileAppsDrawerItem {
1255
+ /** Stable identity for this tile — used as the React key. */
1256
+ key: string;
1257
+ icon: ReactNode;
1258
+ label: string;
1259
+ /** Renders an `<a>` when set; otherwise a `<button>` calling `onClick`. */
1260
+ href?: string;
1261
+ onClick?: () => void;
1262
+ }
1263
+ interface MobileAppsDrawerProps {
1264
+ open: boolean;
1265
+ onClose: () => void;
1266
+ /** Accessible name for the drawer panel — required since there's no
1267
+ * visible title to fall back to (Drawer's grab handle plus swipe-down /
1268
+ * scrim-tap already cover dismissal, so no header row is rendered). */
1269
+ 'aria-label': string;
1270
+ /** The grid tiles — supplied by the consumer (e.g. installed plugins,
1271
+ * a plugin's own sections). MobileAppsDrawer owns only the drawer
1272
+ * chrome/grid layout, never the item list itself. */
1273
+ items: MobileAppsDrawerItem[];
1274
+ }
1275
+ /**
1276
+ * The mobile "Apps" drawer: a bottom sheet with a 3-column grid of icon
1277
+ * tiles — same tile size (56px, radius 14px) and grid layout as the runtime
1278
+ * shell's own Apps drawer (MobileNav's Drawer content), generalized so the
1279
+ * tile list comes from the consumer (the shell passes installed plugins; a
1280
+ * plugin composing its own MobileFooter launcher passes whatever its own
1281
+ * "apps" are, e.g. a section index) rather than being hardcoded to plugins
1282
+ * specifically. No header row (title/close button) — Drawer's own grab
1283
+ * handle plus swipe-down/scrim-tap dismissal are enough, and a header ate
1284
+ * into the limited vertical space a launcher grid needs most.
1285
+ */
1286
+ declare function MobileAppsDrawer({ open, onClose, items, ...rest }: MobileAppsDrawerProps): react.JSX.Element;
661
1287
 
662
1288
  interface EmptyStateProps {
663
1289
  icon?: IconName;
@@ -668,6 +1294,121 @@ interface EmptyStateProps {
668
1294
  }
669
1295
  declare function EmptyState({ icon, heading, description, action, className }: EmptyStateProps): react.JSX.Element;
670
1296
 
1297
+ interface OfflineGateProps {
1298
+ children: ReactNode;
1299
+ /** Defaults to a generic "this section" phrasing — pass the surface's own name. */
1300
+ surfaceName?: string;
1301
+ className?: string;
1302
+ }
1303
+ /**
1304
+ * OfflineGate — blocks administrative/settings surfaces from rendering
1305
+ * (possibly stale) cached content while the device has no network, showing an
1306
+ * explanatory empty state instead (research 0012, epic task 2.32).
1307
+ *
1308
+ * Distinct from `OfflineBanner`: the banner is an informational overlay that
1309
+ * coexists with normal content everywhere in the shell. This is a hard block
1310
+ * for surfaces where operating against stale data is actively wrong — e.g. a
1311
+ * Console user list or an Account billing page reflects a point-in-time
1312
+ * snapshot the moment it's server-rendered, and any cached copy replayed
1313
+ * later has no way to signal that it may already be stale. `OfflineGate`
1314
+ * doesn't try to tell staleness apart from freshness; it removes the
1315
+ * question by not rendering the content at all while offline.
1316
+ *
1317
+ * `children` is rendered unconditionally while online, so this adds no cost
1318
+ * to the common case — it only decides what to show, never how the wrapped
1319
+ * content itself is fetched or cached.
1320
+ */
1321
+ declare function OfflineGate({ children, surfaceName, className }: OfflineGateProps): react.JSX.Element;
1322
+
1323
+ interface DeviceOnlyGateProps {
1324
+ children: ReactNode;
1325
+ /** Defaults to a generic "this app" phrasing — pass the plugin's own name. */
1326
+ surfaceName?: string;
1327
+ /**
1328
+ * The caller's own `isDeviceOnlyTierAvailable()` result (from
1329
+ * `@sovereignfs/sdk/device-client`) — taken as a plain boolean rather than
1330
+ * computed inside this component, so `@sovereignfs/ui` never depends on
1331
+ * `@sovereignfs/sdk` (this package must stay usable standalone, outside the
1332
+ * plugin runtime — RFC 0073).
1333
+ */
1334
+ available: boolean;
1335
+ className?: string;
1336
+ }
1337
+ /**
1338
+ * DeviceOnlyGate — blocks a `device-only`-tier plugin's content from
1339
+ * rendering on a surface that cannot provide the durable, encrypted,
1340
+ * device-auth-gated store that tier requires, showing an explanatory empty
1341
+ * state instead of a broken screen (research 0012, epic tasks 2.33 + 3.36).
1342
+ *
1343
+ * A `device-only` plugin wraps its own root content in this the same way
1344
+ * Console and Account wrap theirs in `OfflineGate` — an opt-in pattern each
1345
+ * surface applies to itself, not a platform-level route gate. The launcher
1346
+ * tile's own "Phone only" badge (`useOfflineTileState`) is advisory UI on top
1347
+ * of this; this component is the actual gate, since a user can always reach a
1348
+ * route directly (a bookmark, a deep link) without passing through the
1349
+ * launcher tile at all.
1350
+ *
1351
+ * **Not a security boundary.** Availability here is a capability signal, not
1352
+ * an authorization check — the real protection for `device-only` data is
1353
+ * that it is encrypted and the key requires device auth to release (epic task
1354
+ * 1.22), so it stays inaccessible regardless of whether this gate is present,
1355
+ * bypassed, or simply never reached (e.g. a hand-crafted request against the
1356
+ * plugin's own API routes).
1357
+ */
1358
+ declare function DeviceOnlyGate({ children, surfaceName, available, className, }: DeviceOnlyGateProps): react.JSX.Element;
1359
+
1360
+ /**
1361
+ * `'checking'` covers the moment before the caller's own async status check
1362
+ * resolves — same transitional-state pattern `EncryptionSection`'s local
1363
+ * `LocalState` uses, so this gate never flashes an empty state before the
1364
+ * real answer is known. `'no-device-auth'` is the hard-block case (RFC 0093
1365
+ * §5, epic task 1.22): the environment supports the tier, but this device
1366
+ * has no passcode, fingerprint, or face unlock configured, so a key cannot
1367
+ * be created here at all — distinct from `'not-set-up'`, where it can.
1368
+ */
1369
+ type DeviceStorageKeyGateStatus = 'checking' | 'unsupported' | 'no-device-auth' | 'not-set-up' | 'set-up';
1370
+ interface DeviceStorageKeyGateProps {
1371
+ children: ReactNode;
1372
+ /** Defaults to a generic "This app" phrasing — pass the plugin's own name. */
1373
+ surfaceName?: string;
1374
+ /**
1375
+ * The caller's own `getDeviceStorageKeyStatus()` result (from
1376
+ * `@sovereignfs/sdk/device-only-storage`) — taken as a plain status rather
1377
+ * than computed inside this component, so `@sovereignfs/ui` never depends
1378
+ * on `@sovereignfs/sdk` (same boundary `DeviceOnlyGate`'s `available` prop
1379
+ * draws — this package must stay usable standalone, outside the plugin
1380
+ * runtime — RFC 0073).
1381
+ */
1382
+ status: DeviceStorageKeyGateStatus;
1383
+ /**
1384
+ * Rendered under the "not set up" message — typically a link to Account →
1385
+ * Security. Not built in here: this package depends on no router, so the
1386
+ * caller supplies its own navigable element (a plain `<a>`, a framework
1387
+ * `<Link>`, whatever the host app uses).
1388
+ */
1389
+ setupAction?: ReactNode;
1390
+ className?: string;
1391
+ }
1392
+ /**
1393
+ * DeviceStorageKeyGate — blocks a `device-only`-tier plugin's content until
1394
+ * the user has set up their Device Storage Key (RFC 0093 §2, epic task
1395
+ * 1.22). Distinct from `DeviceOnlyGate`: that one checks whether the *tier
1396
+ * itself* is available on this surface (native shell, secure-storage bridge
1397
+ * present); this one checks whether the user has actually completed the
1398
+ * one-time, per-device enrollment that tier depends on. A `device-only`
1399
+ * plugin typically wants both — `DeviceOnlyGate` outermost (no point
1400
+ * checking enrollment on a surface that cannot offer the tier at all), this
1401
+ * gate inside it.
1402
+ *
1403
+ * Enrollment is centralized and decoupled from any single plugin (RFC 0093
1404
+ * §2): a plugin that finds no key set up does not run its own enrollment
1405
+ * ceremony inline. It stops here and points the user at Account → Security —
1406
+ * the one place enrollment happens for every `device-only` plugin on this
1407
+ * device — via `setupAction`, the same opt-in, self-applied pattern
1408
+ * `OfflineGate`/`DeviceOnlyGate` already use for their own surfaces.
1409
+ */
1410
+ declare function DeviceStorageKeyGate({ children, surfaceName, status, setupAction, className, }: DeviceStorageKeyGateProps): react.JSX.Element | null;
1411
+
671
1412
  interface SpinnerProps {
672
1413
  size?: 'sm' | 'md' | 'lg';
673
1414
  label?: string;
@@ -688,12 +1429,25 @@ interface NavTabItem {
688
1429
  href: string;
689
1430
  active?: boolean;
690
1431
  }
1432
+ /** Props to spread onto a consumer-supplied link element — keeps NavTabs' own
1433
+ * class names and a11y attributes in sync with whatever the consumer renders. */
1434
+ interface NavTabLinkProps {
1435
+ href: string;
1436
+ className: string;
1437
+ 'aria-current': 'page' | undefined;
1438
+ children: ReactNode;
1439
+ }
691
1440
  interface NavTabsProps {
692
1441
  items: NavTabItem[];
693
1442
  className?: string;
694
1443
  'aria-label'?: string;
1444
+ /** Render a tab as something other than a plain `<a href>` — e.g. Next's
1445
+ * `<Link replace>` inside an overlay-shell plugin, where a full page
1446
+ * navigation would break the dialog's history contract. Receives the item
1447
+ * plus the class name/aria attributes NavTabs would otherwise apply. */
1448
+ renderLink?: (item: NavTabItem, linkProps: NavTabLinkProps) => ReactNode;
695
1449
  }
696
- declare function NavTabs({ items, className, 'aria-label': ariaLabel }: NavTabsProps): react.JSX.Element;
1450
+ declare function NavTabs({ items, className, 'aria-label': ariaLabel, renderLink }: NavTabsProps): react.JSX.Element;
697
1451
 
698
1452
  interface TooltipProps {
699
1453
  content: string;
@@ -1043,6 +1797,17 @@ interface MessageScrollerProps {
1043
1797
  * content does not yank them back down — a "New messages" button appears
1044
1798
  * instead, matching the pattern every chat product (Slack, Discord,
1045
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.
1046
1811
  */
1047
1812
  declare function MessageScroller({ children, className }: MessageScrollerProps): react.JSX.Element;
1048
1813
 
@@ -1313,6 +2078,48 @@ interface DragHandleRowProps extends HTMLAttributes<HTMLDivElement> {
1313
2078
  */
1314
2079
  declare function DragHandleRow({ children, handleProps, isDragging, className, ...rest }: DragHandleRowProps): react.JSX.Element;
1315
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
+
1316
2123
  interface FileDropzoneProps {
1317
2124
  /** Native `<input type="file">` `name` attribute — set this to submit the
1318
2125
  * file as part of a native `<form action={...}>` (Server Action) request. */
@@ -1461,6 +2268,63 @@ interface IconPickerProps {
1461
2268
  */
1462
2269
  declare function IconPicker({ value, onChange, options, 'aria-label': ariaLabel, triggerLabel, disabled, className, }: IconPickerProps): react.JSX.Element;
1463
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
+
1464
2328
  interface QuantityStepperProps {
1465
2329
  value: number;
1466
2330
  onChange: (value: number) => void;
@@ -1711,6 +2575,57 @@ declare const MOBILE_BREAKPOINT_PX = 768;
1711
2575
  */
1712
2576
  declare function useIsMobile(breakpointPx?: number): boolean;
1713
2577
 
2578
+ /**
2579
+ * useIsOffline — whether the browser currently has no network connection.
2580
+ *
2581
+ * SSR-safe: always initialises to `false` (online) so the server-rendered HTML
2582
+ * matches the first client render, then reads the real `navigator.onLine`
2583
+ * value in `useEffect`. This picks up the case where the page loaded already
2584
+ * offline (e.g. served from the service-worker cache) at the cost of an
2585
+ * imperceptible one-frame delay before the offline state appears — the same
2586
+ * trade-off `OfflineBanner` makes, which this hook was extracted from so every
2587
+ * consumer shares one connectivity source instead of re-deriving it slightly
2588
+ * differently (research 0012, epic task 2.32).
2589
+ *
2590
+ * Reflects only `navigator.onLine` — true whenever the OS reports a network
2591
+ * interface is up, even without real upstream connectivity (e.g. Wi-Fi with no
2592
+ * internet). That is a known limitation of the browser API itself, not of this
2593
+ * hook; there is currently no better cross-browser signal available.
2594
+ */
2595
+ declare function useIsOffline(): boolean;
2596
+
2597
+ /**
2598
+ * The two reasons an app tile can be non-interactive, kept structurally
2599
+ * distinct because they have different causes and must never read as the same
2600
+ * thing to a user (research 0012, epic task 2.33):
2601
+ *
2602
+ * - `'connectivity-dimmed'` — a no-offline-tier app, dimmed only while the
2603
+ * device is **actually offline right now**. Reactive and temporary; clears
2604
+ * the instant connectivity returns.
2605
+ * - `'capability-restricted'` — a `device-only` app on a surface without the
2606
+ * durable, encrypted, device-auth-gated store it needs. Static and
2607
+ * unrelated to connectivity — it stays restricted even when fully online,
2608
+ * and must never say "offline" to a user who plainly isn't.
2609
+ */
2610
+ type OfflineTileState = 'connectivity-dimmed' | 'capability-restricted' | null;
2611
+ /**
2612
+ * Which of the two states, if any, applies to an app tile given its declared
2613
+ * offline tier.
2614
+ *
2615
+ * `deviceOnlyAvailable` is the caller's own
2616
+ * `isDeviceOnlyTierAvailable()` result (from
2617
+ * `@sovereignfs/sdk/device-client`) — deliberately taken as a plain boolean
2618
+ * parameter rather than computed inside this hook, so `@sovereignfs/ui` never
2619
+ * depends on `@sovereignfs/sdk` (this package must stay usable standalone,
2620
+ * outside the plugin runtime — RFC 0073).
2621
+ *
2622
+ * An `offline-first` app is never restricted by either state: that tier's
2623
+ * whole point is working with no network, so it stays fully interactive both
2624
+ * online and offline. A `device-only` app that *is* available behaves the
2625
+ * same way — the restriction is about availability, not connectivity.
2626
+ */
2627
+ declare function useOfflineTileState(offline: 'offline-first' | 'device-only' | undefined, deviceOnlyAvailable: boolean): OfflineTileState;
2628
+
1714
2629
  interface CommitOnEnterOrBlurHandlers {
1715
2630
  onKeyDown: (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
1716
2631
  onBlur: () => void;
@@ -1739,4 +2654,739 @@ interface CommitOnEnterOrBlurHandlers {
1739
2654
  */
1740
2655
  declare function useCommitOnEnterOrBlur(onCommit: () => void): CommitOnEnterOrBlurHandlers;
1741
2656
 
1742
- 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, Dialog, type DialogProps, type DialogSize, DragHandleRow, type DragHandleRowProps, Drawer, type DrawerProps, EmptyState, type EmptyStateProps, FileDropzone, type FileDropzoneProps, 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, type LongPressHandlers, MOBILE_BREAKPOINT_PX, 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, type NavTabItem, NavTabs, type NavTabsProps, NavigationMenu, type NavigationMenuItem, type NavigationMenuProps, OverlayHeader, type OverlayHeaderProps, 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, 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, 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 UseLongPressOptions, useCommitOnEnterOrBlur, useDoubleTapHandler, useIsMobile, useLongPress, useOverlaySecondRow, useSingleOrDoubleTap, useToast };
2657
+ interface UseSwipeRevealOptions {
2658
+ /** Max reveal distance in px — the row translates by `-revealWidth` when open. */
2659
+ revealWidth: number;
2660
+ /** Whether the reveal is currently open. Controlled by the caller so a
2661
+ * list of rows can coordinate "only one open at a time" — this hook has
2662
+ * no open state of its own. */
2663
+ open: boolean;
2664
+ /** Called when a drag releases past the halfway point — the caller should
2665
+ * set `open` to true. */
2666
+ onOpen: () => void;
2667
+ /** Called when a drag releases before the halfway point — the caller
2668
+ * should set `open` to false. */
2669
+ onClose: () => void;
2670
+ /** Skip entirely (hooks can't be called conditionally). */
2671
+ disabled?: boolean;
2672
+ }
2673
+ interface UseSwipeRevealHandlers {
2674
+ onPointerDown: (e: PointerEvent) => void;
2675
+ onPointerMove: (e: PointerEvent) => void;
2676
+ onPointerUp: (e: PointerEvent) => void;
2677
+ onPointerCancel: (e: PointerEvent) => void;
2678
+ }
2679
+ interface UseSwipeRevealResult {
2680
+ /** Attach to the swipeable row element — the hook writes a live transform
2681
+ * to it directly during the drag (not via React state) so the row tracks
2682
+ * the finger at 60fps with no re-render per pointermove. */
2683
+ rowRef: RefObject<HTMLDivElement | null>;
2684
+ /** Spread onto the row's pointer event handlers. */
2685
+ handlers: UseSwipeRevealHandlers;
2686
+ }
2687
+ /**
2688
+ * useSwipeReveal — horizontal swipe-to-reveal (e.g. Done/Delete actions
2689
+ * behind a list row), extracted from `sovereign-tasks`'s `TaskItem`/
2690
+ * `ListSidebar`, which independently hand-rolled the identical gesture twice
2691
+ * with only `revealWidth` differing (RFC 0079, epic task 9.20).
2692
+ *
2693
+ * Axis-locks on the first 8px of movement (so a vertical scroll or the
2694
+ * carousel's own horizontal swipe-between-slides gesture isn't hijacked by a
2695
+ * diagonal drag) and only resolves to open/closed on release, past the
2696
+ * halfway point of `revealWidth`.
2697
+ */
2698
+ declare function useSwipeReveal({ revealWidth, open, onOpen, onClose, disabled, }: UseSwipeRevealOptions): UseSwipeRevealResult;
2699
+
2700
+ interface UseSnapCarouselOptions {
2701
+ /** Total number of slides — settle detection clamps to this range. */
2702
+ itemCount: number;
2703
+ /** Called when the user's scroll gesture settles on a different slide
2704
+ * index than the last one reported. */
2705
+ onSettle?: (index: number) => void;
2706
+ /** Debounce delay (ms) after the last `scroll` event before checking where
2707
+ * the container settled. Default 120 — matches the value this hook was
2708
+ * extracted from. Debounced rather than keyed to the `scrollend` event,
2709
+ * which pre-17.4 iOS Safari/WKWebView doesn't support. */
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;
2719
+ }
2720
+ interface UseSnapCarouselResult {
2721
+ /** Attach to the `scroll-snap-type: x` scroll container. */
2722
+ scrollRef: RefObject<HTMLDivElement | null>;
2723
+ /** Imperatively scrolls the container to a slide index. */
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;
2730
+ }
2731
+ /**
2732
+ * useSnapCarousel — debounced "settled slide" detection over a native
2733
+ * `scroll-snap-type: x` container, extracted from `sovereign-tasks`'s
2734
+ * `MobileTasksCarousel` and independently reimplemented in
2735
+ * `sovereign-shopper`'s `MobileShopperCarousel` (RFC 0079, epic task 9.20).
2736
+ * Gives swipe-between-slides physics for free via native scroll-snap, with
2737
+ * this hook only handling "which slide did we land on."
2738
+ */
2739
+ declare function useSnapCarousel({ itemCount, onSettle, debounceMs, initialIndex, }: UseSnapCarouselOptions): UseSnapCarouselResult;
2740
+
2741
+ interface UseResponsiveLayoutOptions<TWeb, TMobile> {
2742
+ web: TWeb;
2743
+ mobile: TMobile;
2744
+ breakpointPx?: number;
2745
+ }
2746
+ interface UseResponsiveLayoutResult<TWeb, TMobile> {
2747
+ isMobile: boolean;
2748
+ value: TWeb | TMobile;
2749
+ }
2750
+ /**
2751
+ * useResponsiveLayout — picks between a `web` and `mobile` value for the
2752
+ * current viewport, built on `useIsMobile` (same breakpoint/SSR-safe-default
2753
+ * behavior, not reimplemented here). Generic over the value type so it works
2754
+ * for JSX (the common case — forking an entire component tree, not just a
2755
+ * class name) or any other per-breakpoint value a plugin wants to pick
2756
+ * without repeating the isMobile-ternary boilerplate every call site.
2757
+ *
2758
+ * This formalizes the `if (isMobile) return <mobile/>; return <web/>;` fork
2759
+ * plugins have hand-rolled per-plugin (e.g. a `MobileAwareShell` component
2760
+ * that swaps an entire routed page tree for a client-only mobile one) —
2761
+ * see `ResponsiveSurface` for the equivalent as a plain JSX component.
2762
+ */
2763
+ declare function useResponsiveLayout<TWeb, TMobile>({ web, mobile, breakpointPx, }: UseResponsiveLayoutOptions<TWeb, TMobile>): UseResponsiveLayoutResult<TWeb, TMobile>;
2764
+
2765
+ interface UseCarouselRouteSyncOptions {
2766
+ /** Maps the current pathname to a slide index — the caller's own routing
2767
+ * logic (e.g. special-casing a virtual "starred" slide), unchanged from
2768
+ * whatever a plugin already has today. This hook has no idea what a
2769
+ * plugin's routes look like, by design — it never imports a router. */
2770
+ indexForPathname: (pathname: string) => number;
2771
+ /** Inverse mapping — given a settled slide index, the path to navigate to. */
2772
+ pathForIndex: (index: number) => string;
2773
+ /** The current pathname. The caller reads this via their own router (e.g.
2774
+ * `usePathname()` from `next/navigation`) and passes it in every render —
2775
+ * this package stays framework-generic and has zero runtime dependencies. */
2776
+ pathname: string;
2777
+ /** Called when this hook wants to navigate — typically
2778
+ * `(path) => router.replace(path, { scroll: false })`. */
2779
+ onNavigate: (path: string) => void;
2780
+ }
2781
+ interface UseCarouselRouteSyncResult {
2782
+ /** Feed directly into SwipableMobileCarousel's `activeIndex` prop. */
2783
+ activeIndex: number;
2784
+ /** Feed directly into SwipableMobileCarousel's `onSettle` prop. */
2785
+ onSettle: (index: number) => void;
2786
+ }
2787
+ /**
2788
+ * useCarouselRouteSync — centralizes the pathname↔slide-index mapping and the
2789
+ * "was this pathname change our own settle, or an external navigation"
2790
+ * distinction that carousel-driving plugins otherwise hand-roll per plugin
2791
+ * (a tapped `<Link>`, browser back/forward, vs. this hook's own
2792
+ * `router.replace` after a swipe settles). Router-agnostic on purpose: the
2793
+ * caller owns the actual `usePathname()`/`router.replace()` calls and only
2794
+ * hands this hook plain values/callbacks.
2795
+ *
2796
+ * Deliberately does not own neighbor-prefetch (SwipableMobileCarousel's
2797
+ * `prefetchDistance`/mount-window covers that) or scroll mechanics (the
2798
+ * carousel component reacts to `activeIndex` changes itself) — this hook is
2799
+ * pathname↔index mapping only, keeping routing glue decoupled from
2800
+ * data-fetching and DOM scrolling.
2801
+ */
2802
+ declare function useCarouselRouteSync({ indexForPathname, pathForIndex, pathname, onNavigate, }: UseCarouselRouteSyncOptions): UseCarouselRouteSyncResult;
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
+
2887
+ interface ResponsiveSurfaceProps {
2888
+ web: ReactNode;
2889
+ mobile: ReactNode;
2890
+ breakpointPx?: number;
2891
+ }
2892
+ /**
2893
+ * ResponsiveSurface — thin JSX convenience wrapper around
2894
+ * `useResponsiveLayout` for the common two-tree case: render an entirely
2895
+ * different component tree below the breakpoint, not a CSS squeeze of the
2896
+ * same one. Renders only whichever side is active — the other tree is never
2897
+ * mounted.
2898
+ *
2899
+ * This does not replace a plugin's own shell component (e.g. a
2900
+ * `MobileAwareShell` that also threads plugin-specific props like a refresh
2901
+ * signal) — those stay a thin per-plugin wrapper around this.
2902
+ */
2903
+ declare function ResponsiveSurface({ web, mobile, breakpointPx }: ResponsiveSurfaceProps): react.JSX.Element;
2904
+
2905
+ interface SwipableMobileCarouselDotsProps {
2906
+ count: number;
2907
+ activeIndex: number;
2908
+ onJump: (index: number) => void;
2909
+ /** Per-dot accessible names, e.g. ["Lists", "Starred", "Groceries"]. Falls
2910
+ * back to "Slide N of count" for any index without one. */
2911
+ labels?: (string | undefined)[];
2912
+ /** Labels the whole group — required, no generic fallback (mirrors
2913
+ * SwipableMobileCarousel's own required aria-label). */
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';
2923
+ className?: string;
2924
+ }
2925
+ /**
2926
+ * SwipableMobileCarouselDots — a real, tappable, labeled slide indicator.
2927
+ * Standalone (not carousel-only): reusable anywhere a set of positions needs
2928
+ * a dot indicator (e.g. an image gallery, an onboarding stepper), and is also
2929
+ * SwipableMobileCarousel's default `renderIndicator`.
2930
+ *
2931
+ * Replaces the `aria-hidden`, non-interactive dots pattern both
2932
+ * sovereign-tasks and sovereign-shopper currently hand-roll — every dot here
2933
+ * is a real `role="tab"` button with its own accessible name, reachable by
2934
+ * keyboard. No roving tabIndex/arrow-key handling: `Tabs` (this library's
2935
+ * other `role="tablist"` component) has none either, so this stays
2936
+ * consistent with it rather than gold-plating past its sibling.
2937
+ */
2938
+ declare function SwipableMobileCarouselDots({ count, activeIndex, onJump, labels, 'aria-label': ariaLabel, density, className, }: SwipableMobileCarouselDotsProps): react.JSX.Element;
2939
+
2940
+ interface SwipableMobileCarouselIndicatorProps {
2941
+ count: number;
2942
+ activeIndex: number;
2943
+ labels: (string | undefined)[];
2944
+ onJump: (index: number) => void;
2945
+ }
2946
+ interface SwipableMobileCarouselProps {
2947
+ /** Controlled active slide index — the caller owns this (typically via
2948
+ * useCarouselRouteSync, or plain useState). */
2949
+ activeIndex: number;
2950
+ /** Called when a swipe gesture settles on a different index, or when the
2951
+ * reorder-jump fix re-snaps after the active slide's position changes.
2952
+ * The caller is responsible for updating `activeIndex` in response. */
2953
+ onSettle: (index: number) => void;
2954
+ /** How many slides on each side of the active one stay mounted. Default 1
2955
+ * matches both sovereign-tasks' and sovereign-shopper's existing "swipe
2956
+ * never shows a spinner" behavior. Slides outside this window keep their
2957
+ * DOM slot (so scroll-snap's position-based indexing stays correct) but
2958
+ * their children are not mounted at all. */
2959
+ prefetchDistance?: number;
2960
+ /** Passed straight through to the internal useSnapCarousel. */
2961
+ settleDebounceMs?: number;
2962
+ /** Required — labels the scroller region for assistive tech. No generic
2963
+ * fallback, since one would be wrong for every actual consumer. */
2964
+ 'aria-label': string;
2965
+ /** Renders the indicator. Defaults to SwipableMobileCarouselDots. Pass
2966
+ * `null` to render no indicator at all. */
2967
+ renderIndicator?: null | ((props: SwipableMobileCarouselIndicatorProps) => ReactNode);
2968
+ className?: string;
2969
+ /** Must be SwipableMobileCarouselSlide elements (nullish/boolean children
2970
+ * are safely skipped for conditional slides). A dev-mode warning is
2971
+ * logged for any other child type — see resolveSlides below. */
2972
+ children: ReactNode;
2973
+ }
2974
+ /**
2975
+ * SwipableMobileCarousel — a compound component for swiping between full-
2976
+ * width slides (each an independent route/view on mobile), wrapping
2977
+ * useSnapCarousel. This library's first compound component: every other
2978
+ * component here is flat/prop-based, but slide content is large, arbitrary,
2979
+ * per-plugin subtrees that need a header-known/body-loading split an
2980
+ * array-of-objects prop would only express with worse JSX ergonomics.
2981
+ *
2982
+ * Owns rendering and mount-window mechanics only — it has no opinion on
2983
+ * where slide data lives. Do NOT: (a) aggregate cross-slide data inside a
2984
+ * SwipableMobileCarouselSlideBody (that recomputes on every slide render
2985
+ * regardless of which slide is active — belongs in the parent, which
2986
+ * already knows every slide exists); (b) mount a detail overlay (Sheet,
2987
+ * Dialog) inside a Slide's children — mount it as a sibling of
2988
+ * SwipableMobileCarousel instead, controlled by the same state that would
2989
+ * otherwise drive a routed page's overlay. sovereign-tasks' current
2990
+ * hand-rolled carousel does both and is measurably laggier than
2991
+ * sovereign-shopper's equivalent, which keeps its overlay in the routed pane.
2992
+ */
2993
+ declare function SwipableMobileCarousel({ activeIndex, onSettle, prefetchDistance, settleDebounceMs, 'aria-label': ariaLabel, renderIndicator, className, children, }: SwipableMobileCarouselProps): react.JSX.Element;
2994
+
2995
+ interface SwipableMobileCarouselSlideProps {
2996
+ /** Stable identity for this slide, independent of its position among
2997
+ * siblings — required. This is what makes SwipableMobileCarousel's
2998
+ * reorder-jump fix possible: a plain array index can't distinguish "this
2999
+ * slide moved to position 2" from "this slide was removed and a
3000
+ * different one is now at position 2." Reuse whatever id the caller
3001
+ * already keys their `.map()` on (e.g. a list's own id). */
3002
+ slideKey: string;
3003
+ /** Accessible label surfaced to the default dots indicator (e.g.
3004
+ * "Groceries"). Falls back to "Slide N of count" if omitted — omitting it
3005
+ * logs a dev-mode warning, since every real slide usually has a title
3006
+ * available synchronously already. */
3007
+ label?: string;
3008
+ /** SwipableMobileCarouselSlideHeader/Body/Footer, in any order/subset. */
3009
+ children: ReactNode;
3010
+ }
3011
+ /**
3012
+ * SwipableMobileCarouselSlide — a single slide of a SwipableMobileCarousel.
3013
+ * Renders its children only while within the carousel's mount window (the
3014
+ * active slide ± its configured prefetchDistance); outside that window it
3015
+ * renders nothing, matching both sovereign-tasks and sovereign-shopper's
3016
+ * existing "never fetch/render a non-neighbor slide" behavior, now
3017
+ * centralized instead of hand-rolled per plugin.
3018
+ */
3019
+ declare function SwipableMobileCarouselSlide({ children }: SwipableMobileCarouselSlideProps): react.JSX.Element | null;
3020
+
3021
+ interface SwipableMobileCarouselSlideHeaderProps {
3022
+ children: ReactNode;
3023
+ className?: string;
3024
+ }
3025
+ /**
3026
+ * SwipableMobileCarouselSlideHeader — always renders its children, no
3027
+ * loading concept. Meant for content already known synchronously (a list's
3028
+ * title, color, item count from data the caller already has) so it can
3029
+ * render immediately even while SwipableMobileCarouselSlideBody's own
3030
+ * content is still loading — see that component's doc comment.
3031
+ */
3032
+ declare function SwipableMobileCarouselSlideHeader({ children, className, }: SwipableMobileCarouselSlideHeaderProps): react.JSX.Element;
3033
+
3034
+ interface SwipableMobileCarouselSlideBodyProps {
3035
+ children: ReactNode;
3036
+ /** While true, renders `loadingFallback` INSTEAD OF children — scoped to
3037
+ * just this region, not the whole slide. This is what fixes the
3038
+ * "whole slide blanks out, title included, until its own fetch resolves"
3039
+ * bug: a caller renders `<SwipableMobileCarouselSlideHeader>` from
3040
+ * already-known metadata unconditionally, and gates only this component's
3041
+ * `loading` on the slower fetch — the natural way to compose
3042
+ * Header/Body/Footer as siblings already produces that behavior, instead
3043
+ * of gating the entire slide behind one boolean. */
3044
+ loading?: boolean;
3045
+ loadingFallback?: ReactNode;
3046
+ className?: string;
3047
+ }
3048
+ /**
3049
+ * SwipableMobileCarouselSlideBody — the scrollable region of a slide.
3050
+ *
3051
+ * Deliberately does not set `touch-action: pan-y` on its scroll container
3052
+ * (see SwipableMobileCarouselSlideParts.module.css's `.body` rule) — that
3053
+ * would intersect-to-empty against the carousel's own horizontal
3054
+ * touch-action handling (docs/architecture-rules.md's touch-action
3055
+ * intersection rule), breaking both the vertical scroll here and the
3056
+ * horizontal swipe between slides.
3057
+ */
3058
+ declare function SwipableMobileCarouselSlideBody({ children, loading, loadingFallback, className, }: SwipableMobileCarouselSlideBodyProps): react.JSX.Element;
3059
+
3060
+ interface SwipableMobileCarouselSlideFooterProps {
3061
+ children: ReactNode;
3062
+ className?: string;
3063
+ }
3064
+ /**
3065
+ * SwipableMobileCarouselSlideFooter — always renders its children, no
3066
+ * loading concept. See SwipableMobileCarouselSlideHeader's doc comment.
3067
+ */
3068
+ declare function SwipableMobileCarouselSlideFooter({ children, className, }: SwipableMobileCarouselSlideFooterProps): react.JSX.Element;
3069
+
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 };