@evinvest/uikit 0.30.0 → 0.32.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 (403) hide show
  1. package/README.md +267 -73
  2. package/dist/{chunk-3IPB4QQJ.js → chunk-35SPIU4U.js} +10 -6
  3. package/dist/chunk-35SPIU4U.js.map +1 -0
  4. package/dist/components/{accordion.js → atomic/accordion.js} +3 -3
  5. package/dist/components/atomic/accordion.js.map +1 -0
  6. package/dist/components/{alert-dialog.js → atomic/alert-dialog.js} +11 -10
  7. package/dist/components/atomic/alert-dialog.js.map +1 -0
  8. package/dist/components/{alert.js → atomic/alert.js} +2 -2
  9. package/dist/components/atomic/alert.js.map +1 -0
  10. package/dist/components/atomic/animated-number-columns.js +105 -0
  11. package/dist/components/atomic/animated-number-columns.js.map +1 -0
  12. package/dist/components/{avatar.js → atomic/avatar.js} +2 -2
  13. package/dist/components/atomic/avatar.js.map +1 -0
  14. package/dist/components/{badge.js → atomic/badge.js} +4 -4
  15. package/dist/components/atomic/badge.js.map +1 -0
  16. package/dist/components/{band.js → atomic/band.js} +2 -2
  17. package/dist/components/atomic/band.js.map +1 -0
  18. package/dist/components/{breadcrumb.js → atomic/breadcrumb.js} +3 -3
  19. package/dist/components/atomic/breadcrumb.js.map +1 -0
  20. package/dist/components/{button-group.js → atomic/button-group.js} +3 -3
  21. package/dist/components/atomic/button-group.js.map +1 -0
  22. package/dist/components/{button.js → atomic/button.js} +7 -15
  23. package/dist/components/atomic/button.js.map +1 -0
  24. package/dist/components/{calendar.js → atomic/calendar.js} +2 -2
  25. package/dist/components/atomic/calendar.js.map +1 -0
  26. package/dist/components/{card.js → atomic/card.js} +2 -2
  27. package/dist/components/atomic/card.js.map +1 -0
  28. package/dist/components/{checkbox.js → atomic/checkbox.js} +4 -4
  29. package/dist/components/atomic/checkbox.js.map +1 -0
  30. package/dist/components/{collapsible.js → atomic/collapsible.js} +1 -1
  31. package/dist/components/atomic/collapsible.js.map +1 -0
  32. package/dist/components/{command.js → atomic/command.js} +9 -7
  33. package/dist/components/atomic/command.js.map +1 -0
  34. package/dist/components/{container.js → atomic/container.js} +2 -2
  35. package/dist/components/atomic/container.js.map +1 -0
  36. package/dist/components/{context-menu.js → atomic/context-menu.js} +62 -14
  37. package/dist/components/atomic/context-menu.js.map +1 -0
  38. package/dist/components/{dialog.js → atomic/dialog.js} +11 -10
  39. package/dist/components/atomic/dialog.js.map +1 -0
  40. package/dist/components/{drawer.js → atomic/drawer.js} +10 -8
  41. package/dist/components/atomic/drawer.js.map +1 -0
  42. package/dist/components/{dropdown-menu.js → atomic/dropdown-menu.js} +74 -15
  43. package/dist/components/atomic/dropdown-menu.js.map +1 -0
  44. package/dist/components/{empty.js → atomic/empty.js} +2 -2
  45. package/dist/components/atomic/empty.js.map +1 -0
  46. package/dist/components/atomic/field-context.js.map +1 -0
  47. package/dist/components/atomic/form-row.js +51 -0
  48. package/dist/components/atomic/form-row.js.map +1 -0
  49. package/dist/components/{hover-card.js → atomic/hover-card.js} +8 -8
  50. package/dist/components/atomic/hover-card.js.map +1 -0
  51. package/dist/components/{info-tip.js → atomic/info-tip.js} +10 -10
  52. package/dist/components/atomic/info-tip.js.map +1 -0
  53. package/dist/components/{input-otp.js → atomic/input-otp.js} +3 -3
  54. package/dist/components/atomic/input-otp.js.map +1 -0
  55. package/dist/components/{input.js → atomic/input.js} +3 -3
  56. package/dist/components/atomic/input.js.map +1 -0
  57. package/dist/components/{kbd.js → atomic/kbd.js} +2 -2
  58. package/dist/components/atomic/kbd.js.map +1 -0
  59. package/dist/components/atomic/key-value.js +68 -0
  60. package/dist/components/atomic/key-value.js.map +1 -0
  61. package/dist/components/{label.js → atomic/label.js} +2 -2
  62. package/dist/components/atomic/label.js.map +1 -0
  63. package/dist/components/{menubar.js → atomic/menubar.js} +48 -14
  64. package/dist/components/atomic/menubar.js.map +1 -0
  65. package/dist/components/{native-select.js → atomic/native-select.js} +6 -7
  66. package/dist/components/atomic/native-select.js.map +1 -0
  67. package/dist/components/{navigation-menu.js → atomic/navigation-menu.js} +11 -12
  68. package/dist/components/atomic/navigation-menu.js.map +1 -0
  69. package/dist/components/{pagination.js → atomic/pagination.js} +1 -1
  70. package/dist/components/atomic/pagination.js.map +1 -0
  71. package/dist/components/{popover.js → atomic/popover.js} +10 -10
  72. package/dist/components/atomic/popover.js.map +1 -0
  73. package/dist/components/{progress.js → atomic/progress.js} +2 -2
  74. package/dist/components/atomic/progress.js.map +1 -0
  75. package/dist/components/{radio-group.js → atomic/radio-group.js} +4 -4
  76. package/dist/components/atomic/radio-group.js.map +1 -0
  77. package/dist/components/{scroll-area.js → atomic/scroll-area.js} +2 -2
  78. package/dist/components/atomic/scroll-area.js.map +1 -0
  79. package/dist/components/{section-descriptor.js → atomic/section-descriptor.js} +2 -2
  80. package/dist/components/atomic/section-descriptor.js.map +1 -0
  81. package/dist/components/{select-listbox.js → atomic/select-listbox.js} +1 -1
  82. package/dist/components/atomic/select-listbox.js.map +1 -0
  83. package/dist/components/{select.js → atomic/select.js} +26 -16
  84. package/dist/components/atomic/select.js.map +1 -0
  85. package/dist/components/{separator.js → atomic/separator.js} +2 -2
  86. package/dist/components/atomic/separator.js.map +1 -0
  87. package/dist/components/{sheet.js → atomic/sheet.js} +11 -10
  88. package/dist/components/atomic/sheet.js.map +1 -0
  89. package/dist/components/{sidebar.js → atomic/sidebar.js} +5 -5
  90. package/dist/components/atomic/sidebar.js.map +1 -0
  91. package/dist/components/{skeleton.js → atomic/skeleton.js} +2 -2
  92. package/dist/components/atomic/skeleton.js.map +1 -0
  93. package/dist/components/{slider.js → atomic/slider.js} +3 -3
  94. package/dist/components/atomic/slider.js.map +1 -0
  95. package/dist/components/{sonner.js → atomic/sonner.js} +2 -2
  96. package/dist/components/atomic/sonner.js.map +1 -0
  97. package/dist/components/{spinner.js → atomic/spinner.js} +1 -1
  98. package/dist/components/atomic/spinner.js.map +1 -0
  99. package/dist/components/atomic/status-item.js +42 -0
  100. package/dist/components/atomic/status-item.js.map +1 -0
  101. package/dist/components/{switch.js → atomic/switch.js} +4 -4
  102. package/dist/components/atomic/switch.js.map +1 -0
  103. package/dist/components/{table.js → atomic/table.js} +2 -2
  104. package/dist/components/atomic/table.js.map +1 -0
  105. package/dist/components/{tabs.js → atomic/tabs.js} +4 -4
  106. package/dist/components/atomic/tabs.js.map +1 -0
  107. package/dist/components/{textarea.js → atomic/textarea.js} +3 -3
  108. package/dist/components/atomic/textarea.js.map +1 -0
  109. package/dist/components/{toggle-group.js → atomic/toggle-group.js} +2 -2
  110. package/dist/components/atomic/toggle-group.js.map +1 -0
  111. package/dist/components/{toggle.js → atomic/toggle.js} +3 -3
  112. package/dist/components/atomic/toggle.js.map +1 -0
  113. package/dist/components/{tooltip.js → atomic/tooltip.js} +8 -8
  114. package/dist/components/atomic/tooltip.js.map +1 -0
  115. package/dist/components/atomic/use-count-tween.js +42 -0
  116. package/dist/components/atomic/use-count-tween.js.map +1 -0
  117. package/dist/components/derived/animated-number.js +157 -0
  118. package/dist/components/derived/animated-number.js.map +1 -0
  119. package/dist/components/{carousel.js → derived/carousel.js} +4 -4
  120. package/dist/components/derived/carousel.js.map +1 -0
  121. package/dist/components/derived/command-palette.js +119 -0
  122. package/dist/components/derived/command-palette.js.map +1 -0
  123. package/dist/components/derived/confirm-dialog.js +123 -0
  124. package/dist/components/derived/confirm-dialog.js.map +1 -0
  125. package/dist/components/{date-time-picker.js → derived/date-time-picker.js} +8 -8
  126. package/dist/components/derived/date-time-picker.js.map +1 -0
  127. package/dist/components/{field.js → derived/field.js} +6 -6
  128. package/dist/components/derived/field.js.map +1 -0
  129. package/dist/components/{form.js → derived/form.js} +4 -4
  130. package/dist/components/derived/form.js.map +1 -0
  131. package/dist/components/derived/icon-button.js +35 -0
  132. package/dist/components/derived/icon-button.js.map +1 -0
  133. package/dist/components/{input-group.js → derived/input-group.js} +5 -5
  134. package/dist/components/derived/input-group.js.map +1 -0
  135. package/dist/components/{item.js → derived/item.js} +4 -4
  136. package/dist/components/derived/item.js.map +1 -0
  137. package/dist/components/derived/popover-form.js +60 -0
  138. package/dist/components/derived/popover-form.js.map +1 -0
  139. package/dist/components/derived/settings.js +94 -0
  140. package/dist/components/derived/settings.js.map +1 -0
  141. package/dist/components/shell/account-list.js +128 -0
  142. package/dist/components/shell/account-list.js.map +1 -0
  143. package/dist/components/shell/account-menu-profile.js +114 -0
  144. package/dist/components/shell/account-menu-profile.js.map +1 -0
  145. package/dist/components/shell/account-menu.js +97 -0
  146. package/dist/components/shell/account-menu.js.map +1 -0
  147. package/dist/components/shell/account-settings-dialog.js +84 -0
  148. package/dist/components/shell/account-settings-dialog.js.map +1 -0
  149. package/dist/components/{app-shell.js → shell/app-shell.js} +10 -1
  150. package/dist/components/shell/app-shell.js.map +1 -0
  151. package/dist/components/shell/aside.js +140 -0
  152. package/dist/components/shell/aside.js.map +1 -0
  153. package/dist/components/{auth-wall.js → shell/auth-wall.js} +1 -1
  154. package/dist/components/shell/auth-wall.js.map +1 -0
  155. package/dist/components/{bottom-tab-bar.js → shell/bottom-tab-bar.js} +1 -1
  156. package/dist/components/shell/bottom-tab-bar.js.map +1 -0
  157. package/dist/components/shell/chat-composer.js +141 -0
  158. package/dist/components/shell/chat-composer.js.map +1 -0
  159. package/dist/components/shell/chat-message.js +195 -0
  160. package/dist/components/shell/chat-message.js.map +1 -0
  161. package/dist/components/shell/chat-panel.js +137 -0
  162. package/dist/components/shell/chat-panel.js.map +1 -0
  163. package/dist/components/shell/chat-stream-text.js +69 -0
  164. package/dist/components/shell/chat-stream-text.js.map +1 -0
  165. package/dist/components/shell/chat-typing.js +26 -0
  166. package/dist/components/shell/chat-typing.js.map +1 -0
  167. package/dist/components/{footer.js → shell/footer.js} +1 -1
  168. package/dist/components/shell/footer.js.map +1 -0
  169. package/dist/components/shell/header-controls.js +149 -0
  170. package/dist/components/shell/header-controls.js.map +1 -0
  171. package/dist/components/{list-rows.js → shell/list-rows.js} +1 -1
  172. package/dist/components/shell/list-rows.js.map +1 -0
  173. package/dist/components/{logo.js → shell/logo.js} +1 -1
  174. package/dist/components/shell/logo.js.map +1 -0
  175. package/dist/components/{mobile-app-bar.js → shell/mobile-app-bar.js} +1 -1
  176. package/dist/components/shell/mobile-app-bar.js.map +1 -0
  177. package/dist/components/{nav-badge.js → shell/nav-badge.js} +1 -1
  178. package/dist/components/shell/nav-badge.js.map +1 -0
  179. package/dist/components/shell/nav-collapse.js +142 -0
  180. package/dist/components/shell/nav-collapse.js.map +1 -0
  181. package/dist/components/shell/nav-link.js.map +1 -0
  182. package/dist/components/shell/nav-model.js.map +1 -0
  183. package/dist/components/{page-frame.js → shell/page-frame.js} +3 -6
  184. package/dist/components/shell/page-frame.js.map +1 -0
  185. package/dist/components/{resource-error.js → shell/resource-error.js} +4 -4
  186. package/dist/components/shell/resource-error.js.map +1 -0
  187. package/dist/components/shell/section-nav.js +139 -0
  188. package/dist/components/shell/section-nav.js.map +1 -0
  189. package/dist/components/shell/settled.js.map +1 -0
  190. package/dist/components/shell/shell-icons.js.map +1 -0
  191. package/dist/components/{shell-nav.js → shell/shell-nav.js} +81 -39
  192. package/dist/components/shell/shell-nav.js.map +1 -0
  193. package/dist/components/shell/smart-header.js +53 -0
  194. package/dist/components/shell/smart-header.js.map +1 -0
  195. package/dist/components/{status-screen.js → shell/status-screen.js} +3 -3
  196. package/dist/components/shell/status-screen.js.map +1 -0
  197. package/dist/components/{system-banner.js → shell/system-banner.js} +23 -13
  198. package/dist/components/shell/system-banner.js.map +1 -0
  199. package/dist/components/{top-bar.js → shell/top-bar.js} +5 -4
  200. package/dist/components/shell/top-bar.js.map +1 -0
  201. package/dist/components/shell/use-shell-nav.js.map +1 -0
  202. package/dist/components/shell/workspace-tab.js +140 -0
  203. package/dist/components/shell/workspace-tab.js.map +1 -0
  204. package/dist/generated/accent.js +2 -2
  205. package/dist/generated/accent.js.map +1 -1
  206. package/dist/generated/account-list.js +35 -0
  207. package/dist/generated/account-list.js.map +1 -0
  208. package/dist/generated/account-settings-dialog.js +27 -0
  209. package/dist/generated/account-settings-dialog.js.map +1 -0
  210. package/dist/generated/alert-dialog.js +1 -1
  211. package/dist/generated/alert-dialog.js.map +1 -1
  212. package/dist/generated/alert.js +2 -2
  213. package/dist/generated/alert.js.map +1 -1
  214. package/dist/generated/aside.js +36 -0
  215. package/dist/generated/aside.js.map +1 -0
  216. package/dist/generated/badge.js +7 -6
  217. package/dist/generated/badge.js.map +1 -1
  218. package/dist/generated/band.js +1 -1
  219. package/dist/generated/band.js.map +1 -1
  220. package/dist/generated/breadcrumb.js +2 -2
  221. package/dist/generated/breadcrumb.js.map +1 -1
  222. package/dist/generated/button-group.js +2 -2
  223. package/dist/generated/button-group.js.map +1 -1
  224. package/dist/generated/button.js +4 -4
  225. package/dist/generated/button.js.map +1 -1
  226. package/dist/generated/card.js +6 -6
  227. package/dist/generated/card.js.map +1 -1
  228. package/dist/generated/chat-composer.js +21 -0
  229. package/dist/generated/chat-composer.js.map +1 -0
  230. package/dist/generated/chat-message.js +86 -0
  231. package/dist/generated/chat-message.js.map +1 -0
  232. package/dist/generated/chat-typing.js +9 -0
  233. package/dist/generated/chat-typing.js.map +1 -0
  234. package/dist/generated/command-palette.js +17 -0
  235. package/dist/generated/command-palette.js.map +1 -0
  236. package/dist/generated/command.js +2 -2
  237. package/dist/generated/command.js.map +1 -1
  238. package/dist/generated/confirm-dialog.js +28 -0
  239. package/dist/generated/confirm-dialog.js.map +1 -0
  240. package/dist/generated/context-menu.js +1 -1
  241. package/dist/generated/context-menu.js.map +1 -1
  242. package/dist/generated/date-time-picker.js +1 -1
  243. package/dist/generated/date-time-picker.js.map +1 -1
  244. package/dist/generated/dialog.js +1 -1
  245. package/dist/generated/dialog.js.map +1 -1
  246. package/dist/generated/drawer.js +1 -1
  247. package/dist/generated/drawer.js.map +1 -1
  248. package/dist/generated/dropdown-menu.js +1 -1
  249. package/dist/generated/dropdown-menu.js.map +1 -1
  250. package/dist/generated/form-row.js +17 -0
  251. package/dist/generated/form-row.js.map +1 -0
  252. package/dist/generated/header-controls.js +56 -0
  253. package/dist/generated/header-controls.js.map +1 -0
  254. package/dist/generated/icon-button.js +13 -0
  255. package/dist/generated/icon-button.js.map +1 -0
  256. package/dist/generated/key-value.js +15 -0
  257. package/dist/generated/key-value.js.map +1 -0
  258. package/dist/generated/menubar.js +1 -1
  259. package/dist/generated/menubar.js.map +1 -1
  260. package/dist/generated/navigation-menu.js +1 -1
  261. package/dist/generated/navigation-menu.js.map +1 -1
  262. package/dist/generated/popover-form.js +13 -0
  263. package/dist/generated/popover-form.js.map +1 -0
  264. package/dist/generated/section-label.js +10 -0
  265. package/dist/generated/section-label.js.map +1 -0
  266. package/dist/generated/select.js +15 -3
  267. package/dist/generated/select.js.map +1 -1
  268. package/dist/generated/settings.js +36 -0
  269. package/dist/generated/settings.js.map +1 -0
  270. package/dist/generated/sheet.js +1 -1
  271. package/dist/generated/sheet.js.map +1 -1
  272. package/dist/generated/slider.js +1 -1
  273. package/dist/generated/slider.js.map +1 -1
  274. package/dist/generated/smart-header.js +11 -0
  275. package/dist/generated/smart-header.js.map +1 -0
  276. package/dist/generated/sonner.js +4 -4
  277. package/dist/generated/sonner.js.map +1 -1
  278. package/dist/generated/status-item.js +17 -0
  279. package/dist/generated/status-item.js.map +1 -0
  280. package/dist/generated/system-banner.js +33 -0
  281. package/dist/generated/system-banner.js.map +1 -0
  282. package/dist/generated/top-bar.js +9 -0
  283. package/dist/generated/top-bar.js.map +1 -0
  284. package/dist/generated/workspace-tab.js +17 -0
  285. package/dist/generated/workspace-tab.js.map +1 -0
  286. package/dist/icons/select-chevron.js.map +1 -0
  287. package/dist/icons/ui-icons.js +77 -0
  288. package/dist/icons/ui-icons.js.map +1 -0
  289. package/dist/index.d.ts +852 -156
  290. package/dist/index.js +96 -76
  291. package/dist/lib/cn.js +8 -1
  292. package/dist/lib/cn.js.map +1 -1
  293. package/dist/lib/number-parts.js +90 -0
  294. package/dist/lib/number-parts.js.map +1 -0
  295. package/dist/palette-cli.js +1 -1
  296. package/dist/palette.d.ts +6 -4
  297. package/dist/palette.js +3 -1
  298. package/dist/primitives/dismissable-layer.js +76 -4
  299. package/dist/primitives/dismissable-layer.js.map +1 -1
  300. package/dist/primitives/focus-scope.js +20 -5
  301. package/dist/primitives/focus-scope.js.map +1 -1
  302. package/dist/primitives/use-floating.js +16 -1
  303. package/dist/primitives/use-floating.js.map +1 -1
  304. package/dist/primitives/use-reduced-motion.js +20 -0
  305. package/dist/primitives/use-reduced-motion.js.map +1 -0
  306. package/package.json +2 -2
  307. package/styles/ev.css +281 -49
  308. package/styles/theme.css +335 -39
  309. package/styles/tokens.css +643 -103
  310. package/dist/chunk-3IPB4QQJ.js.map +0 -1
  311. package/dist/components/accordion.js.map +0 -1
  312. package/dist/components/account-menu.js +0 -70
  313. package/dist/components/account-menu.js.map +0 -1
  314. package/dist/components/alert-dialog.js.map +0 -1
  315. package/dist/components/alert.js.map +0 -1
  316. package/dist/components/app-shell.js.map +0 -1
  317. package/dist/components/auth-wall.js.map +0 -1
  318. package/dist/components/avatar.js.map +0 -1
  319. package/dist/components/badge.js.map +0 -1
  320. package/dist/components/band.js.map +0 -1
  321. package/dist/components/bottom-tab-bar.js.map +0 -1
  322. package/dist/components/breadcrumb.js.map +0 -1
  323. package/dist/components/button-group.js.map +0 -1
  324. package/dist/components/button.js.map +0 -1
  325. package/dist/components/calendar.js.map +0 -1
  326. package/dist/components/card.js.map +0 -1
  327. package/dist/components/carousel.js.map +0 -1
  328. package/dist/components/checkbox.js.map +0 -1
  329. package/dist/components/collapsible.js.map +0 -1
  330. package/dist/components/command.js.map +0 -1
  331. package/dist/components/container.js.map +0 -1
  332. package/dist/components/context-menu.js.map +0 -1
  333. package/dist/components/date-time-picker.js.map +0 -1
  334. package/dist/components/dialog.js.map +0 -1
  335. package/dist/components/drawer.js.map +0 -1
  336. package/dist/components/dropdown-menu.js.map +0 -1
  337. package/dist/components/empty.js.map +0 -1
  338. package/dist/components/field-context.js.map +0 -1
  339. package/dist/components/field.js.map +0 -1
  340. package/dist/components/footer.js.map +0 -1
  341. package/dist/components/form.js.map +0 -1
  342. package/dist/components/hover-card.js.map +0 -1
  343. package/dist/components/info-tip.js.map +0 -1
  344. package/dist/components/input-group.js.map +0 -1
  345. package/dist/components/input-otp.js.map +0 -1
  346. package/dist/components/input.js.map +0 -1
  347. package/dist/components/item.js.map +0 -1
  348. package/dist/components/kbd.js.map +0 -1
  349. package/dist/components/label.js.map +0 -1
  350. package/dist/components/list-rows.js.map +0 -1
  351. package/dist/components/logo.js.map +0 -1
  352. package/dist/components/menubar.js.map +0 -1
  353. package/dist/components/mobile-app-bar.js.map +0 -1
  354. package/dist/components/native-select.js.map +0 -1
  355. package/dist/components/nav-badge.js.map +0 -1
  356. package/dist/components/nav-link.js.map +0 -1
  357. package/dist/components/nav-model.js.map +0 -1
  358. package/dist/components/navigation-menu.js.map +0 -1
  359. package/dist/components/page-frame.js.map +0 -1
  360. package/dist/components/pagination.js.map +0 -1
  361. package/dist/components/popover.js.map +0 -1
  362. package/dist/components/progress.js.map +0 -1
  363. package/dist/components/radio-group.js.map +0 -1
  364. package/dist/components/resource-error.js.map +0 -1
  365. package/dist/components/scroll-area.js.map +0 -1
  366. package/dist/components/section-descriptor.js.map +0 -1
  367. package/dist/components/section-nav.js +0 -86
  368. package/dist/components/section-nav.js.map +0 -1
  369. package/dist/components/select-chevron.js.map +0 -1
  370. package/dist/components/select-listbox.js.map +0 -1
  371. package/dist/components/select.js.map +0 -1
  372. package/dist/components/separator.js.map +0 -1
  373. package/dist/components/settled.js.map +0 -1
  374. package/dist/components/sheet.js.map +0 -1
  375. package/dist/components/shell-icons.js.map +0 -1
  376. package/dist/components/shell-nav.js.map +0 -1
  377. package/dist/components/sidebar.js.map +0 -1
  378. package/dist/components/skeleton.js.map +0 -1
  379. package/dist/components/slider.js.map +0 -1
  380. package/dist/components/sonner.js.map +0 -1
  381. package/dist/components/spinner.js.map +0 -1
  382. package/dist/components/status-screen.js.map +0 -1
  383. package/dist/components/switch.js.map +0 -1
  384. package/dist/components/system-banner.js.map +0 -1
  385. package/dist/components/table.js.map +0 -1
  386. package/dist/components/tabs.js.map +0 -1
  387. package/dist/components/terminal.js +0 -206
  388. package/dist/components/terminal.js.map +0 -1
  389. package/dist/components/textarea.js.map +0 -1
  390. package/dist/components/toggle-group.js.map +0 -1
  391. package/dist/components/toggle.js.map +0 -1
  392. package/dist/components/tooltip.js.map +0 -1
  393. package/dist/components/top-bar.js.map +0 -1
  394. package/dist/components/use-shell-nav.js.map +0 -1
  395. package/dist/generated/terminal.js +0 -70
  396. package/dist/generated/terminal.js.map +0 -1
  397. /package/dist/components/{field-context.js → atomic/field-context.js} +0 -0
  398. /package/dist/components/{nav-link.js → shell/nav-link.js} +0 -0
  399. /package/dist/components/{nav-model.js → shell/nav-model.js} +0 -0
  400. /package/dist/components/{settled.js → shell/settled.js} +0 -0
  401. /package/dist/components/{shell-icons.js → shell/shell-icons.js} +0 -0
  402. /package/dist/components/{use-shell-nav.js → shell/use-shell-nav.js} +0 -0
  403. /package/dist/{components → icons}/select-chevron.js +0 -0
@@ -0,0 +1,139 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../../lib/cn.js";
5
+ import {
6
+ NavCollapse,
7
+ NavGroupHeader,
8
+ useNavGroupOpen
9
+ } from "./nav-collapse.js";
10
+ import { SectionLabel } from "./page-frame.js";
11
+ const ITEM = "flex h-8 w-full items-center gap-2.5 rounded-(--control-radius) px-2.5 text-left text-body outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-40";
12
+ function SectionNav({
13
+ groups,
14
+ value,
15
+ onValueChange,
16
+ linkComponent,
17
+ labels = {},
18
+ collapsible = false,
19
+ className,
20
+ ...props
21
+ }) {
22
+ return /* @__PURE__ */ jsx(
23
+ "nav",
24
+ {
25
+ "data-slot": "section-nav",
26
+ "aria-label": labels.nav ?? "Sections",
27
+ className: cn("flex w-64 shrink-0 flex-col gap-0.5", className),
28
+ ...props,
29
+ children: groups.map((group) => /* @__PURE__ */ jsx(
30
+ SectionNavGroupView,
31
+ {
32
+ group,
33
+ value,
34
+ onSelect: onValueChange,
35
+ linkComponent,
36
+ labels,
37
+ collapsible
38
+ },
39
+ group.id
40
+ ))
41
+ }
42
+ );
43
+ }
44
+ function SectionNavGroupView({
45
+ group,
46
+ value,
47
+ onSelect,
48
+ linkComponent,
49
+ labels,
50
+ collapsible
51
+ }) {
52
+ const labelId = React.useId();
53
+ const regionId = React.useId();
54
+ const [open, setOpen] = useNavGroupOpen(group, group.items.some((i) => i.id === value));
55
+ const folds = (group.collapsible ?? collapsible) && group.label !== void 0;
56
+ const rows = group.items.map((item) => /* @__PURE__ */ jsx(
57
+ SectionNavRow,
58
+ {
59
+ item,
60
+ active: item.id === value,
61
+ nested: folds,
62
+ onSelect,
63
+ linkComponent
64
+ },
65
+ item.id
66
+ ));
67
+ if (folds) {
68
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col pt-1.5 first:pt-0", children: [
69
+ /* @__PURE__ */ jsx(
70
+ NavGroupHeader,
71
+ {
72
+ label: group.label,
73
+ labelId,
74
+ regionId,
75
+ open,
76
+ onToggle: () => setOpen(!open),
77
+ href: group.href,
78
+ linkComponent,
79
+ labels
80
+ }
81
+ ),
82
+ /* @__PURE__ */ jsx(NavCollapse, { open, id: regionId, children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5 pt-0.5 pl-3", children: rows }) })
83
+ ] });
84
+ }
85
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5 pt-3.5 first:pt-0", children: [
86
+ (group.label !== void 0 || group.description !== void 0) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
87
+ group.label !== void 0 && /* @__PURE__ */ jsx(SectionLabel, { className: "px-2 py-1", children: group.label }),
88
+ group.description !== void 0 && /* @__PURE__ */ jsx("p", { className: "px-2 text-caption text-ink-soft", children: group.description })
89
+ ] }),
90
+ rows
91
+ ] });
92
+ }
93
+ function SectionNavRow({
94
+ item,
95
+ active,
96
+ nested,
97
+ onSelect,
98
+ linkComponent
99
+ }) {
100
+ const Icon = item.icon;
101
+ const className = cn(
102
+ ITEM,
103
+ active ? "bg-active text-ink" : "text-ink-mid hover:bg-hover",
104
+ nested && "h-9"
105
+ );
106
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
107
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "size-4 shrink-0 text-ink-soft" }),
108
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
109
+ item.trailing
110
+ ] });
111
+ if (item.href !== void 0 && !item.disabled) {
112
+ const Link = linkComponent ?? "a";
113
+ return /* @__PURE__ */ jsx(
114
+ Link,
115
+ {
116
+ href: item.href,
117
+ "aria-current": active ? "page" : void 0,
118
+ className,
119
+ onClick: () => onSelect?.(item.id),
120
+ children: content
121
+ }
122
+ );
123
+ }
124
+ return /* @__PURE__ */ jsx(
125
+ "button",
126
+ {
127
+ type: "button",
128
+ disabled: item.disabled,
129
+ "aria-current": active ? "true" : void 0,
130
+ className,
131
+ onClick: () => onSelect?.(item.id),
132
+ children: content
133
+ }
134
+ );
135
+ }
136
+ export {
137
+ SectionNav
138
+ };
139
+ //# sourceMappingURL=section-nav.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/section-nav.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport {\n NavCollapse,\n NavGroupHeader,\n useNavGroupOpen,\n type NavCollapseLabels,\n type NavGroupCollapse,\n} from \"./nav-collapse\";\nimport { SectionLabel } from \"./page-frame\";\n\nexport interface SectionNavItem {\n id: string;\n label: React.ReactNode;\n icon?: React.ComponentType<{ className?: string }>;\n /** A link (`?section=…`, a sub-route) instead of a button calling `onValueChange`. */\n href?: string;\n /** After the label — a count, a status chip. */\n trailing?: React.ReactNode;\n disabled?: boolean;\n}\n\nexport interface SectionNavGroup extends NavGroupCollapse {\n id: string;\n label?: React.ReactNode;\n /** One line under the label saying what kind of thing lives here. */\n description?: React.ReactNode;\n items: readonly SectionNavItem[];\n}\n\nexport interface SectionNavLabels extends NavCollapseLabels {\n /** Accessible name of the nav. Default `\"Sections\"`. */\n nav?: string;\n}\n\nexport interface SectionNavProps extends Omit<React.ComponentProps<\"nav\">, \"children\"> {\n groups: readonly SectionNavGroup[];\n /** The current section's id. */\n value: string;\n /** Called by button items (those without `href`), and by link items on click. */\n onValueChange?: (id: string) => void;\n linkComponent?: React.ElementType;\n labels?: SectionNavLabels;\n /** Makes every labelled group collapsible; a group's own `collapsible` wins. Default `false`. */\n collapsible?: boolean;\n}\n\nconst ITEM =\n \"flex h-8 w-full items-center gap-2.5 rounded-(--control-radius) px-2.5 text-left text-body outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-40\";\n\n/**\n * A screen's own section rail — settings panes, a document's chapters: grouped\n * rows, one current (`aria-current`), each a button or a link. The shell's rail\n * is `ShellNav`; this one lives inside a page, so it carries a tint rather than\n * the rail's solid marker and does not slide.\n */\nexport function SectionNav({\n groups,\n value,\n onValueChange,\n linkComponent,\n labels = {},\n collapsible = false,\n className,\n ...props\n}: SectionNavProps) {\n return (\n <nav\n data-slot=\"section-nav\"\n aria-label={labels.nav ?? \"Sections\"}\n className={cn(\"flex w-64 shrink-0 flex-col gap-0.5\", className)}\n {...props}\n >\n {groups.map((group) => (\n <SectionNavGroupView\n key={group.id}\n group={group}\n value={value}\n onSelect={onValueChange}\n linkComponent={linkComponent}\n labels={labels}\n collapsible={collapsible}\n />\n ))}\n </nav>\n );\n}\n\nfunction SectionNavGroupView({\n group,\n value,\n onSelect,\n linkComponent,\n labels,\n collapsible,\n}: {\n group: SectionNavGroup;\n value: string;\n onSelect: ((id: string) => void) | undefined;\n linkComponent: React.ElementType | undefined;\n labels: SectionNavLabels;\n collapsible: boolean;\n}) {\n const labelId = React.useId();\n const regionId = React.useId();\n const [open, setOpen] = useNavGroupOpen(group, group.items.some((i) => i.id === value));\n const folds = (group.collapsible ?? collapsible) && group.label !== undefined;\n const rows = group.items.map((item) => (\n <SectionNavRow\n key={item.id}\n item={item}\n active={item.id === value}\n nested={folds}\n onSelect={onSelect}\n linkComponent={linkComponent}\n />\n ));\n if (folds) {\n return (\n <div className=\"flex flex-col pt-1.5 first:pt-0\">\n <NavGroupHeader\n label={group.label}\n labelId={labelId}\n regionId={regionId}\n open={open}\n onToggle={() => setOpen(!open)}\n href={group.href}\n linkComponent={linkComponent}\n labels={labels}\n />\n <NavCollapse open={open} id={regionId}>\n <div className=\"flex flex-col gap-0.5 pt-0.5 pl-3\">{rows}</div>\n </NavCollapse>\n </div>\n );\n }\n return (\n <div className=\"flex flex-col gap-0.5 pt-3.5 first:pt-0\">\n {(group.label !== undefined || group.description !== undefined) && (\n <div className=\"flex flex-col\">\n {group.label !== undefined && <SectionLabel className=\"px-2 py-1\">{group.label}</SectionLabel>}\n {group.description !== undefined && (\n <p className=\"px-2 text-caption text-ink-soft\">{group.description}</p>\n )}\n </div>\n )}\n {rows}\n </div>\n );\n}\n\nfunction SectionNavRow({\n item,\n active,\n nested,\n onSelect,\n linkComponent,\n}: {\n item: SectionNavItem;\n active: boolean;\n nested: boolean;\n onSelect: ((id: string) => void) | undefined;\n linkComponent: React.ElementType | undefined;\n}) {\n const Icon = item.icon;\n const className = cn(\n ITEM,\n active ? \"bg-active text-ink\" : \"text-ink-mid hover:bg-hover\",\n nested && \"h-9\",\n );\n const content = (\n <>\n {Icon && <Icon className=\"size-4 shrink-0 text-ink-soft\" />}\n <span className=\"min-w-0 flex-1 truncate\">{item.label}</span>\n {item.trailing}\n </>\n );\n if (item.href !== undefined && !item.disabled) {\n const Link = linkComponent ?? \"a\";\n return (\n <Link\n href={item.href}\n aria-current={active ? \"page\" : undefined}\n className={className}\n onClick={() => onSelect?.(item.id)}\n >\n {content}\n </Link>\n );\n }\n return (\n <button\n type=\"button\"\n disabled={item.disabled}\n aria-current={active ? \"true\" : undefined}\n className={className}\n onClick={() => onSelect?.(item.id)}\n >\n {content}\n </button>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/settled.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nexport interface SettledProps extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** True while the data this surface needs is in flight. */\n loading: boolean;\n /** What stands in meanwhile — a `Skeleton` or a group of them. */\n skeleton: React.ReactNode;\n /** The content; also the empty and error states, guarded on the same condition. */\n children: React.ReactNode;\n}\n\n/**\n * The skeleton → content handover. Swapped in a single frame, a skeleton reads\n * as a flicker — the eye sees that something changed, not what. Here the\n * content fades and rises the last `--ev-rise` into place\n * (`data-state=\"revealed\"`, motion.css).\n *\n * Deliberately not a cross-fade: the two would have to overlap, which means\n * taking one out of flow and animating a height, and the surface would jump\n * when the content is a different size. And no entrance when no skeleton was\n * shown — data already present on the first render cuts straight in; fading it\n * would invent a delay the data never had.\n *\n * `data-state`: `loading` → `revealed` after a skeleton, `ready` without one.\n */\nexport function Settled({ loading, skeleton, children, ...props }: SettledProps) {\n // Adjusted during render, not in an effect, so the entrance plays on the very\n // first render after `loading` drops: an effect would paint the content opaque\n // once and only then start the fade. `reveals` keys the wrapper, so a later\n // refetch that shows the skeleton again gets a handover of its own.\n const [wasLoading, setWasLoading] = React.useState(loading);\n const [reveals, setReveals] = React.useState(0);\n if (wasLoading !== loading) {\n setWasLoading(loading);\n if (wasLoading) setReveals((n) => n + 1);\n }\n if (loading) {\n return (\n <div data-slot=\"settled\" data-state=\"loading\" aria-busy=\"true\" {...props}>\n {skeleton}\n </div>\n );\n }\n return (\n <div key={reveals} data-slot=\"settled\" data-state={reveals > 0 ? \"revealed\" : \"ready\"} {...props}>\n {children}\n </div>\n );\n}\n"],"mappings":";AAwCM;AAtCN,YAAY,WAAW;AAyBhB,SAAS,QAAQ,EAAE,SAAS,UAAU,UAAU,GAAG,MAAM,GAAiB;AAK/E,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,OAAO;AAC1D,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,CAAC;AAC9C,MAAI,eAAe,SAAS;AAC1B,kBAAc,OAAO;AACrB,QAAI,WAAY,YAAW,CAAC,MAAM,IAAI,CAAC;AAAA,EACzC;AACA,MAAI,SAAS;AACX,WACE,oBAAC,SAAI,aAAU,WAAU,cAAW,WAAU,aAAU,QAAQ,GAAG,OAChE,oBACH;AAAA,EAEJ;AACA,SACE,oBAAC,SAAkB,aAAU,WAAU,cAAY,UAAU,IAAI,aAAa,SAAU,GAAG,OACxF,YADO,OAEV;AAEJ;","names":[]}
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/shell-icons.tsx"],"sourcesContent":["import * as React from \"react\";\n\n// lucide glyphs the shell needs, inlined so the kit keeps its zero-icon-dep footprint.\nfunction Glyph({ className, children }: { className?: string | undefined; children: React.ReactNode }) {\n return (\n <svg\n className={className}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n {children}\n </svg>\n );\n}\n\nexport function ChevronLeftIcon({ className }: { className?: string | undefined }) {\n return (\n <Glyph className={className}>\n <path d=\"m15 18-6-6 6-6\" />\n </Glyph>\n );\n}\n\nexport function TriangleAlertIcon({ className }: { className?: string | undefined }) {\n return (\n <Glyph className={className}>\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </Glyph>\n );\n}\n\nexport function InfoIcon({ className }: { className?: string | undefined }) {\n return (\n <Glyph className={className}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n </Glyph>\n );\n}\n\nexport function RefreshIcon({ className }: { className?: string | undefined }) {\n return (\n <Glyph className={className}>\n <path d=\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\" />\n <path d=\"M21 3v5h-5\" />\n <path d=\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\" />\n <path d=\"M8 16H3v5\" />\n </Glyph>\n );\n}\n\nexport function CloseIcon({ className }: { className?: string | undefined }) {\n return (\n <Glyph className={className}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </Glyph>\n );\n}\n"],"mappings":"AAKI,cAyBA,YAzBA;AALJ,YAAY,WAAW;AAGvB,SAAS,MAAM,EAAE,WAAW,SAAS,GAAkE;AACrG,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAa;AAAA,MACb,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAW;AAAA,MAEV;AAAA;AAAA,EACH;AAEJ;AAEO,SAAS,gBAAgB,EAAE,UAAU,GAAuC;AACjF,SACE,oBAAC,SAAM,WACL,8BAAC,UAAK,GAAE,kBAAiB,GAC3B;AAEJ;AAEO,SAAS,kBAAkB,EAAE,UAAU,GAAuC;AACnF,SACE,qBAAC,SAAM,WACL;AAAA,wBAAC,UAAK,GAAE,4EAA2E;AAAA,IACnF,oBAAC,UAAK,GAAE,WAAU;AAAA,IAClB,oBAAC,UAAK,GAAE,cAAa;AAAA,KACvB;AAEJ;AAEO,SAAS,SAAS,EAAE,UAAU,GAAuC;AAC1E,SACE,qBAAC,SAAM,WACL;AAAA,wBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,IAC/B,oBAAC,UAAK,GAAE,aAAY;AAAA,IACpB,oBAAC,UAAK,GAAE,aAAY;AAAA,KACtB;AAEJ;AAEO,SAAS,YAAY,EAAE,UAAU,GAAuC;AAC7E,SACE,qBAAC,SAAM,WACL;AAAA,wBAAC,UAAK,GAAE,sDAAqD;AAAA,IAC7D,oBAAC,UAAK,GAAE,cAAa;AAAA,IACrB,oBAAC,UAAK,GAAE,uDAAsD;AAAA,IAC9D,oBAAC,UAAK,GAAE,aAAY;AAAA,KACtB;AAEJ;AAEO,SAAS,UAAU,EAAE,UAAU,GAAuC;AAC3E,SACE,qBAAC,SAAM,WACL;AAAA,wBAAC,UAAK,GAAE,cAAa;AAAA,IACrB,oBAAC,UAAK,GAAE,cAAa;AAAA,KACvB;AAEJ;","names":[]}
@@ -1,10 +1,14 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import { cn } from "../lib/cn.js";
4
+ import { cn } from "../../lib/cn.js";
5
5
  import { NavBadge } from "./nav-badge.js";
6
6
  import { labelTitle, NavLink } from "./nav-link.js";
7
- import { resolveActiveNavItem } from "./nav-model.js";
7
+ import { NavCollapse, NavGroupHeader, useNavGroupOpen } from "./nav-collapse.js";
8
+ import {
9
+ navItemMatch,
10
+ resolveActiveNavItem
11
+ } from "./nav-model.js";
8
12
  import { usePendingNavigation, useSlideMarker } from "./use-shell-nav.js";
9
13
  const NAV_FOCUS = "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-secondary";
10
14
  const ROW = "flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors";
@@ -19,6 +23,7 @@ function ShellNav({
19
23
  onItemIntent,
20
24
  onNavigate,
21
25
  labels = {},
26
+ collapsible = false,
22
27
  className,
23
28
  ...props
24
29
  }) {
@@ -31,6 +36,9 @@ function ShellNav({
31
36
  group,
32
37
  currentId,
33
38
  pendingId,
39
+ pathname,
40
+ labels,
41
+ collapsible,
34
42
  row: { linkComponent, markPending, onItemIntent, onNavigate, renderItem, badgeLabel: labels.badge }
35
43
  },
36
44
  group.id
@@ -58,48 +66,82 @@ function ShellNavSection({
58
66
  group,
59
67
  currentId,
60
68
  pendingId,
61
- row
69
+ pathname,
70
+ row,
71
+ labels,
72
+ collapsible
62
73
  }) {
63
- const root = React.useRef(null);
74
+ const body = React.useRef(null);
64
75
  const labelId = React.useId();
76
+ const regionId = React.useId();
65
77
  const at = group.items.some((i) => i.id === currentId) ? currentId ?? null : null;
66
- useSlideMarker(root, at);
67
- return /* @__PURE__ */ jsxs(
68
- "div",
69
- {
70
- ref: root,
71
- "data-slot": "shell-nav-section",
72
- className: cn("relative isolate flex flex-col gap-1", group.label !== void 0 && "pl-1"),
73
- children: [
74
- at !== null && /* @__PURE__ */ jsx(
75
- "span",
76
- {
77
- "data-slot": "shell-nav-marker",
78
- "aria-hidden": true,
79
- className: "pointer-events-none absolute left-0 top-0 -z-10 rounded-lg bg-primary"
80
- }
81
- ),
82
- group.label !== void 0 && /* @__PURE__ */ jsx("p", { id: labelId, className: "mb-0.5 text-xs font-semibold uppercase tracking-widest text-ink-soft", children: group.label }),
83
- /* @__PURE__ */ jsx(
84
- "ul",
78
+ const [open, setOpen] = useNavGroupOpen(group, at !== null);
79
+ useSlideMarker(body, at);
80
+ const folds = (group.collapsible ?? collapsible) && group.label !== void 0;
81
+ const landing = group.href !== void 0 && navItemMatch({ id: group.id, href: group.href, label: "", match: "exact" }, pathname) !== null;
82
+ const content = /* @__PURE__ */ jsxs("div", { ref: body, className: cn("relative isolate", folds && "pt-1"), children: [
83
+ at !== null && /* @__PURE__ */ jsx(
84
+ "span",
85
+ {
86
+ "data-slot": "shell-nav-marker",
87
+ "aria-hidden": true,
88
+ className: "pointer-events-none absolute left-0 top-0 -z-10 rounded-lg bg-primary"
89
+ }
90
+ ),
91
+ /* @__PURE__ */ jsx(
92
+ "ul",
93
+ {
94
+ "aria-labelledby": group.label !== void 0 ? labelId : void 0,
95
+ className: cn("flex flex-col gap-1", folds && "pl-3"),
96
+ children: group.items.map((item) => /* @__PURE__ */ jsx("li", { className: "flex flex-col", children: /* @__PURE__ */ jsx(
97
+ ShellNavRow,
85
98
  {
86
- "aria-labelledby": group.label !== void 0 ? labelId : void 0,
87
- className: "flex flex-col gap-1",
88
- children: group.items.map((item) => /* @__PURE__ */ jsx("li", { className: "flex flex-col", children: /* @__PURE__ */ jsx(
89
- ShellNavRow,
90
- {
91
- item,
92
- state: { active: item.id === currentId, pending: item.id === pendingId },
93
- row
94
- }
95
- ) }, item.id))
99
+ item,
100
+ nested: folds,
101
+ state: { active: item.id === currentId, pending: item.id === pendingId },
102
+ row
96
103
  }
97
- )
98
- ]
99
- }
100
- );
104
+ ) }, item.id))
105
+ }
106
+ )
107
+ ] });
108
+ if (!folds) {
109
+ return /* @__PURE__ */ jsxs(
110
+ "div",
111
+ {
112
+ "data-slot": "shell-nav-section",
113
+ className: cn("flex flex-col gap-1", group.label !== void 0 && "pl-1"),
114
+ children: [
115
+ group.label !== void 0 && /* @__PURE__ */ jsx("p", { id: labelId, className: "mb-0.5 text-xs font-semibold uppercase tracking-widest text-ink-soft", children: group.label }),
116
+ content
117
+ ]
118
+ }
119
+ );
120
+ }
121
+ return /* @__PURE__ */ jsxs("div", { "data-slot": "shell-nav-section", "data-state": open ? "open" : "closed", className: "flex flex-col", children: [
122
+ /* @__PURE__ */ jsx(
123
+ NavGroupHeader,
124
+ {
125
+ label: group.label,
126
+ labelId,
127
+ regionId,
128
+ open,
129
+ onToggle: () => setOpen(!open),
130
+ href: group.href,
131
+ linkComponent: row.linkComponent,
132
+ current: landing,
133
+ labels
134
+ }
135
+ ),
136
+ /* @__PURE__ */ jsx(NavCollapse, { open, id: regionId, children: content })
137
+ ] });
101
138
  }
102
- function ShellNavRow({ item, state, row }) {
139
+ function ShellNavRow({
140
+ item,
141
+ state,
142
+ row,
143
+ nested
144
+ }) {
103
145
  const Icon = item.icon;
104
146
  const trailing = typeof item.trailing === "function" ? item.trailing(state) : item.trailing;
105
147
  return /* @__PURE__ */ jsx(
@@ -116,7 +158,7 @@ function ShellNavRow({ item, state, row }) {
116
158
  className: cn(
117
159
  ROW,
118
160
  NAV_FOCUS,
119
- state.active ? "font-semibold text-on-primary" : "font-medium text-ink hover:bg-hover",
161
+ state.active ? "font-semibold text-on-primary" : cn("font-medium hover:bg-hover", nested ? "text-ink-mid" : "text-ink"),
120
162
  item.disabled && "cursor-not-allowed opacity-50 hover:bg-transparent"
121
163
  ),
122
164
  children: row.renderItem ? row.renderItem(item, state) : /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/shell-nav.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { NavBadge } from \"./nav-badge\";\nimport { labelTitle, NavLink, type NavLinkCallbacks } from \"./nav-link\";\nimport { NavCollapse, NavGroupHeader, useNavGroupOpen, type NavCollapseLabels } from \"./nav-collapse\";\nimport {\n navItemMatch,\n resolveActiveNavItem,\n type NavGroup,\n type NavItem,\n type NavItemState,\n} from \"./nav-model\";\nimport { usePendingNavigation, useSlideMarker } from \"./use-shell-nav\";\n\nexport interface ShellNavLabels extends NavCollapseLabels {\n /** Accessible name of the nav holding `groups`. Default `\"Main\"`. */\n primary?: string;\n /** Accessible name of the nav holding `footerGroups`. Default `\"Account\"`. */\n footer?: string;\n /** Spoken text of a numeric badge, given the real count. Default `\"{n} new\"`. */\n badge?: (count: number) => string;\n}\n\nexport interface ShellNavProps\n extends Omit<React.ComponentProps<\"aside\">, \"children\">,\n NavLinkCallbacks {\n groups: readonly NavGroup[];\n /** Pinned to the bottom of the rail (profile, notifications, settings). */\n footerGroups?: readonly NavGroup[];\n /** The router's current path — `usePathname()` in Next. */\n pathname: string;\n /** Your router's link (`next/link`); defaults to a plain `<a>`. */\n linkComponent?: React.ElementType;\n /** Above the groups — the brand lock-up. */\n header?: React.ReactNode;\n /** Below the footer groups — the signed-in account, a sign-out. */\n footer?: React.ReactNode;\n /** Replaces a row's content (icon, label, badge); the link, `aria-current` and the marker stay the kit's. */\n renderItem?: (item: NavItem, state: NavItemState) => React.ReactNode;\n labels?: ShellNavLabels;\n /** Makes every labelled group collapsible; a group's own `collapsible` wins. Default `false`. */\n collapsible?: boolean;\n}\n\n// The ring is the solid token, never a tint — at 50% it composites under the 3:1\n// non-text floor. The offset keeps it legible around the marked row, whose fill\n// is that same hue.\nconst NAV_FOCUS =\n \"outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-secondary\";\nconst ROW = \"flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors\";\n\n/**\n * The app's left rail: data-driven groups, a footer block pinned to the bottom,\n * one sliding marker per group, and an optimistic mark on click so the row\n * answers the click rather than the router's round-trip.\n *\n * Exactly one row across the rail is current — the strongest claim on the path\n * (see {@link resolveActiveNavItem}) — so overlapping `prefix` items are safe.\n * Visibility (roles, flags) is the caller's: pass only the items to show.\n */\nexport function ShellNav({\n groups,\n footerGroups = [],\n pathname,\n linkComponent,\n header,\n footer,\n renderItem,\n onItemIntent,\n onNavigate,\n labels = {},\n collapsible = false,\n className,\n ...props\n}: ShellNavProps) {\n const [pendingId, markPending] = usePendingNavigation(pathname);\n const all = [...groups, ...footerGroups].flatMap((g) => g.items);\n const currentId =\n (pendingId !== null && all.some((i) => i.id === pendingId) ? pendingId : undefined) ??\n resolveActiveNavItem(all, pathname)?.id;\n const section = (group: NavGroup) => (\n <ShellNavSection\n key={group.id}\n group={group}\n currentId={currentId}\n pendingId={pendingId}\n pathname={pathname}\n labels={labels}\n collapsible={collapsible}\n row={{ linkComponent, markPending, onItemIntent, onNavigate, renderItem, badgeLabel: labels.badge }}\n />\n );\n return (\n <aside\n data-slot=\"shell-nav\"\n className={cn(\n \"flex h-full w-(--shell-rail-w) flex-col gap-7 overflow-y-auto border-r border-border bg-secondary px-4.5 pb-5 pt-6\",\n className,\n )}\n {...props}\n >\n {header}\n <nav aria-label={labels.primary ?? \"Main\"} className=\"flex flex-col gap-4.5\">\n {groups.map(section)}\n </nav>\n <div className=\"flex-1\" />\n {footerGroups.length > 0 && (\n <nav aria-label={labels.footer ?? \"Account\"} className=\"flex flex-col gap-4.5\">\n {footerGroups.map(section)}\n </nav>\n )}\n {footer}\n </aside>\n );\n}\n\ninterface RowContext extends NavLinkCallbacks {\n linkComponent: React.ElementType | undefined;\n markPending: (id: string) => void;\n renderItem: ShellNavProps[\"renderItem\"];\n badgeLabel: ((count: number) => string) | undefined;\n}\n\n// One marker node per SECTION, mounted once and moved — not one per rail: a\n// marker travelling between groups would cross headings that have nothing to do\n// with either row. Crossing groups unmounts one marker and mounts another (a\n// fade). `isolate` is load-bearing: the marker sits on a negative z-index and\n// without its own stacking context would land behind the rail's background.\n// The marker lives in the BODY, below the header, so a folding section clips it\n// together with its rows instead of leaving it painted over the next group.\nfunction ShellNavSection({\n group,\n currentId,\n pendingId,\n pathname,\n row,\n labels,\n collapsible,\n}: {\n group: NavGroup;\n currentId: string | undefined;\n pendingId: string | null;\n pathname: string;\n row: RowContext;\n labels: ShellNavLabels;\n collapsible: boolean;\n}) {\n const body = React.useRef<HTMLDivElement>(null);\n const labelId = React.useId();\n const regionId = React.useId();\n const at = group.items.some((i) => i.id === currentId) ? (currentId ?? null) : null;\n const [open, setOpen] = useNavGroupOpen(group, at !== null);\n useSlideMarker(body, at);\n const folds = (group.collapsible ?? collapsible) && group.label !== undefined;\n const landing =\n group.href !== undefined &&\n navItemMatch({ id: group.id, href: group.href, label: \"\", match: \"exact\" }, pathname) !== null;\n const content = (\n <div ref={body} className={cn(\"relative isolate\", folds && \"pt-1\")}>\n {/* First in DOM order: the pre-hydration fill in motion.css reaches the marked\n row through a sibling combinator, which only looks forward. */}\n {at !== null && (\n <span\n data-slot=\"shell-nav-marker\"\n aria-hidden\n className=\"pointer-events-none absolute left-0 top-0 -z-10 rounded-lg bg-primary\"\n />\n )}\n <ul\n aria-labelledby={group.label !== undefined ? labelId : undefined}\n className={cn(\"flex flex-col gap-1\", folds && \"pl-3\")}\n >\n {group.items.map((item) => (\n <li key={item.id} className=\"flex flex-col\">\n <ShellNavRow\n item={item}\n nested={folds}\n state={{ active: item.id === currentId, pending: item.id === pendingId }}\n row={row}\n />\n </li>\n ))}\n </ul>\n </div>\n );\n if (!folds) {\n return (\n <div\n data-slot=\"shell-nav-section\"\n className={cn(\"flex flex-col gap-1\", group.label !== undefined && \"pl-1\")}\n >\n {group.label !== undefined && (\n <p id={labelId} className=\"mb-0.5 text-xs font-semibold uppercase tracking-widest text-ink-soft\">\n {group.label}\n </p>\n )}\n {content}\n </div>\n );\n }\n return (\n <div data-slot=\"shell-nav-section\" data-state={open ? \"open\" : \"closed\"} className=\"flex flex-col\">\n <NavGroupHeader\n label={group.label}\n labelId={labelId}\n regionId={regionId}\n open={open}\n onToggle={() => setOpen(!open)}\n href={group.href}\n linkComponent={row.linkComponent}\n current={landing}\n labels={labels}\n />\n <NavCollapse open={open} id={regionId}>\n {content}\n </NavCollapse>\n </div>\n );\n}\n\nfunction ShellNavRow({\n item,\n state,\n row,\n nested,\n}: {\n item: NavItem;\n state: NavItemState;\n row: RowContext;\n nested: boolean;\n}) {\n const Icon = item.icon;\n const trailing = typeof item.trailing === \"function\" ? item.trailing(state) : item.trailing;\n return (\n <NavLink\n item={item}\n current={state.active}\n pending={state.pending}\n linkComponent={row.linkComponent}\n markPending={row.markPending}\n onItemIntent={row.onItemIntent}\n onNavigate={row.onNavigate}\n title={labelTitle(item.label)}\n className={cn(\n ROW,\n NAV_FOCUS,\n state.active\n ? \"font-semibold text-on-primary\"\n : cn(\"font-medium hover:bg-hover\", nested ? \"text-ink-mid\" : \"text-ink\"),\n item.disabled && \"cursor-not-allowed opacity-50 hover:bg-transparent\",\n )}\n >\n {row.renderItem ? (\n row.renderItem(item, state)\n ) : (\n <>\n {Icon && <Icon className=\"size-4.5 shrink-0\" />}\n {/* `min-w-0`: without it the label refuses to shrink below its own text and\n the rail widens to the longest translation instead of truncating. */}\n <span className=\"min-w-0 flex-1 truncate\">{item.label}</span>\n {typeof item.badge === \"number\" ? (\n <NavBadge\n count={item.badge}\n active={state.active}\n {...(row.badgeLabel ? { label: row.badgeLabel } : {})}\n />\n ) : (\n item.badge\n )}\n {trailing}\n </>\n )}\n </NavLink>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,53 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cn } from "../../lib/cn.js";
4
+ import {
5
+ SMART_HEADER_BAR,
6
+ SMART_HEADER_BASE,
7
+ SMART_HEADER_CONTEXT,
8
+ SMART_HEADER_TOOLBAR
9
+ } from "../../generated/smart-header.js";
10
+ import { TopBar } from "./top-bar.js";
11
+ function SmartHeader({
12
+ state = "default",
13
+ start,
14
+ end,
15
+ collapsed,
16
+ banner,
17
+ toolbar,
18
+ context,
19
+ palette,
20
+ className,
21
+ ...props
22
+ }) {
23
+ return /* @__PURE__ */ jsxs(
24
+ "div",
25
+ {
26
+ "data-slot": "smart-header",
27
+ "data-state": state,
28
+ className: cn(SMART_HEADER_BASE, className),
29
+ ...props,
30
+ children: [
31
+ state === "banner" && banner,
32
+ /* @__PURE__ */ jsx(
33
+ TopBar,
34
+ {
35
+ className: SMART_HEADER_BAR,
36
+ start: /* @__PURE__ */ jsxs(Fragment, { children: [
37
+ start,
38
+ state === "collapsed" && collapsed
39
+ ] }),
40
+ end
41
+ }
42
+ ),
43
+ state === "default" && toolbar != null && /* @__PURE__ */ jsx("div", { "data-slot": "smart-header-toolbar", className: SMART_HEADER_TOOLBAR, children: toolbar }),
44
+ state === "default" && context != null && /* @__PURE__ */ jsx("div", { "data-slot": "smart-header-context", className: SMART_HEADER_CONTEXT, children: context }),
45
+ state === "search" && palette != null && /* @__PURE__ */ jsx("div", { "data-slot": "smart-header-palette", children: palette })
46
+ ]
47
+ }
48
+ );
49
+ }
50
+ export {
51
+ SmartHeader
52
+ };
53
+ //# sourceMappingURL=smart-header.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/smart-header.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport {\n SMART_HEADER_BAR,\n SMART_HEADER_BASE,\n SMART_HEADER_CONTEXT,\n SMART_HEADER_TOOLBAR,\n} from \"../../generated/smart-header\";\nimport { TopBar } from \"./top-bar\";\n\nexport type SmartHeaderState = \"default\" | \"collapsed\" | \"banner\" | \"search\";\n\nexport interface SmartHeaderProps extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /**\n * `default` — bar, toolbar and context line; `collapsed` — the toolbar folds\n * into the bar as `collapsed`; `banner` — a banner row above one bar;\n * `search` — one bar with the `palette` under it.\n */\n state?: SmartHeaderState;\n /** Brand, workspace tabs: the left side of the bar. */\n start?: React.ReactNode;\n /** The right side of the bar: icon actions, balance, bell, account menu. */\n end?: React.ReactNode;\n /** The folded toolbar, between `start` and `end`; shown in `collapsed` only. */\n collapsed?: React.ReactNode;\n /** A `SystemBanner`; shown in `banner` only. */\n banner?: React.ReactNode;\n /** The second row, 44 high; shown in `default` only. */\n toolbar?: React.ReactNode;\n /** The slim line on the page fill under the toolbar; shown in `default` only. */\n context?: React.ReactNode;\n /** A `CommandPalette` or any panel that drops from the bar; shown in `search` only. */\n palette?: React.ReactNode;\n}\n\n/**\n * A page header that adapts to scroll and alerts. The bar is the same in every\n * state, so switching never moves the brand or the account: only the rows\n * around it come and go. Layout only; the caller owns the state and its trigger\n * (a scroll observer, a feed status, the search button).\n */\nexport function SmartHeader({\n state = \"default\",\n start,\n end,\n collapsed,\n banner,\n toolbar,\n context,\n palette,\n className,\n ...props\n}: SmartHeaderProps) {\n return (\n <div\n data-slot=\"smart-header\"\n data-state={state}\n className={cn(SMART_HEADER_BASE, className)}\n {...props}\n >\n {state === \"banner\" && banner}\n <TopBar\n className={SMART_HEADER_BAR}\n start={\n <>\n {start}\n {state === \"collapsed\" && collapsed}\n </>\n }\n end={end}\n />\n {state === \"default\" && toolbar != null && (\n <div data-slot=\"smart-header-toolbar\" className={SMART_HEADER_TOOLBAR}>\n {toolbar}\n </div>\n )}\n {state === \"default\" && context != null && (\n <div data-slot=\"smart-header-context\" className={SMART_HEADER_CONTEXT}>\n {context}\n </div>\n )}\n {state === \"search\" && palette != null && <div data-slot=\"smart-header-palette\">{palette}</div>}\n </div>\n );\n}\n"],"mappings":"AA6DM,SAGI,UAHJ,KAGI,YAHJ;AA7DN,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc;AAiChB,SAAS,YAAY;AAAA,EAC1B,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAqB;AACnB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,cAAY;AAAA,MACZ,WAAW,GAAG,mBAAmB,SAAS;AAAA,MACzC,GAAG;AAAA,MAEH;AAAA,kBAAU,YAAY;AAAA,QACvB;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,YACX,OACE,iCACG;AAAA;AAAA,cACA,UAAU,eAAe;AAAA,eAC5B;AAAA,YAEF;AAAA;AAAA,QACF;AAAA,QACC,UAAU,aAAa,WAAW,QACjC,oBAAC,SAAI,aAAU,wBAAuB,WAAW,sBAC9C,mBACH;AAAA,QAED,UAAU,aAAa,WAAW,QACjC,oBAAC,SAAI,aAAU,wBAAuB,WAAW,sBAC9C,mBACH;AAAA,QAED,UAAU,YAAY,WAAW,QAAQ,oBAAC,SAAI,aAAU,wBAAwB,mBAAQ;AAAA;AAAA;AAAA,EAC3F;AAEJ;","names":[]}
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import { cn } from "../lib/cn.js";
5
- import { accentTextClasses } from "../generated/accent.js";
6
- import { buttonVariants } from "./button.js";
4
+ import { cn } from "../../lib/cn.js";
5
+ import { accentTextClasses } from "../../generated/accent.js";
6
+ import { buttonVariants } from "../atomic/button.js";
7
7
  import { Logo } from "./logo.js";
8
8
  function statusCtaClass(accent, variant) {
9
9
  return cn(
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/status-screen.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { accentTextClasses, type Accent } from \"../../generated/accent\";\nimport { buttonVariants, type ButtonVariant } from \"../atomic/button\";\nimport { Logo } from \"./logo\";\n\n/**\n * The shared 404 / 403 / 500 status surface.\n *\n * `StatusScreen` is the generic shell; `NotFound` / `Forbidden` / `ServerError`\n * are the ready-made pages with their copy baked in — a host renders those with\n * its own hrefs. The mark is `Logo`'s, i.e. the consumer's. Links default to a\n * plain `<a>` (a full document load, which is what you want off an error page);\n * pass `linkComponent` (e.g. `next/link`) for soft navigation from a client\n * boundary.\n */\nexport type { Accent };\n\n/**\n * A status CTA is a Button at the page's accent: the canonical button string for\n * that variant and rung, then the mono/uppercase treatment the error pages wear.\n *\n * Exported because a host that renders its own action into `StatusScreen`'s\n * slot — a retry button wired to Next's `reset`, say — has to be able to match\n * the CTAs beside it.\n */\nexport function statusCtaClass(accent: Accent, variant: ButtonVariant) {\n return cn(\n buttonVariants({ variant, size: \"lg\", accent }),\n \"font-mono text-xs uppercase tracking-widest\",\n );\n}\n\n// lucide `arrow-left`, inlined so the kit keeps its zero-icon-dep footprint.\nfunction ArrowLeftIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <path d=\"m12 19-7-7 7-7\" />\n <path d=\"M19 12H5\" />\n </svg>\n );\n}\n\nexport interface StatusLinkData {\n label: string;\n href: string;\n variant?: ButtonVariant;\n leadingArrow?: boolean;\n}\n\nexport interface StatusScreenProps {\n accent: Accent;\n eyebrow: string;\n code: string;\n headlineLead: string;\n headlineAccent: string;\n headlineTail?: string;\n subtext: string;\n links?: StatusLinkData[];\n /** Leading action slot, rendered before `links` (e.g. the 500 client retry). */\n children?: React.ReactNode;\n /** CTA element — `next/link` for soft nav; defaults to `<a>` (full load). */\n linkComponent?: React.ElementType;\n}\n\n/**\n * Shared skeleton for the 404 / 403 / 500 status pages: a centred hero with the\n * logo mark, a mono eyebrow, a giant Playfair code, a headline whose final clause\n * is an italic accent, supporting copy, and the CTAs. The accent threads through\n * all four marks. Actions render inline (from `links` data, plus an optional\n * `children` slot) — never passed as a JSX prop through a server boundary.\n */\nexport function StatusScreen({\n accent,\n eyebrow,\n code,\n headlineLead,\n headlineAccent,\n headlineTail = \".\",\n subtext,\n links,\n children,\n linkComponent,\n}: StatusScreenProps) {\n const L = linkComponent ?? \"a\";\n const accentText = accentTextClasses[accent];\n return (\n <section className=\"relative flex min-h-screen flex-col items-center justify-center overflow-hidden bg-background px-6 py-32 text-center\">\n <div\n aria-hidden\n className={cn(\n \"pointer-events-none absolute inset-0 opacity-[0.07] [background:radial-gradient(55%_45%_at_50%_30%,currentColor,transparent_70%)]\",\n accentText,\n )}\n />\n <div className=\"relative z-10 flex w-full max-w-2xl flex-col items-center\">\n <Logo className={cn(\"mb-7 h-10 w-auto\", accentText)} />\n <p className={cn(\"mb-6 font-mono text-[11px] uppercase tracking-[0.34em]\", accentText)}>{eyebrow}</p>\n <p className={cn(\"font-serif text-[110px] font-medium leading-[0.9] sm:text-[180px]\", accentText)}>{code}</p>\n <h1 className=\"mt-4 font-serif text-3xl font-light leading-tight text-ink sm:text-5xl\">\n {headlineLead}\n <span className={cn(\"font-serif italic\", accentText)}>{headlineAccent}</span>\n {headlineTail}\n </h1>\n <p className=\"mx-auto mt-5 max-w-md text-sm leading-relaxed text-ink/60 sm:text-base\">{subtext}</p>\n <div className=\"mt-9 flex flex-col items-center gap-3 sm:flex-row\">\n {children}\n {links?.map((link) => (\n <L key={link.label} href={link.href} className={statusCtaClass(accent, link.variant ?? \"primary\")}>\n {link.leadingArrow ? <ArrowLeftIcon className=\"mr-2 h-4 w-4\" /> : null}\n {link.label}\n </L>\n ))}\n </div>\n </div>\n </section>\n );\n}\n\nexport interface StatusPageProps {\n /** CTA element — `next/link` for soft nav; defaults to `<a>` (full load). */\n linkComponent?: React.ElementType;\n /** \"Back to home\" target — `/` for the landing, `/cabinet` for the cabinet. */\n homeHref?: string;\n /** Secondary CTA target (contact / request access). */\n contactHref?: string;\n}\n\n/** 404 — page not found. */\nexport function NotFound({ linkComponent = \"a\", homeHref = \"/\", contactHref = \"/contact\" }: StatusPageProps) {\n return (\n <StatusScreen\n accent=\"debug\"\n eyebrow=\"Page not found\"\n code=\"404\"\n headlineLead=\"You've reached \"\n headlineAccent=\"open water\"\n subtext=\"The page you're looking for has drifted off our coastline — moved, renamed, or never charted. Let's get you back to shore.\"\n linkComponent={linkComponent}\n links={[\n { label: \"Back to home\", href: homeHref, leadingArrow: true },\n { label: \"Contact the team\", href: contactHref, variant: \"outline\" },\n ]}\n />\n );\n}\n\n/** 403 — access forbidden. */\nexport function Forbidden({ linkComponent = \"a\", homeHref = \"/\", contactHref = \"/contact\" }: StatusPageProps) {\n return (\n <StatusScreen\n accent=\"warn\"\n eyebrow=\"Access forbidden\"\n code=\"403\"\n headlineLead=\"This harbour is \"\n headlineAccent=\"private\"\n subtext=\"You don't have the credentials to view this page. If you believe you should, our team can open the right doors.\"\n linkComponent={linkComponent}\n links={[\n { label: \"Back to home\", href: homeHref, leadingArrow: true },\n { label: \"Request access\", href: contactHref, variant: \"outline\" },\n ]}\n />\n );\n}\n\nexport interface ServerErrorProps {\n /** CTA element — `next/link` for soft nav; defaults to `<a>` (full load). */\n linkComponent?: React.ElementType;\n /** \"Back to home\" target — `/` for the landing, `/cabinet` for the cabinet. */\n homeHref?: string;\n /** Retry handler (e.g. Next's error-boundary `reset`); falls back to a reload. */\n reset?: () => void;\n}\n\n/** 500 — server error. The \"Try again\" button runs `reset` or reloads the page. */\nexport function ServerError({ linkComponent = \"a\", homeHref = \"/\", reset }: ServerErrorProps) {\n return (\n <StatusScreen\n accent=\"error\"\n eyebrow=\"Server error\"\n code=\"500\"\n headlineLead=\"Our systems are \"\n headlineAccent=\"recalibrating\"\n subtext=\"Something broke on our end — not yours. We've been alerted and are restoring service. Please try again in a moment.\"\n linkComponent={linkComponent}\n links={[{ label: \"Back to home\", href: homeHref, variant: \"outline\", leadingArrow: true }]}\n >\n <button\n type=\"button\"\n className={statusCtaClass(\"error\", \"primary\")}\n onClick={() => (reset ? reset() : window.location.reload())}\n >\n Try again\n </button>\n </StatusScreen>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,46 +1,56 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import { cn } from "../lib/cn.js";
4
+ import { cn } from "../../lib/cn.js";
5
+ import {
6
+ SYSTEM_BANNER_ACTION,
7
+ SYSTEM_BANNER_BASE,
8
+ SYSTEM_BANNER_BODY_AFTER_TITLE,
9
+ SYSTEM_BANNER_DISMISS,
10
+ SYSTEM_BANNER_GLYPH,
11
+ SYSTEM_BANNER_ICON,
12
+ SYSTEM_BANNER_MESSAGE,
13
+ SYSTEM_BANNER_TITLE,
14
+ systemBannerIconToneClasses,
15
+ systemBannerToneClasses
16
+ } from "../../generated/system-banner.js";
5
17
  import { CloseIcon, InfoIcon, TriangleAlertIcon } from "./shell-icons.js";
6
- const TONE = {
7
- warn: "border-accent-warn/40 bg-accent-warn/10 text-accent-warn",
8
- info: "border-border bg-card text-ink"
9
- };
10
18
  function SystemBanner({
11
19
  tone = "info",
12
20
  title,
13
21
  icon,
14
22
  onDismiss,
23
+ action,
15
24
  labels = {},
16
25
  className,
17
26
  children,
18
27
  ...props
19
28
  }) {
20
- const glyph = icon !== void 0 ? icon : tone === "warn" ? /* @__PURE__ */ jsx(TriangleAlertIcon, { className: "size-4" }) : /* @__PURE__ */ jsx(InfoIcon, { className: "size-4" });
29
+ const glyph = icon !== void 0 ? icon : tone === "warn" ? /* @__PURE__ */ jsx(TriangleAlertIcon, { className: SYSTEM_BANNER_GLYPH }) : /* @__PURE__ */ jsx(InfoIcon, { className: SYSTEM_BANNER_GLYPH });
21
30
  return /* @__PURE__ */ jsxs(
22
31
  "div",
23
32
  {
24
33
  "data-slot": "system-banner",
25
34
  "data-tone": tone,
26
35
  role: "status",
27
- className: cn("flex items-start gap-2.5 rounded-lg border px-4 py-2.5 text-sm", TONE[tone], className),
36
+ className: cn(SYSTEM_BANNER_BASE, systemBannerToneClasses[tone], className),
28
37
  ...props,
29
38
  children: [
30
- glyph !== null && /* @__PURE__ */ jsx("span", { className: "mt-0.5 flex shrink-0", children: glyph }),
31
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
32
- title !== void 0 && /* @__PURE__ */ jsx("span", { className: "font-semibold", children: title }),
39
+ glyph !== null && /* @__PURE__ */ jsx("span", { className: cn(SYSTEM_BANNER_ICON, systemBannerIconToneClasses[tone]), children: glyph }),
40
+ /* @__PURE__ */ jsxs("div", { className: SYSTEM_BANNER_MESSAGE, children: [
41
+ title !== void 0 && /* @__PURE__ */ jsx("span", { className: SYSTEM_BANNER_TITLE, children: title }),
33
42
  title !== void 0 && children !== void 0 && " \u2014 ",
34
- children !== void 0 && /* @__PURE__ */ jsx("span", { className: cn(title !== void 0 && tone === "info" && "text-ink-soft"), children })
43
+ children !== void 0 && /* @__PURE__ */ jsx("span", { className: cn(title !== void 0 && SYSTEM_BANNER_BODY_AFTER_TITLE), children })
35
44
  ] }),
45
+ action !== void 0 && /* @__PURE__ */ jsx("span", { className: SYSTEM_BANNER_ACTION, children: action }),
36
46
  onDismiss && /* @__PURE__ */ jsx(
37
47
  "button",
38
48
  {
39
49
  type: "button",
40
50
  "aria-label": labels.dismiss ?? "Dismiss",
41
51
  onClick: onDismiss,
42
- className: "-mr-1 shrink-0 rounded-md p-0.5 opacity-70 outline-none transition-opacity hover:opacity-100 focus-visible:ring-2 focus-visible:ring-ring",
43
- children: /* @__PURE__ */ jsx(CloseIcon, { className: "size-4" })
52
+ className: SYSTEM_BANNER_DISMISS,
53
+ children: /* @__PURE__ */ jsx(CloseIcon, { className: SYSTEM_BANNER_GLYPH })
44
54
  }
45
55
  )
46
56
  ]
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/system-banner.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport {\n SYSTEM_BANNER_ACTION,\n SYSTEM_BANNER_BASE,\n SYSTEM_BANNER_BODY_AFTER_TITLE,\n SYSTEM_BANNER_DISMISS,\n SYSTEM_BANNER_GLYPH,\n SYSTEM_BANNER_ICON,\n SYSTEM_BANNER_MESSAGE,\n SYSTEM_BANNER_TITLE,\n systemBannerIconToneClasses,\n systemBannerToneClasses,\n type SystemBannerTone,\n} from \"../../generated/system-banner\";\nimport { CloseIcon, InfoIcon, TriangleAlertIcon } from \"./shell-icons\";\n\nexport type { SystemBannerTone };\n\nexport interface SystemBannerLabels {\n /** The close button. Default `\"Dismiss\"`. */\n dismiss?: string;\n}\n\nexport interface SystemBannerProps extends Omit<React.ComponentProps<\"div\">, \"title\"> {\n /** `warn` — a platform state (maintenance, read-only); `info` — an announcement. */\n tone?: SystemBannerTone;\n /** Bold lead before the message. */\n title?: React.ReactNode;\n /** Replaces the tone's glyph; `null` drops it. */\n icon?: React.ReactNode;\n /** Shows a close button; remembering the dismissal is the caller's. */\n onDismiss?: () => void;\n /** A link or button after the message. */\n action?: React.ReactNode;\n labels?: SystemBannerLabels;\n}\n\n/**\n * A slim full-width strip above the page — presentation only: where its state\n * comes from, and whether a dismissal sticks, are the caller's. Put it in\n * `AppShell`'s `banner` slot; several stack with a gap.\n */\nexport function SystemBanner({\n tone = \"info\",\n title,\n icon,\n onDismiss,\n action,\n labels = {},\n className,\n children,\n ...props\n}: SystemBannerProps) {\n const glyph =\n icon !== undefined ? icon : tone === \"warn\" ? <TriangleAlertIcon className={SYSTEM_BANNER_GLYPH} /> : <InfoIcon className={SYSTEM_BANNER_GLYPH} />;\n return (\n <div\n data-slot=\"system-banner\"\n data-tone={tone}\n role=\"status\"\n className={cn(SYSTEM_BANNER_BASE, systemBannerToneClasses[tone], className)}\n {...props}\n >\n {glyph !== null && <span className={cn(SYSTEM_BANNER_ICON, systemBannerIconToneClasses[tone])}>{glyph}</span>}\n <div className={SYSTEM_BANNER_MESSAGE}>\n {title !== undefined && <span className={SYSTEM_BANNER_TITLE}>{title}</span>}\n {title !== undefined && children !== undefined && \" — \"}\n {children !== undefined && <span className={cn(title !== undefined && SYSTEM_BANNER_BODY_AFTER_TITLE)}>{children}</span>}\n </div>\n {action !== undefined && <span className={SYSTEM_BANNER_ACTION}>{action}</span>}\n {onDismiss && (\n <button\n type=\"button\"\n aria-label={labels.dismiss ?? \"Dismiss\"}\n onClick={onDismiss}\n className={SYSTEM_BANNER_DISMISS}\n >\n <CloseIcon className={SYSTEM_BANNER_GLYPH} />\n </button>\n )}\n </div>\n );\n}\n"],"mappings":";AAyDkD,cAU5C,YAV4C;AAvDlD,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,WAAW,UAAU,yBAAyB;AA4BhD,SAAS,aAAa;AAAA,EAC3B,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,CAAC;AAAA,EACV;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsB;AACpB,QAAM,QACJ,SAAS,SAAY,OAAO,SAAS,SAAS,oBAAC,qBAAkB,WAAW,qBAAqB,IAAK,oBAAC,YAAS,WAAW,qBAAqB;AAClJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,aAAW;AAAA,MACX,MAAK;AAAA,MACL,WAAW,GAAG,oBAAoB,wBAAwB,IAAI,GAAG,SAAS;AAAA,MACzE,GAAG;AAAA,MAEH;AAAA,kBAAU,QAAQ,oBAAC,UAAK,WAAW,GAAG,oBAAoB,4BAA4B,IAAI,CAAC,GAAI,iBAAM;AAAA,QACtG,qBAAC,SAAI,WAAW,uBACb;AAAA,oBAAU,UAAa,oBAAC,UAAK,WAAW,qBAAsB,iBAAM;AAAA,UACpE,UAAU,UAAa,aAAa,UAAa;AAAA,UACjD,aAAa,UAAa,oBAAC,UAAK,WAAW,GAAG,UAAU,UAAa,8BAA8B,GAAI,UAAS;AAAA,WACnH;AAAA,QACC,WAAW,UAAa,oBAAC,UAAK,WAAW,sBAAuB,kBAAO;AAAA,QACvE,aACC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,cAAY,OAAO,WAAW;AAAA,YAC9B,SAAS;AAAA,YACT,WAAW;AAAA,YAEX,8BAAC,aAAU,WAAW,qBAAqB;AAAA;AAAA,QAC7C;AAAA;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
@@ -1,16 +1,17 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
- import { cn } from "../lib/cn.js";
3
+ import { cn } from "../../lib/cn.js";
4
+ import { TOP_BAR_BASE, TOP_BAR_END, TOP_BAR_START } from "../../generated/top-bar.js";
4
5
  function TopBar({ start, end, className, ...props }) {
5
6
  return /* @__PURE__ */ jsxs(
6
7
  "header",
7
8
  {
8
9
  "data-slot": "top-bar",
9
- className: cn("flex h-14 items-center gap-3 border-b border-border bg-background px-8", className),
10
+ className: cn(TOP_BAR_BASE, className),
10
11
  ...props,
11
12
  children: [
12
- /* @__PURE__ */ jsx("div", { "data-slot": "top-bar-start", className: "flex min-w-0 items-center gap-2", children: start }),
13
- /* @__PURE__ */ jsx("div", { "data-slot": "top-bar-end", className: "ml-auto flex shrink-0 items-center gap-3", children: end })
13
+ /* @__PURE__ */ jsx("div", { "data-slot": "top-bar-start", className: TOP_BAR_START, children: start }),
14
+ /* @__PURE__ */ jsx("div", { "data-slot": "top-bar-end", className: TOP_BAR_END, children: end })
14
15
  ]
15
16
  }
16
17
  );
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/top-bar.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { TOP_BAR_BASE, TOP_BAR_END, TOP_BAR_START } from \"../../generated/top-bar\";\n\nexport interface TopBarProps extends React.ComponentProps<\"header\"> {\n /** The app switcher, or the service's name. */\n start?: React.ReactNode;\n /** Service stats, then an `AccountMenu` last. */\n end?: React.ReactNode;\n}\n\n/**\n * The wide screen's utility bar over the content column: who and where, never\n * product nav (that is the rail's). Layout only — `AppShell.topBar` pins it.\n */\nexport function TopBar({ start, end, className, ...props }: TopBarProps) {\n return (\n <header\n data-slot=\"top-bar\"\n className={cn(TOP_BAR_BASE, className)}\n {...props}\n >\n <div data-slot=\"top-bar-start\" className={TOP_BAR_START}>\n {start}\n </div>\n <div data-slot=\"top-bar-end\" className={TOP_BAR_END}>\n {end}\n </div>\n </header>\n );\n}\n"],"mappings":"AAiBI,SAKE,KALF;AAjBJ,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB,SAAS,cAAc,aAAa,qBAAqB;AAalD,SAAS,OAAO,EAAE,OAAO,KAAK,WAAW,GAAG,MAAM,GAAgB;AACvE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,cAAc,SAAS;AAAA,MACpC,GAAG;AAAA,MAEJ;AAAA,4BAAC,SAAI,aAAU,iBAAgB,WAAW,eACvC,iBACH;AAAA,QACA,oBAAC,SAAI,aAAU,eAAc,WAAW,aACrC,eACH;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/use-shell-nav.ts"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\n/**\n * The optimistic half of a nav: the id of the item just clicked, until the\n * pathname catches up.\n *\n * A router that waits for the next page's payload changes the pathname 150–300ms\n * after the click — exactly the window in which a highlight that has not moved\n * reads as a click that did not land. So the clicked item is marked at once.\n *\n * The entry remembers the pathname it was made on, so the moment the pathname\n * changes it is stale by construction and the URL is the truth again. It is\n * cleared during render, not in an effect (an effect would paint one frame with\n * the URL's row marked and the stale one not), and cleared rather than ignored:\n * left behind, it would come back to life on a return to the page it was made\n * on. A click that never navigates is forgotten by the next one.\n */\nexport function usePendingNavigation(\n pathname: string,\n): readonly [pendingId: string | null, markPending: (id: string) => void] {\n const [pending, setPending] = React.useState<{ id: string; from: string } | null>(null);\n if (pending && pending.from !== pathname) setPending(null);\n const pendingId = pending && pending.from === pathname ? pending.id : null;\n const markPending = React.useCallback(\n (id: string) => setPending({ id, from: pathname }),\n [pathname],\n );\n return [pendingId, markPending] as const;\n}\n\n/**\n * Places the section's `[data-slot=\"shell-nav-marker\"]` over its\n * `[aria-current=\"page\"]` row, by measurement: rows differ in count and every\n * label is somebody's translation, and SSR cannot know those offsets (until the\n * first placement the row carries the fill itself — see motion.css). Re-runs\n * when `at` changes and whenever the section resizes — rows come and go, labels\n * change width with the locale or a font swap.\n */\nexport function useSlideMarker(\n ref: React.RefObject<HTMLElement | null>,\n at: string | null,\n): void {\n // Which marker node was last placed, so a re-run over the same node — a move,\n // a resize — is told apart from a marker that has just mounted. `undefined`\n // until the first run, so only a marker mounting AFTER the section settled\n // counts as entering (and fades); one hydration finds on its row cuts in.\n const placed = React.useRef<HTMLElement | null | undefined>(undefined);\n React.useLayoutEffect(() => {\n const section = ref.current;\n if (!section) return;\n const place = () => {\n const marker = section.querySelector<HTMLElement>('[data-slot=\"shell-nav-marker\"]');\n const row = section.querySelector<HTMLElement>('[aria-current=\"page\"]');\n const fresh = marker !== placed.current;\n const entering = fresh && placed.current !== undefined;\n placed.current = marker;\n if (!marker || !row) return;\n if (fresh) marker.style.transition = \"none\";\n marker.style.transform = `translate(${row.offsetLeft}px, ${row.offsetTop}px)`;\n marker.style.width = `${row.offsetWidth}px`;\n marker.style.height = `${row.offsetHeight}px`;\n if (fresh) {\n // A transition is decided by the style AFTER the change: flushing the\n // placement first makes it the starting point, so a new marker appears on\n // its row instead of sliding in from the section's origin.\n void marker.offsetWidth;\n marker.style.transition = \"\";\n marker.dataset[\"placed\"] = entering ? \"entered\" : \"first\";\n }\n };\n place();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(place);\n observer.observe(section);\n return () => observer.disconnect();\n }, [ref, at]);\n}\n"],"mappings":";AAEA,YAAY,WAAW;AAiBhB,SAAS,qBACd,UACwE;AACxE,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAA8C,IAAI;AACtF,MAAI,WAAW,QAAQ,SAAS,SAAU,YAAW,IAAI;AACzD,QAAM,YAAY,WAAW,QAAQ,SAAS,WAAW,QAAQ,KAAK;AACtE,QAAM,cAAc,MAAM;AAAA,IACxB,CAAC,OAAe,WAAW,EAAE,IAAI,MAAM,SAAS,CAAC;AAAA,IACjD,CAAC,QAAQ;AAAA,EACX;AACA,SAAO,CAAC,WAAW,WAAW;AAChC;AAUO,SAAS,eACd,KACA,IACM;AAKN,QAAM,SAAS,MAAM,OAAuC,MAAS;AACrE,QAAM,gBAAgB,MAAM;AAC1B,UAAM,UAAU,IAAI;AACpB,QAAI,CAAC,QAAS;AACd,UAAM,QAAQ,MAAM;AAClB,YAAM,SAAS,QAAQ,cAA2B,gCAAgC;AAClF,YAAM,MAAM,QAAQ,cAA2B,uBAAuB;AACtE,YAAM,QAAQ,WAAW,OAAO;AAChC,YAAM,WAAW,SAAS,OAAO,YAAY;AAC7C,aAAO,UAAU;AACjB,UAAI,CAAC,UAAU,CAAC,IAAK;AACrB,UAAI,MAAO,QAAO,MAAM,aAAa;AACrC,aAAO,MAAM,YAAY,aAAa,IAAI,UAAU,OAAO,IAAI,SAAS;AACxE,aAAO,MAAM,QAAQ,GAAG,IAAI,WAAW;AACvC,aAAO,MAAM,SAAS,GAAG,IAAI,YAAY;AACzC,UAAI,OAAO;AAIT,aAAK,OAAO;AACZ,eAAO,MAAM,aAAa;AAC1B,eAAO,QAAQ,QAAQ,IAAI,WAAW,YAAY;AAAA,MACpD;AAAA,IACF;AACA,UAAM;AACN,QAAI,OAAO,mBAAmB,YAAa;AAC3C,UAAM,WAAW,IAAI,eAAe,KAAK;AACzC,aAAS,QAAQ,OAAO;AACxB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,KAAK,EAAE,CAAC;AACd;","names":[]}