@devalok/shilp-sutra 0.56.0 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. package/MIGRATION.md +198 -0
  2. package/dist/_chunks/badge-group.js +75 -174
  3. package/dist/_chunks/badge-group.js.map +1 -1
  4. package/dist/_chunks/chat.js +270 -253
  5. package/dist/_chunks/chat.js.map +1 -1
  6. package/dist/_chunks/document-preview.js +1 -1
  7. package/dist/_chunks/document-preview.js.map +1 -1
  8. package/dist/_chunks/emoji-suggestion.js +1 -1
  9. package/dist/_chunks/emoji-suggestion.js.map +1 -1
  10. package/dist/_chunks/image-preview.js +71 -70
  11. package/dist/_chunks/image-preview.js.map +1 -1
  12. package/dist/_chunks/mention-suggestion.js +2 -2
  13. package/dist/_chunks/mention-suggestion.js.map +1 -1
  14. package/dist/_chunks/motion-preference.js +15 -0
  15. package/dist/_chunks/motion-preference.js.map +1 -0
  16. package/dist/_chunks/motion-provider.js +1 -1
  17. package/dist/_chunks/motion-provider.js.map +1 -1
  18. package/dist/_chunks/oauth-button.js +1 -1
  19. package/dist/_chunks/oauth-button.js.map +1 -1
  20. package/dist/_chunks/popover.js +50 -49
  21. package/dist/_chunks/popover.js.map +1 -1
  22. package/dist/_chunks/primitives-internal.js +29 -29
  23. package/dist/_chunks/primitives-internal.js.map +1 -1
  24. package/dist/_chunks/shared.js +48 -47
  25. package/dist/_chunks/shared.js.map +1 -1
  26. package/dist/_chunks/success.js +36 -36
  27. package/dist/_chunks/success.js.map +1 -1
  28. package/dist/_chunks/tree-view.js +1 -1
  29. package/dist/_chunks/tree-view.js.map +1 -1
  30. package/dist/_chunks/use-calendar.js +4 -4
  31. package/dist/_chunks/use-calendar.js.map +1 -1
  32. package/dist/ai/block-renderer.js +8 -8
  33. package/dist/ai/blocks/text.js +1 -1
  34. package/dist/ai/blocks/text.js.map +1 -1
  35. package/dist/ai/command-bar.js +67 -67
  36. package/dist/ai/command-bar.js.map +1 -1
  37. package/dist/ai/conversation.js +35 -35
  38. package/dist/ai/conversation.js.map +1 -1
  39. package/dist/ai/index.js +4 -4
  40. package/dist/composed/activity-feed.d.ts.map +1 -1
  41. package/dist/composed/activity-feed.js +109 -108
  42. package/dist/composed/activity-feed.js.map +1 -1
  43. package/dist/composed/avatar-group.d.ts +7 -2
  44. package/dist/composed/avatar-group.d.ts.map +1 -1
  45. package/dist/composed/avatar-group.js +3 -3
  46. package/dist/composed/avatar-group.js.map +1 -1
  47. package/dist/composed/command-palette.js +137 -137
  48. package/dist/composed/command-palette.js.map +1 -1
  49. package/dist/composed/content-card.js +2 -2
  50. package/dist/composed/content-card.js.map +1 -1
  51. package/dist/composed/date-picker/index.js +9 -9
  52. package/dist/composed/date-picker/index.js.map +1 -1
  53. package/dist/composed/diff.d.ts +23 -2
  54. package/dist/composed/diff.d.ts.map +1 -1
  55. package/dist/composed/diff.js +341 -260
  56. package/dist/composed/diff.js.map +1 -1
  57. package/dist/composed/emoji-picker.js +3 -3
  58. package/dist/composed/emoji-picker.js.map +1 -1
  59. package/dist/composed/empty-state.js +4 -4
  60. package/dist/composed/error-boundary.js +2 -2
  61. package/dist/composed/error-boundary.js.map +1 -1
  62. package/dist/composed/file-preview/image-preview.d.ts.map +1 -1
  63. package/dist/composed/file-preview/shared.d.ts.map +1 -1
  64. package/dist/composed/file-preview/video-preview.d.ts.map +1 -1
  65. package/dist/composed/file-preview.js +152 -151
  66. package/dist/composed/file-preview.js.map +1 -1
  67. package/dist/composed/filter-bar.d.ts.map +1 -1
  68. package/dist/composed/filter-bar.js +53 -52
  69. package/dist/composed/filter-bar.js.map +1 -1
  70. package/dist/composed/form-section.d.ts.map +1 -1
  71. package/dist/composed/form-section.js +38 -37
  72. package/dist/composed/form-section.js.map +1 -1
  73. package/dist/composed/inline-edit.js +1 -1
  74. package/dist/composed/inline-edit.js.map +1 -1
  75. package/dist/composed/loading-skeleton.js +3 -3
  76. package/dist/composed/loading-skeleton.js.map +1 -1
  77. package/dist/composed/master-detail.d.ts.map +1 -1
  78. package/dist/composed/master-detail.js +1 -1
  79. package/dist/composed/master-detail.js.map +1 -1
  80. package/dist/composed/member-picker.js +1 -1
  81. package/dist/composed/member-picker.js.map +1 -1
  82. package/dist/composed/multi-select-popover.d.ts.map +1 -1
  83. package/dist/composed/multi-select-popover.js +109 -108
  84. package/dist/composed/multi-select-popover.js.map +1 -1
  85. package/dist/composed/page-skeletons.js +4 -4
  86. package/dist/composed/page-skeletons.js.map +1 -1
  87. package/dist/composed/responsive-modal.js +1 -1
  88. package/dist/composed/responsive-modal.js.map +1 -1
  89. package/dist/composed/rich-chat-input/attachment-strip.d.ts.map +1 -1
  90. package/dist/composed/rich-chat-input/reply-banner.d.ts.map +1 -1
  91. package/dist/composed/rich-chat-input/schedule-send.d.ts.map +1 -1
  92. package/dist/composed/rich-chat-input.d.ts.map +1 -1
  93. package/dist/composed/rich-chat-input.js +473 -472
  94. package/dist/composed/rich-chat-input.js.map +1 -1
  95. package/dist/composed/rich-text-editor.js +6 -6
  96. package/dist/composed/rich-text-editor.js.map +1 -1
  97. package/dist/composed/schedule-view.js +5 -5
  98. package/dist/composed/schedule-view.js.map +1 -1
  99. package/dist/composed/status-badge.d.ts.map +1 -1
  100. package/dist/composed/status-badge.js +29 -28
  101. package/dist/composed/status-badge.js.map +1 -1
  102. package/dist/hooks/index.d.ts +1 -0
  103. package/dist/hooks/index.d.ts.map +1 -1
  104. package/dist/hooks/index.js +4 -3
  105. package/dist/hooks/use-container-size.d.ts +18 -0
  106. package/dist/hooks/use-container-size.d.ts.map +1 -0
  107. package/dist/hooks/use-container-size.js +28 -0
  108. package/dist/hooks/use-container-size.js.map +1 -0
  109. package/dist/motion/index.d.ts +1 -0
  110. package/dist/motion/index.d.ts.map +1 -1
  111. package/dist/motion/index.js +2 -15
  112. package/dist/motion/motion-preference.d.ts +36 -0
  113. package/dist/motion/motion-preference.d.ts.map +1 -0
  114. package/dist/motion/motion-provider.d.ts +2 -1
  115. package/dist/motion/motion-provider.d.ts.map +1 -1
  116. package/dist/motion/primitives-index.js +103 -102
  117. package/dist/motion/primitives-index.js.map +1 -1
  118. package/dist/motion/primitives.d.ts.map +1 -1
  119. package/dist/shell/app-shell.d.ts +101 -0
  120. package/dist/shell/app-shell.d.ts.map +1 -0
  121. package/dist/shell/app-shell.js +76 -0
  122. package/dist/shell/app-shell.js.map +1 -0
  123. package/dist/shell/bottom-navbar.js +21 -21
  124. package/dist/shell/bottom-navbar.js.map +1 -1
  125. package/dist/shell/index.d.ts +2 -1
  126. package/dist/shell/index.d.ts.map +1 -1
  127. package/dist/shell/index.js +6 -5
  128. package/dist/shell/notification-center.d.ts +17 -0
  129. package/dist/shell/notification-center.d.ts.map +1 -1
  130. package/dist/shell/notification-center.js +110 -105
  131. package/dist/shell/notification-center.js.map +1 -1
  132. package/dist/shell/notification-preferences.js +1 -1
  133. package/dist/shell/notification-preferences.js.map +1 -1
  134. package/dist/shell/top-bar.js +7 -7
  135. package/dist/shell/top-bar.js.map +1 -1
  136. package/dist/tokens/generate-scale.d.ts +49 -0
  137. package/dist/tokens/generate-scale.d.ts.map +1 -1
  138. package/dist/tokens/index.css +1 -0
  139. package/dist/tokens/palettes.css +292 -0
  140. package/dist/tokens/primitives.css +29 -26
  141. package/dist/tokens/semantic.css +170 -47
  142. package/dist/tokens/shilp-sutra.css +1 -0
  143. package/dist/tokens/utilities.css +10 -7
  144. package/dist/tokens/variants.css +1 -1
  145. package/dist/ui/accordion.d.ts.map +1 -1
  146. package/dist/ui/accordion.js +27 -26
  147. package/dist/ui/accordion.js.map +1 -1
  148. package/dist/ui/alert-dialog.d.ts.map +1 -1
  149. package/dist/ui/alert-dialog.js +60 -59
  150. package/dist/ui/alert-dialog.js.map +1 -1
  151. package/dist/ui/alert.d.ts.map +1 -1
  152. package/dist/ui/alert.js +55 -113
  153. package/dist/ui/alert.js.map +1 -1
  154. package/dist/ui/autocomplete.js +80 -80
  155. package/dist/ui/autocomplete.js.map +1 -1
  156. package/dist/ui/avatar.d.ts.map +1 -1
  157. package/dist/ui/avatar.js +71 -70
  158. package/dist/ui/avatar.js.map +1 -1
  159. package/dist/ui/badge-indicator.d.ts +4 -8
  160. package/dist/ui/badge-indicator.d.ts.map +1 -1
  161. package/dist/ui/badge-indicator.js +3 -8
  162. package/dist/ui/badge-indicator.js.map +1 -1
  163. package/dist/ui/badge.d.ts +55 -34
  164. package/dist/ui/badge.d.ts.map +1 -1
  165. package/dist/ui/banner.d.ts.map +1 -1
  166. package/dist/ui/banner.js +43 -41
  167. package/dist/ui/banner.js.map +1 -1
  168. package/dist/ui/button-group.d.ts.map +1 -1
  169. package/dist/ui/button-group.js +3 -23
  170. package/dist/ui/button-group.js.map +1 -1
  171. package/dist/ui/button.d.ts +10 -1
  172. package/dist/ui/button.d.ts.map +1 -1
  173. package/dist/ui/button.js +79 -212
  174. package/dist/ui/button.js.map +1 -1
  175. package/dist/ui/card.d.ts.map +1 -1
  176. package/dist/ui/card.js +78 -75
  177. package/dist/ui/card.js.map +1 -1
  178. package/dist/ui/charts/radar-chart.d.ts.map +1 -1
  179. package/dist/ui/charts/radar-chart.js +1 -1
  180. package/dist/ui/charts/radar-chart.js.map +1 -1
  181. package/dist/ui/chat/date-separator.d.ts +8 -1
  182. package/dist/ui/chat/date-separator.d.ts.map +1 -1
  183. package/dist/ui/chat/message-list.d.ts.map +1 -1
  184. package/dist/ui/chat/message.d.ts.map +1 -1
  185. package/dist/ui/chat/typing-indicator.d.ts.map +1 -1
  186. package/dist/ui/checkbox.js +1 -1
  187. package/dist/ui/checkbox.js.map +1 -1
  188. package/dist/ui/code.js +2 -2
  189. package/dist/ui/code.js.map +1 -1
  190. package/dist/ui/color-input.d.ts.map +1 -1
  191. package/dist/ui/color-input.js +151 -150
  192. package/dist/ui/color-input.js.map +1 -1
  193. package/dist/ui/combobox.d.ts +14 -0
  194. package/dist/ui/combobox.d.ts.map +1 -1
  195. package/dist/ui/combobox.js +156 -152
  196. package/dist/ui/combobox.js.map +1 -1
  197. package/dist/ui/context-menu.d.ts.map +1 -1
  198. package/dist/ui/context-menu.js +70 -69
  199. package/dist/ui/context-menu.js.map +1 -1
  200. package/dist/ui/data-table-body.d.ts +3 -1
  201. package/dist/ui/data-table-body.d.ts.map +1 -1
  202. package/dist/ui/data-table-body.js +93 -92
  203. package/dist/ui/data-table-body.js.map +1 -1
  204. package/dist/ui/data-table-bulk-actions.d.ts +7 -1
  205. package/dist/ui/data-table-bulk-actions.d.ts.map +1 -1
  206. package/dist/ui/data-table-bulk-actions.js +14 -8
  207. package/dist/ui/data-table-bulk-actions.js.map +1 -1
  208. package/dist/ui/data-table-card.d.ts.map +1 -1
  209. package/dist/ui/data-table-card.js +66 -47
  210. package/dist/ui/data-table-card.js.map +1 -1
  211. package/dist/ui/data-table-context.d.ts +4 -0
  212. package/dist/ui/data-table-context.d.ts.map +1 -1
  213. package/dist/ui/data-table-context.js +2 -2
  214. package/dist/ui/data-table-context.js.map +1 -1
  215. package/dist/ui/data-table-header.d.ts.map +1 -1
  216. package/dist/ui/data-table-header.js +50 -46
  217. package/dist/ui/data-table-header.js.map +1 -1
  218. package/dist/ui/data-table-pagination.js +3 -3
  219. package/dist/ui/data-table-pagination.js.map +1 -1
  220. package/dist/ui/data-table-toolbar.d.ts +11 -1
  221. package/dist/ui/data-table-toolbar.d.ts.map +1 -1
  222. package/dist/ui/data-table-toolbar.js +7 -7
  223. package/dist/ui/data-table-toolbar.js.map +1 -1
  224. package/dist/ui/data-table.d.ts +52 -5
  225. package/dist/ui/data-table.d.ts.map +1 -1
  226. package/dist/ui/data-table.js +181 -169
  227. package/dist/ui/data-table.js.map +1 -1
  228. package/dist/ui/dialog.d.ts.map +1 -1
  229. package/dist/ui/dialog.js +62 -61
  230. package/dist/ui/dialog.js.map +1 -1
  231. package/dist/ui/dot.d.ts.map +1 -1
  232. package/dist/ui/dot.js +10 -41
  233. package/dist/ui/dot.js.map +1 -1
  234. package/dist/ui/dropdown-menu.d.ts.map +1 -1
  235. package/dist/ui/dropdown-menu.js +79 -78
  236. package/dist/ui/dropdown-menu.js.map +1 -1
  237. package/dist/ui/file-upload.d.ts.map +1 -1
  238. package/dist/ui/file-upload.js +117 -116
  239. package/dist/ui/file-upload.js.map +1 -1
  240. package/dist/ui/form.d.ts.map +1 -1
  241. package/dist/ui/form.js +27 -26
  242. package/dist/ui/form.js.map +1 -1
  243. package/dist/ui/hover-card.d.ts.map +1 -1
  244. package/dist/ui/hover-card.js +26 -25
  245. package/dist/ui/hover-card.js.map +1 -1
  246. package/dist/ui/icon.js +7 -7
  247. package/dist/ui/index.d.ts +2 -2
  248. package/dist/ui/index.d.ts.map +1 -1
  249. package/dist/ui/index.js +3 -3
  250. package/dist/ui/index.js.map +1 -1
  251. package/dist/ui/input-otp.js +1 -1
  252. package/dist/ui/input-otp.js.map +1 -1
  253. package/dist/ui/input.js +8 -8
  254. package/dist/ui/input.js.map +1 -1
  255. package/dist/ui/menubar.d.ts.map +1 -1
  256. package/dist/ui/menubar.js +73 -72
  257. package/dist/ui/menubar.js.map +1 -1
  258. package/dist/ui/navigation-menu.d.ts.map +1 -1
  259. package/dist/ui/navigation-menu.js +80 -79
  260. package/dist/ui/navigation-menu.js.map +1 -1
  261. package/dist/ui/number-input.js +3 -3
  262. package/dist/ui/number-input.js.map +1 -1
  263. package/dist/ui/pagination.js +1 -1
  264. package/dist/ui/pagination.js.map +1 -1
  265. package/dist/ui/popover.d.ts.map +1 -1
  266. package/dist/ui/progress-ring.js +2 -2
  267. package/dist/ui/progress-ring.js.map +1 -1
  268. package/dist/ui/progress.d.ts.map +1 -1
  269. package/dist/ui/progress.js +82 -74
  270. package/dist/ui/progress.js.map +1 -1
  271. package/dist/ui/radio.d.ts.map +1 -1
  272. package/dist/ui/radio.js +32 -31
  273. package/dist/ui/radio.js.map +1 -1
  274. package/dist/ui/search-input.d.ts.map +1 -1
  275. package/dist/ui/search-input.js +28 -27
  276. package/dist/ui/search-input.js.map +1 -1
  277. package/dist/ui/select.d.ts.map +1 -1
  278. package/dist/ui/select.js +67 -66
  279. package/dist/ui/select.js.map +1 -1
  280. package/dist/ui/sheet.js +1 -1
  281. package/dist/ui/sheet.js.map +1 -1
  282. package/dist/ui/sidebar.d.ts.map +1 -1
  283. package/dist/ui/sidebar.js +14 -14
  284. package/dist/ui/sidebar.js.map +1 -1
  285. package/dist/ui/slider.d.ts +63 -9
  286. package/dist/ui/slider.d.ts.map +1 -1
  287. package/dist/ui/slider.js +75 -33
  288. package/dist/ui/slider.js.map +1 -1
  289. package/dist/ui/split-button.d.ts +8 -2
  290. package/dist/ui/split-button.d.ts.map +1 -1
  291. package/dist/ui/split-button.js +49 -95
  292. package/dist/ui/split-button.js.map +1 -1
  293. package/dist/ui/stat-card.d.ts.map +1 -1
  294. package/dist/ui/stat-card.js +89 -88
  295. package/dist/ui/stat-card.js.map +1 -1
  296. package/dist/ui/stat-flash.js +16 -16
  297. package/dist/ui/stepper.d.ts.map +1 -1
  298. package/dist/ui/stepper.js +63 -62
  299. package/dist/ui/stepper.js.map +1 -1
  300. package/dist/ui/surface.d.ts.map +1 -1
  301. package/dist/ui/surface.js +2 -2
  302. package/dist/ui/surface.js.map +1 -1
  303. package/dist/ui/switch.js +1 -1
  304. package/dist/ui/switch.js.map +1 -1
  305. package/dist/ui/table.js +3 -3
  306. package/dist/ui/table.js.map +1 -1
  307. package/dist/ui/tabs.d.ts.map +1 -1
  308. package/dist/ui/tabs.js +68 -67
  309. package/dist/ui/tabs.js.map +1 -1
  310. package/dist/ui/textarea.js +5 -5
  311. package/dist/ui/textarea.js.map +1 -1
  312. package/dist/ui/toast.d.ts.map +1 -1
  313. package/dist/ui/toast.js +196 -195
  314. package/dist/ui/toast.js.map +1 -1
  315. package/dist/ui/toggle.d.ts.map +1 -1
  316. package/dist/ui/toggle.js +26 -24
  317. package/dist/ui/toggle.js.map +1 -1
  318. package/dist/ui/tooltip.d.ts.map +1 -1
  319. package/dist/ui/tooltip.js +37 -36
  320. package/dist/ui/tooltip.js.map +1 -1
  321. package/dist/ui/tree-view/tree-item.d.ts.map +1 -1
  322. package/docs/components/composed/avatar-group.md +4 -4
  323. package/docs/components/composed/diff.md +10 -2
  324. package/docs/components/composed/schedule-view.md +1 -1
  325. package/docs/components/shell/app-shell.md +132 -0
  326. package/docs/components/ui/avatar.md +1 -1
  327. package/docs/components/ui/button.md +1 -1
  328. package/docs/components/ui/chat.md +7 -1
  329. package/docs/components/ui/color-swatch.md +1 -1
  330. package/docs/components/ui/data-table-toolbar.md +6 -2
  331. package/docs/components/ui/data-table.md +41 -7
  332. package/docs/components/ui/dot.md +1 -1
  333. package/docs/components/ui/progress.md +1 -0
  334. package/docs/components/ui/surface.md +3 -3
  335. package/docs/components/ui/table.md +2 -2
  336. package/docs/recipes/customize-brand.md +58 -0
  337. package/docs/recipes/install-astro.md +1 -0
  338. package/docs/recipes/install-next-app-router.md +1 -0
  339. package/docs/recipes/install-next-pages.md +22 -1
  340. package/docs/recipes/install-remix.md +1 -0
  341. package/docs/recipes/install-tanstack-start.md +1 -0
  342. package/docs/recipes/install-vite.md +2 -0
  343. package/docs/recipes/server-components.md +7 -4
  344. package/docs/recipes/troubleshoot.md +1 -0
  345. package/llms.txt +2 -1
  346. package/make-kit/Guidelines.md +2 -2
  347. package/make-kit/components/button.md +1 -1
  348. package/make-kit/components/card.md +6 -6
  349. package/make-kit/components/surface.md +4 -4
  350. package/make-kit/foundations/color.md +4 -4
  351. package/make-kit/foundations/dark-mode.md +1 -1
  352. package/make-kit/foundations/radius.md +1 -1
  353. package/make-kit/foundations/surfaces.md +9 -9
  354. package/mcp-manifest.json +358 -35
  355. package/package.json +8 -4
  356. package/skill/SKILL.md +12 -6
  357. package/skill/references/components.md +2 -1
  358. package/skill/references/customize-brand.md +58 -0
  359. package/skill/references/server-components.md +7 -4
  360. package/skill/references/setup-astro.md +1 -0
  361. package/skill/references/setup-next-app-router.md +1 -0
  362. package/skill/references/setup-next-pages.md +22 -1
  363. package/skill/references/setup-remix.md +1 -0
  364. package/skill/references/setup-tanstack-start.md +1 -0
  365. package/skill/references/setup-vite.md +2 -0
  366. package/skill/references/troubleshoot.md +1 -0
  367. package/dist/motion/check-motion-provider.d.ts +0 -2
  368. package/dist/motion/check-motion-provider.d.ts.map +0 -1
  369. package/dist/motion/index.js.map +0 -1
  370. package/dist/primitives/react-toast.d.ts +0 -120
  371. package/dist/ui/charts/_internal/scales.d.ts +0 -5
  372. package/dist/ui/charts/_internal/scales.d.ts.map +0 -1
  373. package/dist/ui/lib/slot.d.ts +0 -8
  374. package/dist/ui/lib/slot.d.ts.map +0 -1
@@ -0,0 +1,101 @@
1
+ import { ComponentProps } from 'react';
2
+ /**
3
+ * AppShell — the frame that lets a bar span above BOTH the sidebar and the
4
+ * content.
5
+ *
6
+ * This is the one shape the library could not express. `SidebarProvider`
7
+ * renders a single flex row, so a bar can only live *inside* the content pane —
8
+ * which is why every shadcn example puts its `<header>` inside `SidebarInset`.
9
+ * Carbon can do it because its `Header` is a sibling above `SideNav`; this is
10
+ * that arrangement.
11
+ *
12
+ * Compose it with the components you already have:
13
+ *
14
+ * ```tsx
15
+ * <AppShell variant="inset" chrome="dim">
16
+ * <AppShellBar><TopBar … /></AppShellBar>
17
+ * <AppShellBody>
18
+ * <AppShellSidebar><Sidebar … /></AppShellSidebar>
19
+ * <AppShellCanvas>{children}</AppShellCanvas>
20
+ * </AppShellBody>
21
+ * </AppShell>
22
+ * ```
23
+ *
24
+ * ## The two inset arrangements
25
+ *
26
+ * `chrome` decides which plane the frame takes and which the work takes. It is
27
+ * not a lightness switch — the two planes swap roles, and which one is lighter
28
+ * flips between themes:
29
+ *
30
+ * | | light chrome | light canvas | dark chrome | dark canvas |
31
+ * |---|---|---|---|---|
32
+ * | `dim` | `#eeeeee` | `#ffffff` | `#0a0a0a` | `#171717` |
33
+ * | `bright` | `#ffffff` | `#eeeeee` | `#171717` | `#0a0a0a` |
34
+ *
35
+ * Both come from the same two tokens — `surface-sunken` and `surface-panel` —
36
+ * swapped. No third tier, and no per-theme special case.
37
+ *
38
+ * With `dim` the brand tint lands on the frame and the work area stays neutral.
39
+ * With `bright` it is the reverse. That choice matters more than the lightness:
40
+ * it decides whether your brand colour surrounds the work or sits underneath it.
41
+ *
42
+ * See docs/plans/2026-08-26-surface-model-rebuild.md.
43
+ */
44
+ type Variant = 'flat' | 'inset';
45
+ type Chrome = 'dim' | 'bright';
46
+ export interface AppShellProps extends ComponentProps<'div'> {
47
+ /**
48
+ * `flat` — chrome and content share one surface; a hairline on the sidebar
49
+ * does the separating. `inset` — the content sits in a rounded panel inside
50
+ * the chrome. @default 'flat'
51
+ */
52
+ variant?: Variant;
53
+ /**
54
+ * Which plane the chrome takes when `variant="inset"`. Ignored when flat.
55
+ * @default 'dim'
56
+ */
57
+ chrome?: Chrome;
58
+ }
59
+ declare const AppShell: import('react').ForwardRefExoticComponent<Omit<AppShellProps, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
60
+ export interface AppShellBarProps extends ComponentProps<'header'> {
61
+ /**
62
+ * Draw a hairline under the bar. Defaults to `true` when flat (the bar is its
63
+ * own region and needs the edge) and `false` when inset (the bar is part of a
64
+ * continuous chrome plane, and a border would cut it in half).
65
+ */
66
+ bordered?: boolean;
67
+ }
68
+ /**
69
+ * The full-width bar. Sits above the sidebar and the canvas, which is the whole
70
+ * point of this component.
71
+ *
72
+ * Height is a MINIMUM, not a fixed value — `TopBar` sizes to its content, and a
73
+ * two-line workspace switcher legitimately needs more room than a one-line one.
74
+ * Fixing it would clip.
75
+ */
76
+ declare const AppShellBar: import('react').ForwardRefExoticComponent<Omit<AppShellBarProps, "ref"> & import('react').RefAttributes<HTMLElement>>;
77
+ /** The row beneath the bar: sidebar alongside canvas. */
78
+ declare const AppShellBody: import('react').ForwardRefExoticComponent<Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
79
+ export interface AppShellSidebarProps extends ComponentProps<'div'> {
80
+ /** Render at the collapsed icon width instead of the full width. */
81
+ collapsed?: boolean;
82
+ }
83
+ /**
84
+ * Fixed-width slot for the sidebar. Widths come from the same constants
85
+ * `Sidebar` uses (16rem expanded, 3rem collapsed), so the two agree whether or
86
+ * not you compose them together.
87
+ */
88
+ declare const AppShellSidebar: import('react').ForwardRefExoticComponent<Omit<AppShellSidebarProps, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
89
+ /**
90
+ * The content pane.
91
+ *
92
+ * When inset, the panel is flush to the bar and the sidebar and floats only off
93
+ * the bottom-right. It reads as the frame opening up rather than as a card
94
+ * dropped into the middle — a symmetric gap fights that.
95
+ *
96
+ * No shadow. The inset canvas is a frame, not a floating thing; shadows are
97
+ * reserved for what genuinely floats.
98
+ */
99
+ declare const AppShellCanvas: import('react').ForwardRefExoticComponent<Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
100
+ export { AppShell, AppShellBar, AppShellBody, AppShellCanvas, AppShellSidebar };
101
+ //# sourceMappingURL=app-shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-shell.d.ts","sourceRoot":"","sources":["../../src/shell/app-shell.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAK3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO,CAAA;AAC/B,KAAK,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAA;AAe9B,MAAM,WAAW,aAAc,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC1D;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,QAAA,MAAM,QAAQ,uHAmBb,CAAA;AAGD,MAAM,WAAW,gBAAiB,SAAQ,cAAc,CAAC,QAAQ,CAAC;IAChE;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,WAAW,uHAiBhB,CAAA;AAGD,yDAAyD;AACzD,QAAA,MAAM,YAAY,2MAKjB,CAAA;AAGD,MAAM,WAAW,oBAAqB,SAAQ,cAAc,CAAC,KAAK,CAAC;IACjE,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED;;;;GAIG;AACH,QAAA,MAAM,eAAe,8HAkBpB,CAAA;AAGD;;;;;;;;;GASG;AACH,QAAA,MAAM,cAAc,qMAgCnB,CAAA;AAGD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,CAAA"}
@@ -0,0 +1,76 @@
1
+ "use client";
2
+ import { cn as e } from "../ui/lib/utils.js";
3
+ import { createContext as t, forwardRef as n, useContext as r } from "react";
4
+ import { jsx as i } from "react/jsx-runtime";
5
+ //#region src/shell/app-shell.tsx
6
+ var a = t({
7
+ variant: "flat",
8
+ chrome: "dim"
9
+ });
10
+ function o(e) {
11
+ let t = r(a);
12
+ if (!t) throw Error(`${e} must be rendered inside <AppShell>.`);
13
+ return t;
14
+ }
15
+ var s = n(({ variant: t = "flat", chrome: n = "dim", className: r, children: o, ...s }, c) => /* @__PURE__ */ i(a.Provider, {
16
+ value: {
17
+ variant: t,
18
+ chrome: n
19
+ },
20
+ children: /* @__PURE__ */ i("div", {
21
+ ref: c,
22
+ className: e("flex min-h-svh flex-col", t === "flat" && "bg-surface-base", t === "inset" && n === "dim" && "bg-surface-sunken", t === "inset" && n === "bright" && "bg-surface-panel", r),
23
+ ...s,
24
+ children: o
25
+ })
26
+ }));
27
+ s.displayName = "AppShell";
28
+ var c = n(({ bordered: t, className: n, ...r }, a) => {
29
+ let { variant: s } = o("AppShellBar");
30
+ return /* @__PURE__ */ i("header", {
31
+ ref: a,
32
+ className: e("flex w-full shrink-0 items-center", s === "flat" ? "min-h-ds-xl" : "min-h-ds-lg", (t ?? s === "flat") && "border-b border-surface-border", n),
33
+ ...r
34
+ });
35
+ });
36
+ c.displayName = "AppShellBar";
37
+ var l = n(({ className: t, ...n }, r) => /* @__PURE__ */ i("div", {
38
+ ref: r,
39
+ className: e("flex min-h-0 flex-1", t),
40
+ ...n
41
+ }));
42
+ l.displayName = "AppShellBody";
43
+ var u = n(({ collapsed: t = !1, className: n, style: r, ...a }, s) => {
44
+ let { variant: c } = o("AppShellSidebar");
45
+ return /* @__PURE__ */ i("div", {
46
+ ref: s,
47
+ "data-collapsed": t || void 0,
48
+ style: {
49
+ width: t ? "3rem" : "16rem",
50
+ ...r
51
+ },
52
+ className: e("flex shrink-0 flex-col", c === "flat" && "border-r border-surface-border", n),
53
+ ...a
54
+ });
55
+ });
56
+ u.displayName = "AppShellSidebar";
57
+ var d = n(({ className: t, children: n, ...r }, a) => {
58
+ let { variant: s, chrome: c } = o("AppShellCanvas");
59
+ return s === "flat" ? /* @__PURE__ */ i("main", {
60
+ ref: a,
61
+ className: e("flex min-w-0 flex-1 flex-col bg-surface-base", t),
62
+ ...r,
63
+ children: n
64
+ }) : /* @__PURE__ */ i("div", {
65
+ className: "flex min-w-0 flex-1 pb-ds-03 pr-ds-03",
66
+ children: /* @__PURE__ */ i("main", {
67
+ ref: a,
68
+ className: e("flex min-w-0 flex-1 flex-col overflow-hidden rounded-overlay-lg", c === "dim" ? "bg-surface-panel" : "bg-surface-sunken", t),
69
+ ...r,
70
+ children: n
71
+ })
72
+ });
73
+ });
74
+ d.displayName = "AppShellCanvas";
75
+ //#endregion
76
+ export { s as AppShell, c as AppShellBar, l as AppShellBody, d as AppShellCanvas, u as AppShellSidebar };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-shell.js","names":[],"sources":["../../src/shell/app-shell.tsx"],"sourcesContent":["'use client'\n\nimport type { ComponentProps } from 'react'\nimport { createContext, forwardRef, useContext } from 'react'\n\nimport { cn } from '../ui/lib/utils'\n\n/**\n * AppShell — the frame that lets a bar span above BOTH the sidebar and the\n * content.\n *\n * This is the one shape the library could not express. `SidebarProvider`\n * renders a single flex row, so a bar can only live *inside* the content pane —\n * which is why every shadcn example puts its `<header>` inside `SidebarInset`.\n * Carbon can do it because its `Header` is a sibling above `SideNav`; this is\n * that arrangement.\n *\n * Compose it with the components you already have:\n *\n * ```tsx\n * <AppShell variant=\"inset\" chrome=\"dim\">\n * <AppShellBar><TopBar … /></AppShellBar>\n * <AppShellBody>\n * <AppShellSidebar><Sidebar … /></AppShellSidebar>\n * <AppShellCanvas>{children}</AppShellCanvas>\n * </AppShellBody>\n * </AppShell>\n * ```\n *\n * ## The two inset arrangements\n *\n * `chrome` decides which plane the frame takes and which the work takes. It is\n * not a lightness switch — the two planes swap roles, and which one is lighter\n * flips between themes:\n *\n * | | light chrome | light canvas | dark chrome | dark canvas |\n * |---|---|---|---|---|\n * | `dim` | `#eeeeee` | `#ffffff` | `#0a0a0a` | `#171717` |\n * | `bright` | `#ffffff` | `#eeeeee` | `#171717` | `#0a0a0a` |\n *\n * Both come from the same two tokens — `surface-sunken` and `surface-panel` —\n * swapped. No third tier, and no per-theme special case.\n *\n * With `dim` the brand tint lands on the frame and the work area stays neutral.\n * With `bright` it is the reverse. That choice matters more than the lightness:\n * it decides whether your brand colour surrounds the work or sits underneath it.\n *\n * See docs/plans/2026-08-26-surface-model-rebuild.md.\n */\n\ntype Variant = 'flat' | 'inset'\ntype Chrome = 'dim' | 'bright'\n\ninterface ShellContext {\n variant: Variant\n chrome: Chrome\n}\n\nconst AppShellContext = createContext<ShellContext>({ variant: 'flat', chrome: 'dim' })\n\nfunction useAppShell(part: string): ShellContext {\n const ctx = useContext(AppShellContext)\n if (!ctx) throw new Error(`${part} must be rendered inside <AppShell>.`)\n return ctx\n}\n\nexport interface AppShellProps extends ComponentProps<'div'> {\n /**\n * `flat` — chrome and content share one surface; a hairline on the sidebar\n * does the separating. `inset` — the content sits in a rounded panel inside\n * the chrome. @default 'flat'\n */\n variant?: Variant\n /**\n * Which plane the chrome takes when `variant=\"inset\"`. Ignored when flat.\n * @default 'dim'\n */\n chrome?: Chrome\n}\n\nconst AppShell = forwardRef<HTMLDivElement, AppShellProps>(\n ({ variant = 'flat', chrome = 'dim', className, children, ...props }, ref) => (\n <AppShellContext.Provider value={{ variant, chrome }}>\n <div\n ref={ref}\n className={cn(\n 'flex min-h-svh flex-col',\n variant === 'flat' && 'bg-surface-base',\n // the two inset arrangements are the same pair of tokens, swapped\n variant === 'inset' && chrome === 'dim' && 'bg-surface-sunken',\n variant === 'inset' && chrome === 'bright' && 'bg-surface-panel',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n </AppShellContext.Provider>\n ),\n)\nAppShell.displayName = 'AppShell'\n\nexport interface AppShellBarProps extends ComponentProps<'header'> {\n /**\n * Draw a hairline under the bar. Defaults to `true` when flat (the bar is its\n * own region and needs the edge) and `false` when inset (the bar is part of a\n * continuous chrome plane, and a border would cut it in half).\n */\n bordered?: boolean\n}\n\n/**\n * The full-width bar. Sits above the sidebar and the canvas, which is the whole\n * point of this component.\n *\n * Height is a MINIMUM, not a fixed value — `TopBar` sizes to its content, and a\n * two-line workspace switcher legitimately needs more room than a one-line one.\n * Fixing it would clip.\n */\nconst AppShellBar = forwardRef<HTMLElement, AppShellBarProps>(\n ({ bordered, className, ...props }, ref) => {\n const { variant } = useAppShell('AppShellBar')\n const showBorder = bordered ?? variant === 'flat'\n return (\n <header\n ref={ref}\n className={cn(\n 'flex w-full shrink-0 items-center',\n variant === 'flat' ? 'min-h-ds-xl' : 'min-h-ds-lg',\n showBorder && 'border-b border-surface-border',\n className,\n )}\n {...props}\n />\n )\n },\n)\nAppShellBar.displayName = 'AppShellBar'\n\n/** The row beneath the bar: sidebar alongside canvas. */\nconst AppShellBody = forwardRef<HTMLDivElement, ComponentProps<'div'>>(\n ({ className, ...props }, ref) => (\n // min-h-0 so a scrolling canvas does not stretch the row past the viewport\n <div ref={ref} className={cn('flex min-h-0 flex-1', className)} {...props} />\n ),\n)\nAppShellBody.displayName = 'AppShellBody'\n\nexport interface AppShellSidebarProps extends ComponentProps<'div'> {\n /** Render at the collapsed icon width instead of the full width. */\n collapsed?: boolean\n}\n\n/**\n * Fixed-width slot for the sidebar. Widths come from the same constants\n * `Sidebar` uses (16rem expanded, 3rem collapsed), so the two agree whether or\n * not you compose them together.\n */\nconst AppShellSidebar = forwardRef<HTMLDivElement, AppShellSidebarProps>(\n ({ collapsed = false, className, style, ...props }, ref) => {\n const { variant } = useAppShell('AppShellSidebar')\n return (\n <div\n ref={ref}\n data-collapsed={collapsed || undefined}\n style={{ width: collapsed ? '3rem' : '16rem', ...style }}\n className={cn(\n 'flex shrink-0 flex-col',\n // flat has no chrome plane of its own, so the edge does the work\n variant === 'flat' && 'border-r border-surface-border',\n className,\n )}\n {...props}\n />\n )\n },\n)\nAppShellSidebar.displayName = 'AppShellSidebar'\n\n/**\n * The content pane.\n *\n * When inset, the panel is flush to the bar and the sidebar and floats only off\n * the bottom-right. It reads as the frame opening up rather than as a card\n * dropped into the middle — a symmetric gap fights that.\n *\n * No shadow. The inset canvas is a frame, not a floating thing; shadows are\n * reserved for what genuinely floats.\n */\nconst AppShellCanvas = forwardRef<HTMLDivElement, ComponentProps<'main'>>(\n ({ className, children, ...props }, ref) => {\n const { variant, chrome } = useAppShell('AppShellCanvas')\n\n if (variant === 'flat') {\n return (\n <main\n ref={ref}\n className={cn('flex min-w-0 flex-1 flex-col bg-surface-base', className)}\n {...props}\n >\n {children}\n </main>\n )\n }\n\n return (\n <div className=\"flex min-w-0 flex-1 pb-ds-03 pr-ds-03\">\n <main\n ref={ref}\n className={cn(\n 'flex min-w-0 flex-1 flex-col overflow-hidden rounded-overlay-lg',\n chrome === 'dim' ? 'bg-surface-panel' : 'bg-surface-sunken',\n className,\n )}\n {...props}\n >\n {children}\n </main>\n </div>\n )\n },\n)\nAppShellCanvas.displayName = 'AppShellCanvas'\n\nexport { AppShell, AppShellBar, AppShellBody, AppShellCanvas, AppShellSidebar }\n"],"mappings":";;;;;AA0DA,IAAM,IAAkB,EAA4B;CAAE,SAAS;CAAQ,QAAQ;AAAM,CAAC;AAEtF,SAAS,EAAY,GAA4B;CAC/C,IAAM,IAAM,EAAW,CAAe;CACtC,IAAI,CAAC,GAAK,MAAU,MAAM,GAAG,EAAK,qCAAqC;CACvE,OAAO;AACT;AAgBA,IAAM,IAAW,GACd,EAAE,aAAU,QAAQ,YAAS,OAAO,cAAW,aAAU,GAAG,KAAS,MACpE,kBAAC,EAAgB,UAAjB;CAA0B,OAAO;EAAE;EAAS;CAAO;WACjD,kBAAC,OAAD;EACO;EACL,WAAW,EACT,2BACA,MAAY,UAAU,mBAEtB,MAAY,WAAW,MAAW,SAAS,qBAC3C,MAAY,WAAW,MAAW,YAAY,oBAC9C,CACF;EACA,GAAI;EAEH;CACE,CAAA;AACmB,CAAA,CAE9B;AACA,EAAS,cAAc;AAmBvB,IAAM,IAAc,GACjB,EAAE,aAAU,cAAW,GAAG,KAAS,MAAQ;CAC1C,IAAM,EAAE,eAAY,EAAY,aAAa;CAE7C,OACE,kBAAC,UAAD;EACO;EACL,WAAW,EACT,qCACA,MAAY,SAAS,gBAAgB,gBANxB,KAAY,MAAY,WAOvB,kCACd,CACF;EACA,GAAI;CACL,CAAA;AAEL,CACF;AACA,EAAY,cAAc;AAG1B,IAAM,IAAe,GAClB,EAAE,cAAW,GAAG,KAAS,MAExB,kBAAC,OAAD;CAAU;CAAK,WAAW,EAAG,uBAAuB,CAAS;CAAG,GAAI;AAAQ,CAAA,CAEhF;AACA,EAAa,cAAc;AAY3B,IAAM,IAAkB,GACrB,EAAE,eAAY,IAAO,cAAW,UAAO,GAAG,KAAS,MAAQ;CAC1D,IAAM,EAAE,eAAY,EAAY,iBAAiB;CACjD,OACE,kBAAC,OAAD;EACO;EACL,kBAAgB,KAAa,KAAA;EAC7B,OAAO;GAAE,OAAO,IAAY,SAAS;GAAS,GAAG;EAAM;EACvD,WAAW,EACT,0BAEA,MAAY,UAAU,kCACtB,CACF;EACA,GAAI;CACL,CAAA;AAEL,CACF;AACA,EAAgB,cAAc;AAY9B,IAAM,IAAiB,GACpB,EAAE,cAAW,aAAU,GAAG,KAAS,MAAQ;CAC1C,IAAM,EAAE,YAAS,cAAW,EAAY,gBAAgB;CAcxD,OAZI,MAAY,SAEZ,kBAAC,QAAD;EACO;EACL,WAAW,EAAG,gDAAgD,CAAS;EACvE,GAAI;EAEH;CACG,CAAA,IAKR,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,QAAD;GACO;GACL,WAAW,EACT,mEACA,MAAW,QAAQ,qBAAqB,qBACxC,CACF;GACA,GAAI;GAEH;EACG,CAAA;CACH,CAAA;AAET,CACF;AACA,EAAe,cAAc"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { IconProvider as e } from "../ui/icon-context.js";
3
- import { springs as t } from "../ui/lib/motion.js";
2
+ import { springs as e } from "../ui/lib/motion.js";
3
+ import { IconProvider as t } from "../ui/icon-context.js";
4
4
  import { cn as n } from "../ui/lib/utils.js";
5
5
  import { Icon as r } from "../ui/icon.js";
6
6
  import { normalizeIcon as i } from "../_chunks/normalize-icon.js";
@@ -29,24 +29,24 @@ function b({ count: e }) {
29
29
  children: t
30
30
  });
31
31
  }
32
- function x({ indicator: e, layoutId: n, reduced: r }) {
33
- if (e === "none") return null;
32
+ function x({ indicator: t, layoutId: n, reduced: r }) {
33
+ if (t === "none") return null;
34
34
  let i = {
35
35
  layoutId: n,
36
36
  "aria-hidden": !0,
37
- transition: r ? { duration: 0 } : t.snappy,
37
+ transition: r ? { duration: 0 } : e.snappy,
38
38
  initial: !r && { opacity: 0 },
39
39
  animate: { opacity: 1 }
40
40
  };
41
- return e === "underline" ? /* @__PURE__ */ m(_.span, {
41
+ return t === "underline" ? /* @__PURE__ */ m(_.span, {
42
42
  ...i,
43
43
  className: "absolute top-0 h-[3px] w-full rounded-b-control-inner bg-accent-9"
44
- }) : e === "tint" ? /* @__PURE__ */ m(_.span, {
44
+ }) : t === "tint" ? /* @__PURE__ */ m(_.span, {
45
45
  ...i,
46
- className: "absolute inset-0 rounded-control bg-accent-3"
46
+ className: "absolute inset-0 rounded-control bg-accent-4"
47
47
  }) : /* @__PURE__ */ m(_.span, {
48
48
  ...i,
49
- className: "absolute inset-0 rounded-pill bg-accent-3"
49
+ className: "absolute inset-0 rounded-pill bg-accent-4"
50
50
  });
51
51
  }
52
52
  var S = "relative flex h-16 w-full min-w-0 cursor-pointer flex-col items-center justify-center gap-ds-02 px-ds-01 pt-0 text-body-sm transition-colors duration-fast-02 ease-productive-standard";
@@ -54,7 +54,7 @@ function C({ item: r, isActive: a, indicator: o, indicatorId: s, showLabel: c, r
54
54
  let u = d();
55
55
  return /* @__PURE__ */ m(_.div, {
56
56
  whileTap: l ? void 0 : { scale: .96 },
57
- transition: l ? { duration: 0 } : t.snappy,
57
+ transition: l ? { duration: 0 } : e.snappy,
58
58
  className: "flex min-w-0 flex-1 basis-0",
59
59
  children: /* @__PURE__ */ h(u, {
60
60
  href: r.href,
@@ -84,7 +84,7 @@ function C({ item: r, isActive: a, indicator: o, indicatorId: s, showLabel: c, r
84
84
  /* @__PURE__ */ m("span", {
85
85
  className: "relative [&>svg]:h-ico-md [&>svg]:w-ico-md",
86
86
  "aria-hidden": "true",
87
- children: /* @__PURE__ */ m(e, {
87
+ children: /* @__PURE__ */ m(t, {
88
88
  size: "md",
89
89
  children: i(a && r.activeIcon ? r.activeIcon : r.icon)
90
90
  })
@@ -107,7 +107,7 @@ var w = f.forwardRef(({ currentPath: a = "/", user: b = null, primaryItems: w =
107
107
  ...k,
108
108
  ref: A,
109
109
  "aria-label": "Mobile navigation",
110
- className: n("fixed bottom-0 start-0 end-0 z-sticky flex w-full flex-row items-stretch justify-between border-t border-surface-border-strong bg-surface-chrome px-ds-05 pb-safe pt-0 md:hidden", O),
110
+ className: n("fixed bottom-0 start-0 end-0 z-sticky flex w-full flex-row items-stretch justify-between border-t border-surface-border-strong bg-surface-base px-ds-05 pb-safe pt-0 md:hidden", O),
111
111
  children: [L.map((e) => /* @__PURE__ */ m(C, {
112
112
  item: e,
113
113
  isActive: I(e.href, e.exact),
@@ -124,7 +124,7 @@ var w = f.forwardRef(({ currentPath: a = "/", user: b = null, primaryItems: w =
124
124
  type: "button",
125
125
  "aria-label": "More navigation options",
126
126
  whileTap: M ? void 0 : { scale: .96 },
127
- transition: M ? { duration: 0 } : t.snappy,
127
+ transition: M ? { duration: 0 } : e.snappy,
128
128
  className: n(S, "min-w-0 flex-1 basis-0", B ? "font-semibold text-accent-11" : "text-surface-fg-subtle"),
129
129
  children: [B && E === "tint" && /* @__PURE__ */ m(x, {
130
130
  indicator: "tint",
@@ -158,25 +158,25 @@ var w = f.forwardRef(({ currentPath: a = "/", user: b = null, primaryItems: w =
158
158
  className: "rounded-t-bubble",
159
159
  children: [/* @__PURE__ */ m(c, { children: /* @__PURE__ */ m(l, { children: "More" }) }), /* @__PURE__ */ m("div", {
160
160
  className: "grid grid-cols-[repeat(auto-fit,minmax(72px,1fr))] gap-ds-03 pt-ds-04",
161
- children: R.map((t) => {
162
- let r = I(t.href, t.exact);
161
+ children: R.map((e) => {
162
+ let r = I(e.href, e.exact);
163
163
  return /* @__PURE__ */ h(j, {
164
- href: t.href,
164
+ href: e.href,
165
165
  onClick: () => P(!1),
166
166
  "aria-current": r ? "page" : void 0,
167
- className: n("flex min-w-0 flex-col items-center gap-ds-02b rounded-overlay-lg p-ds-04 text-body-sm transition-colors ease-productive-standard", r ? "bg-surface-raised-hover text-accent-11" : "text-surface-fg-subtle hover:bg-surface-raised-hover"),
167
+ className: n("flex min-w-0 flex-col items-center gap-ds-02b rounded-overlay-lg p-ds-04 text-body-sm transition-colors ease-productive-standard", r ? "bg-surface-panel-hover text-accent-11" : "text-surface-fg-subtle hover:bg-surface-panel-hover"),
168
168
  children: [/* @__PURE__ */ m("span", {
169
169
  className: "[&>svg]:h-ico-md [&>svg]:w-ico-md",
170
170
  "aria-hidden": "true",
171
- children: /* @__PURE__ */ m(e, {
171
+ children: /* @__PURE__ */ m(t, {
172
172
  size: "md",
173
- children: i(t.icon)
173
+ children: i(e.icon)
174
174
  })
175
175
  }), /* @__PURE__ */ m("span", {
176
176
  className: "max-w-full truncate text-center",
177
- children: t.title
177
+ children: e.title
178
178
  })]
179
- }, t.href);
179
+ }, e.href);
180
180
  })
181
181
  })]
182
182
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"bottom-navbar.js","names":[],"sources":["../../src/shell/bottom-navbar.tsx"],"sourcesContent":["'use client'\n\n/**\n * BottomNavbar -- Mobile bottom navigation bar.\n *\n * Props-driven (currentPath / user / items) and router-agnostic via `useLink`.\n * The \"More\" overflow uses the DS `Sheet` primitive, so it inherits focus trap,\n * scroll lock, return-focus, `aria-modal`, and trigger↔panel ARIA wiring.\n */\nimport { IconDots } from '@tabler/icons-react'\nimport { motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\nimport { useState } from 'react'\n\nimport { Badge } from '../ui/badge'\nimport { Icon } from '../ui/icon'\nimport { IconProvider } from '../ui/icon-context'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { springs } from '../ui/lib/motion'\nimport { normalizeIcon } from '../ui/lib/normalize-icon'\nimport { cn } from '../ui/lib/utils'\nimport { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '../ui/sheet'\nimport { useLink } from './link-context'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface BottomNavbarUser {\n name: string\n role?: string\n}\n\nexport interface BottomNavItem {\n title: string\n href: string\n /** Icon for this nav item. Accepts any `IconInput`. */\n icon: IconInput\n /** Icon shown when the item is active — e.g. a filled variant. Falls back to `icon`. */\n activeIcon?: IconInput\n /** When true, the route matches only when the path is exactly equal */\n exact?: boolean\n /** Notification badge count. 0 or undefined = hidden, 1–99 = shown, >99 = \"99+\" */\n badge?: number\n /**\n * Roles allowed to see this item, matched against `user.role`. Omit to show\n * it to everyone. For arbitrary logic, use `canView` instead.\n */\n roles?: string[]\n /**\n * Visibility predicate — full control over whether this item renders.\n * Receives the current `user` (or `null`). Takes precedence over `roles`.\n */\n canView?: (user: BottomNavbarUser | null) => boolean\n}\n\n/**\n * Active-item indicator, animated between items on selection:\n * - `pill` (default) — Material-3 tonal pill behind the icon\n * - `underline` — top accent bar (Material-2 tab style)\n * - `tint` — subtle background tint on the whole active cell\n * - `none` — no shape; rely on the filled `activeIcon` + accent color (iOS)\n */\nexport type BottomNavIndicator = 'pill' | 'underline' | 'tint' | 'none'\n/** Show labels always (default) or only for the selected item (narrow viewports). */\nexport type BottomNavLabelVisibility = 'always' | 'selected'\n\nexport interface BottomNavbarProps extends React.HTMLAttributes<HTMLElement> {\n /** Currently active pathname */\n currentPath?: string\n /** Current user. Drives per-item role gating via `item.roles` / `item.canView`. */\n user?: BottomNavbarUser | null\n /** Primary nav items shown directly in the bottom bar (max 4 recommended) */\n primaryItems?: BottomNavItem[]\n /** Additional items shown in the \"More\" overflow sheet */\n moreItems?: BottomNavItem[]\n /** Active-indicator style. @default 'pill' */\n indicator?: BottomNavIndicator\n /** Label visibility. @default 'always' */\n labelVisibility?: BottomNavLabelVisibility\n /** Additional className for the nav element */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// Helpers\n// -----------------------------------------------------------------------\n\n/** Per-item role/visibility gate. `canView` wins; else `roles` matched against user.role; else visible. */\nfunction itemVisible(item: BottomNavItem, user: BottomNavbarUser | null): boolean {\n if (item.canView) return item.canView(user)\n if (item.roles && item.roles.length > 0) {\n return !!user?.role && item.roles.includes(user.role)\n }\n return true\n}\n\n// -----------------------------------------------------------------------\n// NavBadge (composes Badge)\n// -----------------------------------------------------------------------\n\nfunction NavBadge({ count }: { count: number }) {\n if (!count || count <= 0) return null\n const display = count > 99 ? '99+' : String(count)\n return (\n <Badge\n color=\"error\"\n variant=\"solid\"\n size=\"xs\"\n aria-label={`${count} notifications`}\n className=\"pointer-events-none absolute -end-1 -top-1 justify-center px-ds-01 tabular-nums motion-safe:animate-in motion-safe:zoom-in-75\"\n >\n {display}\n </Badge>\n )\n}\n\n// -----------------------------------------------------------------------\n// Active indicator (shared-element)\n// -----------------------------------------------------------------------\n\n/**\n * The active-item indicator. A single shared-element (`layoutId`) that SLIDES\n * to the selected item and fades in on first appearance. `none` renders\n * nothing (the filled `activeIcon` + accent color carry the state).\n */\nfunction ActiveIndicator({\n indicator,\n layoutId,\n reduced,\n}: {\n indicator: BottomNavIndicator\n layoutId: string\n reduced: boolean\n}) {\n if (indicator === 'none') return null\n const common = {\n layoutId,\n 'aria-hidden': true as const,\n transition: reduced ? { duration: 0 } : springs.snappy,\n initial: reduced ? false : { opacity: 0 },\n animate: { opacity: 1 },\n }\n if (indicator === 'underline') {\n return <motion.span {...common} className=\"absolute top-0 h-[3px] w-full rounded-b-control-inner bg-accent-9\" />\n }\n if (indicator === 'tint') {\n return <motion.span {...common} className=\"absolute inset-0 rounded-control bg-accent-3\" />\n }\n // pill (default) — Material-3 tonal pill behind the icon\n return <motion.span {...common} className=\"absolute inset-0 rounded-pill bg-accent-3\" />\n}\n\n// -----------------------------------------------------------------------\n// BottomNavLink (internal)\n// -----------------------------------------------------------------------\n\nconst itemClass =\n 'relative flex h-16 w-full min-w-0 cursor-pointer flex-col items-center justify-center gap-ds-02 px-ds-01 pt-0 text-body-sm transition-colors duration-fast-02 ease-productive-standard'\n\nfunction BottomNavLink({\n item,\n isActive,\n indicator,\n indicatorId,\n showLabel,\n reduced,\n}: {\n item: BottomNavItem\n isActive: boolean\n indicator: BottomNavIndicator\n indicatorId: string\n showLabel: boolean\n reduced: boolean\n}) {\n const Link = useLink()\n return (\n <motion.div\n whileTap={reduced ? undefined : { scale: 0.96 }}\n transition={reduced ? { duration: 0 } : springs.snappy}\n className=\"flex min-w-0 flex-1 basis-0\"\n >\n <Link\n href={item.href}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n className={cn(itemClass, isActive ? 'font-semibold text-accent-11' : 'text-surface-fg-subtle')}\n >\n {/* tint covers the whole cell — sits behind the content */}\n {isActive && indicator === 'tint' && (\n <ActiveIndicator indicator=\"tint\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative flex w-full min-w-0 flex-col items-center gap-ds-02\">\n {isActive && indicator === 'underline' && (\n <ActiveIndicator indicator=\"underline\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative px-ds-04 py-ds-01\">\n {isActive && indicator === 'pill' && (\n <ActiveIndicator indicator=\"pill\" layoutId={indicatorId} reduced={reduced} />\n )}\n <span className=\"relative [&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\">\n <IconProvider size=\"md\">\n {normalizeIcon(isActive && item.activeIcon ? item.activeIcon : item.icon)}\n </IconProvider>\n </span>\n {item.badge != null && <NavBadge count={item.badge} />}\n </div>\n {showLabel && <span className=\"max-w-full truncate text-center\">{item.title}</span>}\n </div>\n </Link>\n </motion.div>\n )\n}\n\n// -----------------------------------------------------------------------\n// BottomNavbar\n// -----------------------------------------------------------------------\n\nconst BottomNavbar = React.forwardRef<HTMLElement, BottomNavbarProps>(\n (\n {\n currentPath = '/',\n user = null,\n primaryItems = [],\n moreItems = [],\n indicator = 'pill',\n labelVisibility = 'always',\n className,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const reduced = useReducedMotion() ?? false\n const [showMore, setShowMore] = useState(false)\n // Scope the shared-element layoutId per instance so two navbars don't animate into each other.\n const instanceId = React.useId()\n const indicatorId = `${instanceId}-nav-indicator`\n\n const isActive = (path: string, exact = false) => {\n if (exact || path === '/') return currentPath === path\n return currentPath.startsWith(path)\n }\n\n // Role/visibility gating\n const visiblePrimary = primaryItems.filter((item) => itemVisible(item, user))\n const visibleMore = moreItems.filter((item) => itemVisible(item, user))\n\n const isMoreActive = visibleMore.some((item) => isActive(item.href, item.exact))\n const moreSelected = showMore || isMoreActive\n const showMoreLabel = labelVisibility === 'always' || moreSelected\n\n return (\n <nav\n {...props}\n ref={ref}\n aria-label=\"Mobile navigation\"\n className={cn(\n 'fixed bottom-0 start-0 end-0 z-sticky flex w-full flex-row items-stretch justify-between border-t border-surface-border-strong bg-surface-chrome px-ds-05 pb-safe pt-0 md:hidden',\n className,\n )}\n >\n {visiblePrimary.map((item) => (\n <BottomNavLink\n key={item.href}\n item={item}\n isActive={isActive(item.href, item.exact)}\n indicator={indicator}\n indicatorId={indicatorId}\n showLabel={labelVisibility === 'always' || isActive(item.href, item.exact)}\n reduced={reduced}\n />\n ))}\n\n {visibleMore.length > 0 && (\n <Sheet open={showMore} onOpenChange={setShowMore}>\n <SheetTrigger asChild>\n <motion.button\n type=\"button\"\n aria-label=\"More navigation options\"\n whileTap={reduced ? undefined : { scale: 0.96 }}\n transition={reduced ? { duration: 0 } : springs.snappy}\n className={cn(\n itemClass,\n 'min-w-0 flex-1 basis-0',\n moreSelected ? 'font-semibold text-accent-11' : 'text-surface-fg-subtle',\n )}\n >\n {moreSelected && indicator === 'tint' && (\n <ActiveIndicator indicator=\"tint\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative flex w-full min-w-0 flex-col items-center gap-ds-02\">\n {moreSelected && indicator === 'underline' && (\n <ActiveIndicator indicator=\"underline\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative px-ds-04 py-ds-01\">\n {moreSelected && indicator === 'pill' && (\n <ActiveIndicator indicator=\"pill\" layoutId={indicatorId} reduced={reduced} />\n )}\n <Icon icon={IconDots} />\n </div>\n {showMoreLabel && <span className=\"max-w-full truncate text-center\">More</span>}\n </div>\n </motion.button>\n </SheetTrigger>\n\n <SheetContent side=\"bottom\" className=\"rounded-t-bubble\">\n <SheetHeader>\n <SheetTitle>More</SheetTitle>\n </SheetHeader>\n <div className=\"grid grid-cols-[repeat(auto-fit,minmax(72px,1fr))] gap-ds-03 pt-ds-04\">\n {visibleMore.map((item) => {\n const active = isActive(item.href, item.exact)\n return (\n <Link\n key={item.href}\n href={item.href}\n onClick={() => setShowMore(false)}\n aria-current={active ? 'page' : undefined}\n className={cn(\n 'flex min-w-0 flex-col items-center gap-ds-02b rounded-overlay-lg p-ds-04 text-body-sm transition-colors ease-productive-standard',\n active\n ? 'bg-surface-raised-hover text-accent-11'\n : 'text-surface-fg-subtle hover:bg-surface-raised-hover',\n )}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\">\n <IconProvider size=\"md\">{normalizeIcon(item.icon)}</IconProvider>\n </span>\n <span className=\"max-w-full truncate text-center\">{item.title}</span>\n </Link>\n )\n })}\n </div>\n </SheetContent>\n </Sheet>\n )}\n </nav>\n )\n },\n)\nBottomNavbar.displayName = 'BottomNavbar'\n\nexport { BottomNavbar }\n"],"mappings":";;;;;;;;;;;;;;;;AAyFA,SAAS,EAAY,GAAqB,GAAwC;CAKhF,OAJI,EAAK,UAAgB,EAAK,QAAQ,CAAI,IACtC,EAAK,SAAS,EAAK,MAAM,SAAS,IAC7B,CAAC,CAAC,GAAM,QAAQ,EAAK,MAAM,SAAS,EAAK,IAAI,IAE/C;AACT;AAMA,SAAS,EAAS,EAAE,YAA4B;CAC9C,IAAI,CAAC,KAAS,KAAS,GAAG,OAAO;CACjC,IAAM,IAAU,IAAQ,KAAK,QAAQ,OAAO,CAAK;CACjD,OACE,kBAAC,GAAD;EACE,OAAM;EACN,SAAQ;EACR,MAAK;EACL,cAAY,GAAG,EAAM;EACrB,WAAU;YAET;CACI,CAAA;AAEX;AAWA,SAAS,EAAgB,EACvB,cACA,aACA,cAKC;CACD,IAAI,MAAc,QAAQ,OAAO;CACjC,IAAM,IAAS;EACb;EACA,eAAe;EACf,YAAY,IAAU,EAAE,UAAU,EAAE,IAAI,EAAQ;EAChD,SAAS,MAAkB,EAAE,SAAS,EAAE;EACxC,SAAS,EAAE,SAAS,EAAE;CACxB;CAQA,OAPI,MAAc,cACT,kBAAC,EAAO,MAAR;EAAa,GAAI;EAAQ,WAAU;CAAqE,CAAA,IAE7G,MAAc,SACT,kBAAC,EAAO,MAAR;EAAa,GAAI;EAAQ,WAAU;CAAgD,CAAA,IAGrF,kBAAC,EAAO,MAAR;EAAa,GAAI;EAAQ,WAAU;CAA6C,CAAA;AACzF;AAMA,IAAM,IACJ;AAEF,SAAS,EAAc,EACrB,SACA,aACA,cACA,gBACA,cACA,cAQC;CACD,IAAM,IAAO,EAAQ;CACrB,OACE,kBAAC,EAAO,KAAR;EACE,UAAU,IAAU,KAAA,IAAY,EAAE,OAAO,IAAK;EAC9C,YAAY,IAAU,EAAE,UAAU,EAAE,IAAI,EAAQ;EAChD,WAAU;YAEV,kBAAC,GAAD;GACE,MAAM,EAAK;GACX,cAAY,EAAK;GACjB,gBAAc,IAAW,SAAS,KAAA;GAClC,WAAW,EAAG,GAAW,IAAW,iCAAiC,wBAAwB;aAJ/F,CAOG,KAAY,MAAc,UACzB,kBAAC,GAAD;IAAiB,WAAU;IAAO,UAAU;IAAsB;GAAU,CAAA,GAE9E,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,KAAY,MAAc,eACzB,kBAAC,GAAD;MAAiB,WAAU;MAAY,UAAU;MAAsB;KAAU,CAAA;KAEnF,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACG,KAAY,MAAc,UACzB,kBAAC,GAAD;QAAiB,WAAU;QAAO,UAAU;QAAsB;OAAU,CAAA;OAE9E,kBAAC,QAAD;QAAM,WAAU;QAA6C,eAAY;kBACvE,kBAAC,GAAD;SAAc,MAAK;mBAChB,EAAc,KAAY,EAAK,aAAa,EAAK,aAAa,EAAK,IAAI;QAC5D,CAAA;OACV,CAAA;OACL,EAAK,SAAS,QAAQ,kBAAC,GAAD,EAAU,OAAO,EAAK,MAAQ,CAAA;MAClD;;KACJ,KAAa,kBAAC,QAAD;MAAM,WAAU;gBAAmC,EAAK;KAAY,CAAA;IAC/E;KACD;;CACI,CAAA;AAEhB;AAMA,IAAM,IAAe,EAAM,YAEvB,EACE,iBAAc,KACd,UAAO,MACP,kBAAe,CAAC,GAChB,eAAY,CAAC,GACb,eAAY,QACZ,qBAAkB,UAClB,cACA,GAAG,KAEL,MACG;CACH,IAAM,IAAO,EAAQ,GACf,IAAU,EAAiB,KAAK,IAChC,CAAC,GAAU,KAAe,EAAS,EAAK,GAGxC,IAAc,GADD,EAAM,MACF,EAAW,iBAE5B,KAAY,GAAc,IAAQ,OAClC,KAAS,MAAS,MAAY,MAAgB,IAC3C,EAAY,WAAW,CAAI,GAI9B,IAAiB,EAAa,QAAQ,MAAS,EAAY,GAAM,CAAI,CAAC,GACtE,IAAc,EAAU,QAAQ,MAAS,EAAY,GAAM,CAAI,CAAC,GAEhE,IAAe,EAAY,MAAM,MAAS,EAAS,EAAK,MAAM,EAAK,KAAK,CAAC,GACzE,IAAe,KAAY,GAC3B,IAAgB,MAAoB,YAAY;CAEtD,OACE,kBAAC,OAAD;EACE,GAAI;EACC;EACL,cAAW;EACX,WAAW,EACT,oLACA,CACF;YAPF,CASG,EAAe,KAAK,MACnB,kBAAC,GAAD;GAEQ;GACN,UAAU,EAAS,EAAK,MAAM,EAAK,KAAK;GAC7B;GACE;GACb,WAAW,MAAoB,YAAY,EAAS,EAAK,MAAM,EAAK,KAAK;GAChE;EACV,GAPM,EAAK,IAOX,CACF,GAEA,EAAY,SAAS,KACpB,kBAAC,GAAD;GAAO,MAAM;GAAU,cAAc;aAArC,CACE,kBAAC,GAAD;IAAc,SAAA;cACZ,kBAAC,EAAO,QAAR;KACE,MAAK;KACL,cAAW;KACX,UAAU,IAAU,KAAA,IAAY,EAAE,OAAO,IAAK;KAC9C,YAAY,IAAU,EAAE,UAAU,EAAE,IAAI,EAAQ;KAChD,WAAW,EACT,GACA,0BACA,IAAe,iCAAiC,wBAClD;eATF,CAWG,KAAgB,MAAc,UAC7B,kBAAC,GAAD;MAAiB,WAAU;MAAO,UAAU;MAAsB;KAAU,CAAA,GAE9E,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACG,KAAgB,MAAc,eAC7B,kBAAC,GAAD;QAAiB,WAAU;QAAY,UAAU;QAAsB;OAAU,CAAA;OAEnF,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACG,KAAgB,MAAc,UAC7B,kBAAC,GAAD;SAAiB,WAAU;SAAO,UAAU;SAAsB;QAAU,CAAA,GAE9E,kBAAC,GAAD,EAAM,MAAM,EAAW,CAAA,CACpB;;OACJ,KAAiB,kBAAC,QAAD;QAAM,WAAU;kBAAkC;OAAU,CAAA;MAC3E;OACQ;;GACH,CAAA,GAEd,kBAAC,GAAD;IAAc,MAAK;IAAS,WAAU;cAAtC,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAY,OAAgB,CAAA,EACjB,CAAA,GACb,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAY,KAAK,MAAS;MACzB,IAAM,IAAS,EAAS,EAAK,MAAM,EAAK,KAAK;MAC7C,OACE,kBAAC,GAAD;OAEE,MAAM,EAAK;OACX,eAAe,EAAY,EAAK;OAChC,gBAAc,IAAS,SAAS,KAAA;OAChC,WAAW,EACT,oIACA,IACI,2CACA,sDACN;iBAVF,CAYE,kBAAC,QAAD;QAAM,WAAU;QAAoC,eAAY;kBAC9D,kBAAC,GAAD;SAAc,MAAK;mBAAM,EAAc,EAAK,IAAI;QAAgB,CAAA;OAC5D,CAAA,GACN,kBAAC,QAAD;QAAM,WAAU;kBAAmC,EAAK;OAAY,CAAA,CAChE;SAfC,EAAK,IAeN;KAEV,CAAC;IACE,CAAA,CACO;KACT;IAEN;;AAET,CACF;AACA,EAAa,cAAc"}
1
+ {"version":3,"file":"bottom-navbar.js","names":[],"sources":["../../src/shell/bottom-navbar.tsx"],"sourcesContent":["'use client'\n\n/**\n * BottomNavbar -- Mobile bottom navigation bar.\n *\n * Props-driven (currentPath / user / items) and router-agnostic via `useLink`.\n * The \"More\" overflow uses the DS `Sheet` primitive, so it inherits focus trap,\n * scroll lock, return-focus, `aria-modal`, and trigger↔panel ARIA wiring.\n */\nimport { IconDots } from '@tabler/icons-react'\nimport { motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\nimport { useState } from 'react'\n\nimport { Badge } from '../ui/badge'\nimport { Icon } from '../ui/icon'\nimport { IconProvider } from '../ui/icon-context'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { springs } from '../ui/lib/motion'\nimport { normalizeIcon } from '../ui/lib/normalize-icon'\nimport { cn } from '../ui/lib/utils'\nimport { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '../ui/sheet'\nimport { useLink } from './link-context'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface BottomNavbarUser {\n name: string\n role?: string\n}\n\nexport interface BottomNavItem {\n title: string\n href: string\n /** Icon for this nav item. Accepts any `IconInput`. */\n icon: IconInput\n /** Icon shown when the item is active — e.g. a filled variant. Falls back to `icon`. */\n activeIcon?: IconInput\n /** When true, the route matches only when the path is exactly equal */\n exact?: boolean\n /** Notification badge count. 0 or undefined = hidden, 1–99 = shown, >99 = \"99+\" */\n badge?: number\n /**\n * Roles allowed to see this item, matched against `user.role`. Omit to show\n * it to everyone. For arbitrary logic, use `canView` instead.\n */\n roles?: string[]\n /**\n * Visibility predicate — full control over whether this item renders.\n * Receives the current `user` (or `null`). Takes precedence over `roles`.\n */\n canView?: (user: BottomNavbarUser | null) => boolean\n}\n\n/**\n * Active-item indicator, animated between items on selection:\n * - `pill` (default) — Material-3 tonal pill behind the icon\n * - `underline` — top accent bar (Material-2 tab style)\n * - `tint` — subtle background tint on the whole active cell\n * - `none` — no shape; rely on the filled `activeIcon` + accent color (iOS)\n */\nexport type BottomNavIndicator = 'pill' | 'underline' | 'tint' | 'none'\n/** Show labels always (default) or only for the selected item (narrow viewports). */\nexport type BottomNavLabelVisibility = 'always' | 'selected'\n\nexport interface BottomNavbarProps extends React.HTMLAttributes<HTMLElement> {\n /** Currently active pathname */\n currentPath?: string\n /** Current user. Drives per-item role gating via `item.roles` / `item.canView`. */\n user?: BottomNavbarUser | null\n /** Primary nav items shown directly in the bottom bar (max 4 recommended) */\n primaryItems?: BottomNavItem[]\n /** Additional items shown in the \"More\" overflow sheet */\n moreItems?: BottomNavItem[]\n /** Active-indicator style. @default 'pill' */\n indicator?: BottomNavIndicator\n /** Label visibility. @default 'always' */\n labelVisibility?: BottomNavLabelVisibility\n /** Additional className for the nav element */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// Helpers\n// -----------------------------------------------------------------------\n\n/** Per-item role/visibility gate. `canView` wins; else `roles` matched against user.role; else visible. */\nfunction itemVisible(item: BottomNavItem, user: BottomNavbarUser | null): boolean {\n if (item.canView) return item.canView(user)\n if (item.roles && item.roles.length > 0) {\n return !!user?.role && item.roles.includes(user.role)\n }\n return true\n}\n\n// -----------------------------------------------------------------------\n// NavBadge (composes Badge)\n// -----------------------------------------------------------------------\n\nfunction NavBadge({ count }: { count: number }) {\n if (!count || count <= 0) return null\n const display = count > 99 ? '99+' : String(count)\n return (\n <Badge\n color=\"error\"\n variant=\"solid\"\n size=\"xs\"\n aria-label={`${count} notifications`}\n className=\"pointer-events-none absolute -end-1 -top-1 justify-center px-ds-01 tabular-nums motion-safe:animate-in motion-safe:zoom-in-75\"\n >\n {display}\n </Badge>\n )\n}\n\n// -----------------------------------------------------------------------\n// Active indicator (shared-element)\n// -----------------------------------------------------------------------\n\n/**\n * The active-item indicator. A single shared-element (`layoutId`) that SLIDES\n * to the selected item and fades in on first appearance. `none` renders\n * nothing (the filled `activeIcon` + accent color carry the state).\n */\nfunction ActiveIndicator({\n indicator,\n layoutId,\n reduced,\n}: {\n indicator: BottomNavIndicator\n layoutId: string\n reduced: boolean\n}) {\n if (indicator === 'none') return null\n const common = {\n layoutId,\n 'aria-hidden': true as const,\n transition: reduced ? { duration: 0 } : springs.snappy,\n initial: reduced ? false : { opacity: 0 },\n animate: { opacity: 1 },\n }\n if (indicator === 'underline') {\n return <motion.span {...common} className=\"absolute top-0 h-[3px] w-full rounded-b-control-inner bg-accent-9\" />\n }\n if (indicator === 'tint') {\n return <motion.span {...common} className=\"absolute inset-0 rounded-control bg-accent-4\" />\n }\n // pill (default) — Material-3 tonal pill behind the icon\n return <motion.span {...common} className=\"absolute inset-0 rounded-pill bg-accent-4\" />\n}\n\n// -----------------------------------------------------------------------\n// BottomNavLink (internal)\n// -----------------------------------------------------------------------\n\nconst itemClass =\n 'relative flex h-16 w-full min-w-0 cursor-pointer flex-col items-center justify-center gap-ds-02 px-ds-01 pt-0 text-body-sm transition-colors duration-fast-02 ease-productive-standard'\n\nfunction BottomNavLink({\n item,\n isActive,\n indicator,\n indicatorId,\n showLabel,\n reduced,\n}: {\n item: BottomNavItem\n isActive: boolean\n indicator: BottomNavIndicator\n indicatorId: string\n showLabel: boolean\n reduced: boolean\n}) {\n const Link = useLink()\n return (\n <motion.div\n whileTap={reduced ? undefined : { scale: 0.96 }}\n transition={reduced ? { duration: 0 } : springs.snappy}\n className=\"flex min-w-0 flex-1 basis-0\"\n >\n <Link\n href={item.href}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n className={cn(itemClass, isActive ? 'font-semibold text-accent-11' : 'text-surface-fg-subtle')}\n >\n {/* tint covers the whole cell — sits behind the content */}\n {isActive && indicator === 'tint' && (\n <ActiveIndicator indicator=\"tint\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative flex w-full min-w-0 flex-col items-center gap-ds-02\">\n {isActive && indicator === 'underline' && (\n <ActiveIndicator indicator=\"underline\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative px-ds-04 py-ds-01\">\n {isActive && indicator === 'pill' && (\n <ActiveIndicator indicator=\"pill\" layoutId={indicatorId} reduced={reduced} />\n )}\n <span className=\"relative [&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\">\n <IconProvider size=\"md\">\n {normalizeIcon(isActive && item.activeIcon ? item.activeIcon : item.icon)}\n </IconProvider>\n </span>\n {item.badge != null && <NavBadge count={item.badge} />}\n </div>\n {showLabel && <span className=\"max-w-full truncate text-center\">{item.title}</span>}\n </div>\n </Link>\n </motion.div>\n )\n}\n\n// -----------------------------------------------------------------------\n// BottomNavbar\n// -----------------------------------------------------------------------\n\nconst BottomNavbar = React.forwardRef<HTMLElement, BottomNavbarProps>(\n (\n {\n currentPath = '/',\n user = null,\n primaryItems = [],\n moreItems = [],\n indicator = 'pill',\n labelVisibility = 'always',\n className,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const reduced = useReducedMotion() ?? false\n const [showMore, setShowMore] = useState(false)\n // Scope the shared-element layoutId per instance so two navbars don't animate into each other.\n const instanceId = React.useId()\n const indicatorId = `${instanceId}-nav-indicator`\n\n const isActive = (path: string, exact = false) => {\n if (exact || path === '/') return currentPath === path\n return currentPath.startsWith(path)\n }\n\n // Role/visibility gating\n const visiblePrimary = primaryItems.filter((item) => itemVisible(item, user))\n const visibleMore = moreItems.filter((item) => itemVisible(item, user))\n\n const isMoreActive = visibleMore.some((item) => isActive(item.href, item.exact))\n const moreSelected = showMore || isMoreActive\n const showMoreLabel = labelVisibility === 'always' || moreSelected\n\n return (\n <nav\n {...props}\n ref={ref}\n aria-label=\"Mobile navigation\"\n className={cn(\n 'fixed bottom-0 start-0 end-0 z-sticky flex w-full flex-row items-stretch justify-between border-t border-surface-border-strong bg-surface-base px-ds-05 pb-safe pt-0 md:hidden',\n className,\n )}\n >\n {visiblePrimary.map((item) => (\n <BottomNavLink\n key={item.href}\n item={item}\n isActive={isActive(item.href, item.exact)}\n indicator={indicator}\n indicatorId={indicatorId}\n showLabel={labelVisibility === 'always' || isActive(item.href, item.exact)}\n reduced={reduced}\n />\n ))}\n\n {visibleMore.length > 0 && (\n <Sheet open={showMore} onOpenChange={setShowMore}>\n <SheetTrigger asChild>\n <motion.button\n type=\"button\"\n aria-label=\"More navigation options\"\n whileTap={reduced ? undefined : { scale: 0.96 }}\n transition={reduced ? { duration: 0 } : springs.snappy}\n className={cn(\n itemClass,\n 'min-w-0 flex-1 basis-0',\n moreSelected ? 'font-semibold text-accent-11' : 'text-surface-fg-subtle',\n )}\n >\n {moreSelected && indicator === 'tint' && (\n <ActiveIndicator indicator=\"tint\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative flex w-full min-w-0 flex-col items-center gap-ds-02\">\n {moreSelected && indicator === 'underline' && (\n <ActiveIndicator indicator=\"underline\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative px-ds-04 py-ds-01\">\n {moreSelected && indicator === 'pill' && (\n <ActiveIndicator indicator=\"pill\" layoutId={indicatorId} reduced={reduced} />\n )}\n <Icon icon={IconDots} />\n </div>\n {showMoreLabel && <span className=\"max-w-full truncate text-center\">More</span>}\n </div>\n </motion.button>\n </SheetTrigger>\n\n <SheetContent side=\"bottom\" className=\"rounded-t-bubble\">\n <SheetHeader>\n <SheetTitle>More</SheetTitle>\n </SheetHeader>\n <div className=\"grid grid-cols-[repeat(auto-fit,minmax(72px,1fr))] gap-ds-03 pt-ds-04\">\n {visibleMore.map((item) => {\n const active = isActive(item.href, item.exact)\n return (\n <Link\n key={item.href}\n href={item.href}\n onClick={() => setShowMore(false)}\n aria-current={active ? 'page' : undefined}\n className={cn(\n 'flex min-w-0 flex-col items-center gap-ds-02b rounded-overlay-lg p-ds-04 text-body-sm transition-colors ease-productive-standard',\n active\n ? 'bg-surface-panel-hover text-accent-11'\n : 'text-surface-fg-subtle hover:bg-surface-panel-hover',\n )}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\">\n <IconProvider size=\"md\">{normalizeIcon(item.icon)}</IconProvider>\n </span>\n <span className=\"max-w-full truncate text-center\">{item.title}</span>\n </Link>\n )\n })}\n </div>\n </SheetContent>\n </Sheet>\n )}\n </nav>\n )\n },\n)\nBottomNavbar.displayName = 'BottomNavbar'\n\nexport { BottomNavbar }\n"],"mappings":"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"}
@@ -14,8 +14,9 @@
14
14
  export { AppCommandPalette, type AppCommandPaletteProps, type AppCommandPaletteUser, type SearchResult, type SearchResultGroup, } from './app-command-palette.js';
15
15
  export { BottomNavbar, type BottomNavbarProps, type BottomNavbarUser, type BottomNavItem, } from './bottom-navbar.js';
16
16
  export { type CommandPageItem, type CommandRegistry, CommandRegistryProvider, type CommandRegistryProviderProps, useCommandRegistry, } from './command-registry.js';
17
+ export { AppShell, AppShellBar, type AppShellBarProps, AppShellBody, AppShellCanvas, type AppShellProps, AppShellSidebar, type AppShellSidebarProps, } from './app-shell.js';
17
18
  export { LinkProvider, type LinkProviderProps, useLink } from './link-context.js';
18
- export { type Notification, NotificationCenter, type NotificationCenterProps, } from './notification-center.js';
19
+ export { type Notification, NotificationCenter, type NotificationCenterProps, type NotificationUnreadStyle, } from './notification-center.js';
19
20
  export { type NotificationPreference, NotificationPreferences, type NotificationPreferencesProps, type NotificationProject, } from './notification-preferences.js';
20
21
  export { TopBar, type TopBarProps, type TopBarUser, type UserMenuItem, } from './top-bar.js';
21
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACvB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,uBAAuB,EACvB,KAAK,4BAA4B,EACjC,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAC,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAC7E,OAAO,EACL,KAAK,YAAY,EACjB,kBAAkB,EAClB,KAAK,uBAAuB,GAC7B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,KAAK,sBAAsB,EAC3B,uBAAuB,EACvB,KAAK,4BAA4B,EACjC,KAAK,mBAAmB,GACzB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EACL,MAAM,EACN,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACvB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,uBAAuB,EACvB,KAAK,4BAA4B,EACjC,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,QAAQ,EACR,WAAW,EACX,KAAK,gBAAgB,EACrB,YAAY,EACZ,cAAc,EACd,KAAK,aAAa,EAClB,eAAe,EACf,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAC,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAC7E,OAAO,EACL,KAAK,YAAY,EACjB,kBAAkB,EAClB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,GAC7B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,KAAK,sBAAsB,EAC3B,uBAAuB,EACvB,KAAK,4BAA4B,EACjC,KAAK,mBAAmB,GACzB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EACL,MAAM,EACN,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,WAAW,CAAA"}
@@ -2,9 +2,10 @@
2
2
  import { LinkProvider as e, useLink as t } from "../_chunks/link-context.js";
3
3
  import { CommandRegistryProvider as n, useCommandRegistry as r } from "./command-registry.js";
4
4
  import { AppCommandPalette as i } from "./app-command-palette.js";
5
+ import { AppShell as a, AppShellBar as o, AppShellBody as s, AppShellCanvas as c, AppShellSidebar as l } from "./app-shell.js";
5
6
  import "./link-context.js";
6
- import { BottomNavbar as a } from "./bottom-navbar.js";
7
- import { NotificationCenter as o } from "./notification-center.js";
8
- import { NotificationPreferences as s } from "./notification-preferences.js";
9
- import { TopBar as c } from "./top-bar.js";
10
- export { i as AppCommandPalette, a as BottomNavbar, n as CommandRegistryProvider, e as LinkProvider, o as NotificationCenter, s as NotificationPreferences, c as TopBar, r as useCommandRegistry, t as useLink };
7
+ import { BottomNavbar as u } from "./bottom-navbar.js";
8
+ import { NotificationCenter as d } from "./notification-center.js";
9
+ import { NotificationPreferences as f } from "./notification-preferences.js";
10
+ import { TopBar as p } from "./top-bar.js";
11
+ export { i as AppCommandPalette, a as AppShell, o as AppShellBar, s as AppShellBody, c as AppShellCanvas, l as AppShellSidebar, u as BottomNavbar, n as CommandRegistryProvider, e as LinkProvider, d as NotificationCenter, f as NotificationPreferences, p as TopBar, r as useCommandRegistry, t as useLink };
@@ -23,6 +23,8 @@ export interface Notification {
23
23
  /** Inline action buttons (e.g. Approve / Deny). Max 2–3 recommended. */
24
24
  actions?: NotificationAction[];
25
25
  }
26
+ /** Visual weight of an unread row. See `NotificationCenterProps.unreadStyle`. */
27
+ export type NotificationUnreadStyle = 'tint' | 'strong' | 'none';
26
28
  export interface NotificationCenterProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
27
29
  /** List of notifications to display */
28
30
  notifications?: Notification[];
@@ -54,6 +56,21 @@ export interface NotificationCenterProps extends React.ButtonHTMLAttributes<HTML
54
56
  footerSlot?: React.ReactNode;
55
57
  /** Called when the user dismisses a notification. Renders an X button per row when provided. */
56
58
  onDismiss?: (id: string) => void;
59
+ /**
60
+ * How an unread row announces itself.
61
+ *
62
+ * - `tint` (default) — an accent wash plus a bold title. The conventional
63
+ * look, and the quietest fill that still reads louder than a hovered
64
+ * already-read row in both themes.
65
+ * - `strong` — a heavier wash, for inboxes where unread has to carry across
66
+ * a long list at a glance.
67
+ * - `none` — no wash at all. The tier dot (which already fades to 20% once
68
+ * read) and the bold title carry the state on their own. The calmest
69
+ * option, and the one that scales best down a long list.
70
+ *
71
+ * @default 'tint'
72
+ */
73
+ unreadStyle?: NotificationUnreadStyle;
57
74
  /** Additional className for the popover content container */
58
75
  popoverClassName?: string;
59
76
  /** Additional className */
@@ -1 +1 @@
1
- {"version":3,"file":"notification-center.d.ts","sourceRoot":"","sources":["../../src/shell/notification-center.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAgC9B,MAAM,WAAW,kBAAkB;IACjC,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;IAC1C,8EAA8E;IAC9E,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;IACvC,MAAM,EAAE,OAAO,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAClC,wEAAwE;IACxE,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAA;CAC/B;AAED,MAAM,WAAW,uBACf,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrD,uCAAuC;IACvC,aAAa,CAAC,EAAE,YAAY,EAAE,CAAA;IAC9B,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oDAAoD;IACpD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,iDAAiD;IACjD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,6CAA6C;IAC7C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,mDAAmD;IACnD,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,+CAA+C;IAC/C,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,4EAA4E;IAC5E,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,iFAAiF;IACjF,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,MAAM,GAAG,IAAI,CAAA;IACpE,wEAAwE;IACxE,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B,gGAAgG;IAChG,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAuKD,QAAA,MAAM,kBAAkB,mGAqPvB,CAAA;AAGD,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
1
+ {"version":3,"file":"notification-center.d.ts","sourceRoot":"","sources":["../../src/shell/notification-center.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAgC9B,MAAM,WAAW,kBAAkB;IACjC,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;IAC1C,8EAA8E;IAC9E,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;IACvC,MAAM,EAAE,OAAO,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAClC,wEAAwE;IACxE,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAA;CAC/B;AAED,iFAAiF;AACjF,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEhE,MAAM,WAAW,uBACf,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrD,uCAAuC;IACvC,aAAa,CAAC,EAAE,YAAY,EAAE,CAAA;IAC9B,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oDAAoD;IACpD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,iDAAiD;IACjD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,6CAA6C;IAC7C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,mDAAmD;IACnD,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,+CAA+C;IAC/C,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,4EAA4E;IAC5E,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,iFAAiF;IACjF,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,MAAM,GAAG,IAAI,CAAA;IACpE,wEAAwE;IACxE,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B,gGAAgG;IAChG,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC;;;;;;;;;;;;;OAaG;IACH,WAAW,CAAC,EAAE,uBAAuB,CAAA;IACrC,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AA4LD,QAAA,MAAM,kBAAkB,mGAuPvB,CAAA;AAGD,OAAO,EAAE,kBAAkB,EAAE,CAAA"}