@evinvest/uikit 0.31.0 → 0.33.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 (485) hide show
  1. package/README.md +23 -12
  2. package/dist/components/{accordion.js → atomic/accordion.js} +5 -4
  3. package/dist/components/atomic/accordion.js.map +1 -0
  4. package/dist/components/{alert-dialog.js → atomic/alert-dialog.js} +9 -9
  5. package/dist/components/atomic/alert-dialog.js.map +1 -0
  6. package/dist/components/{alert.js → atomic/alert.js} +6 -6
  7. package/dist/components/atomic/alert.js.map +1 -0
  8. package/dist/components/{animated-number-columns.js → atomic/animated-number-columns.js} +1 -1
  9. package/dist/components/atomic/animated-number-columns.js.map +1 -0
  10. package/dist/components/{avatar.js → atomic/avatar.js} +2 -2
  11. package/dist/components/atomic/avatar.js.map +1 -0
  12. package/dist/components/atomic/badge.js +26 -0
  13. package/dist/components/atomic/badge.js.map +1 -0
  14. package/dist/components/{band.js → atomic/band.js} +2 -2
  15. package/dist/components/atomic/band.js.map +1 -0
  16. package/dist/components/{breadcrumb.js → atomic/breadcrumb.js} +10 -12
  17. package/dist/components/atomic/breadcrumb.js.map +1 -0
  18. package/dist/components/{button-group.js → atomic/button-group.js} +3 -3
  19. package/dist/components/atomic/button-group.js.map +1 -0
  20. package/dist/components/{button.js → atomic/button.js} +8 -7
  21. package/dist/components/atomic/button.js.map +1 -0
  22. package/dist/components/{calendar.js → atomic/calendar.js} +12 -27
  23. package/dist/components/atomic/calendar.js.map +1 -0
  24. package/dist/components/{card.js → atomic/card.js} +2 -2
  25. package/dist/components/atomic/card.js.map +1 -0
  26. package/dist/components/{checkbox.js → atomic/checkbox.js} +6 -5
  27. package/dist/components/atomic/checkbox.js.map +1 -0
  28. package/dist/components/{collapsible.js → atomic/collapsible.js} +1 -1
  29. package/dist/components/atomic/collapsible.js.map +1 -0
  30. package/dist/components/{command.js → atomic/command.js} +11 -26
  31. package/dist/components/atomic/command.js.map +1 -0
  32. package/dist/components/{container.js → atomic/container.js} +2 -2
  33. package/dist/components/atomic/container.js.map +1 -0
  34. package/dist/components/{context-menu.js → atomic/context-menu.js} +15 -22
  35. package/dist/components/atomic/context-menu.js.map +1 -0
  36. package/dist/components/{dialog.js → atomic/dialog.js} +13 -11
  37. package/dist/components/atomic/dialog.js.map +1 -0
  38. package/dist/components/{drawer.js → atomic/drawer.js} +8 -8
  39. package/dist/components/atomic/drawer.js.map +1 -0
  40. package/dist/components/{dropdown-menu.js → atomic/dropdown-menu.js} +16 -24
  41. package/dist/components/atomic/dropdown-menu.js.map +1 -0
  42. package/dist/components/{empty.js → atomic/empty.js} +2 -2
  43. package/dist/components/atomic/empty.js.map +1 -0
  44. package/dist/components/atomic/field-context.js.map +1 -0
  45. package/dist/components/{form-row.js → atomic/form-row.js} +2 -2
  46. package/dist/components/atomic/form-row.js.map +1 -0
  47. package/dist/components/{hover-card.js → atomic/hover-card.js} +8 -8
  48. package/dist/components/atomic/hover-card.js.map +1 -0
  49. package/dist/components/{info-tip.js → atomic/info-tip.js} +18 -19
  50. package/dist/components/atomic/info-tip.js.map +1 -0
  51. package/dist/components/{input-otp.js → atomic/input-otp.js} +5 -4
  52. package/dist/components/atomic/input-otp.js.map +1 -0
  53. package/dist/components/{input.js → atomic/input.js} +3 -3
  54. package/dist/components/atomic/input.js.map +1 -0
  55. package/dist/components/{kbd.js → atomic/kbd.js} +2 -2
  56. package/dist/components/atomic/kbd.js.map +1 -0
  57. package/dist/components/{key-value.js → atomic/key-value.js} +8 -7
  58. package/dist/components/atomic/key-value.js.map +1 -0
  59. package/dist/components/{label.js → atomic/label.js} +2 -2
  60. package/dist/components/atomic/label.js.map +1 -0
  61. package/dist/components/{menubar.js → atomic/menubar.js} +16 -27
  62. package/dist/components/atomic/menubar.js.map +1 -0
  63. package/dist/components/{native-select.js → atomic/native-select.js} +5 -5
  64. package/dist/components/atomic/native-select.js.map +1 -0
  65. package/dist/components/{navigation-menu.js → atomic/navigation-menu.js} +12 -20
  66. package/dist/components/atomic/navigation-menu.js.map +1 -0
  67. package/dist/components/{pagination.js → atomic/pagination.js} +19 -20
  68. package/dist/components/atomic/pagination.js.map +1 -0
  69. package/dist/components/{popover.js → atomic/popover.js} +10 -10
  70. package/dist/components/atomic/popover.js.map +1 -0
  71. package/dist/components/{progress.js → atomic/progress.js} +2 -2
  72. package/dist/components/atomic/progress.js.map +1 -0
  73. package/dist/components/{radio-group.js → atomic/radio-group.js} +8 -7
  74. package/dist/components/atomic/radio-group.js.map +1 -0
  75. package/dist/components/{scroll-area.js → atomic/scroll-area.js} +2 -2
  76. package/dist/components/atomic/scroll-area.js.map +1 -0
  77. package/dist/components/{section-descriptor.js → atomic/section-descriptor.js} +7 -10
  78. package/dist/components/atomic/section-descriptor.js.map +1 -0
  79. package/dist/components/{select-listbox.js → atomic/select-listbox.js} +3 -3
  80. package/dist/components/atomic/select-listbox.js.map +1 -0
  81. package/dist/components/{select.js → atomic/select.js} +15 -23
  82. package/dist/components/atomic/select.js.map +1 -0
  83. package/dist/components/{separator.js → atomic/separator.js} +2 -2
  84. package/dist/components/atomic/separator.js.map +1 -0
  85. package/dist/components/{sheet.js → atomic/sheet.js} +13 -11
  86. package/dist/components/atomic/sheet.js.map +1 -0
  87. package/dist/components/{sidebar.js → atomic/sidebar.js} +11 -30
  88. package/dist/components/atomic/sidebar.js.map +1 -0
  89. package/dist/components/{skeleton.js → atomic/skeleton.js} +2 -2
  90. package/dist/components/atomic/skeleton.js.map +1 -0
  91. package/dist/components/{slider.js → atomic/slider.js} +3 -3
  92. package/dist/components/atomic/slider.js.map +1 -0
  93. package/dist/components/{sonner.js → atomic/sonner.js} +22 -20
  94. package/dist/components/atomic/sonner.js.map +1 -0
  95. package/dist/components/atomic/spinner.js +26 -0
  96. package/dist/components/atomic/spinner.js.map +1 -0
  97. package/dist/components/{status-item.js → atomic/status-item.js} +2 -2
  98. package/dist/components/atomic/status-item.js.map +1 -0
  99. package/dist/components/{switch.js → atomic/switch.js} +4 -4
  100. package/dist/components/atomic/switch.js.map +1 -0
  101. package/dist/components/{table.js → atomic/table.js} +2 -2
  102. package/dist/components/atomic/table.js.map +1 -0
  103. package/dist/components/{tabs.js → atomic/tabs.js} +4 -4
  104. package/dist/components/atomic/tabs.js.map +1 -0
  105. package/dist/components/{textarea.js → atomic/textarea.js} +3 -3
  106. package/dist/components/atomic/textarea.js.map +1 -0
  107. package/dist/components/{toggle-group.js → atomic/toggle-group.js} +4 -4
  108. package/dist/components/atomic/toggle-group.js.map +1 -0
  109. package/dist/components/{toggle.js → atomic/toggle.js} +5 -8
  110. package/dist/components/atomic/toggle.js.map +1 -0
  111. package/dist/components/{tooltip.js → atomic/tooltip.js} +8 -8
  112. package/dist/components/atomic/tooltip.js.map +1 -0
  113. package/dist/components/{use-count-tween.js → atomic/use-count-tween.js} +1 -1
  114. package/dist/components/atomic/use-count-tween.js.map +1 -0
  115. package/dist/components/{animated-number.js → derived/animated-number.js} +5 -5
  116. package/dist/components/derived/animated-number.js.map +1 -0
  117. package/dist/components/{carousel.js → derived/carousel.js} +10 -10
  118. package/dist/components/derived/carousel.js.map +1 -0
  119. package/dist/components/{command-palette.js → derived/command-palette.js} +14 -13
  120. package/dist/components/derived/command-palette.js.map +1 -0
  121. package/dist/components/{confirm-dialog.js → derived/confirm-dialog.js} +15 -20
  122. package/dist/components/derived/confirm-dialog.js.map +1 -0
  123. package/dist/components/{date-time-picker.js → derived/date-time-picker.js} +18 -22
  124. package/dist/components/derived/date-time-picker.js.map +1 -0
  125. package/dist/components/{field.js → derived/field.js} +6 -6
  126. package/dist/components/derived/field.js.map +1 -0
  127. package/dist/components/{form.js → derived/form.js} +4 -5
  128. package/dist/components/derived/form.js.map +1 -0
  129. package/dist/components/{icon-button.js → derived/icon-button.js} +4 -4
  130. package/dist/components/derived/icon-button.js.map +1 -0
  131. package/dist/components/{input-group.js → derived/input-group.js} +5 -5
  132. package/dist/components/derived/input-group.js.map +1 -0
  133. package/dist/components/{item.js → derived/item.js} +4 -5
  134. package/dist/components/derived/item.js.map +1 -0
  135. package/dist/components/{popover-form.js → derived/popover-form.js} +9 -8
  136. package/dist/components/derived/popover-form.js.map +1 -0
  137. package/dist/components/{settings.js → derived/settings.js} +7 -7
  138. package/dist/components/derived/settings.js.map +1 -0
  139. package/dist/components/{account-list.js → shell/account-list.js} +5 -5
  140. package/dist/components/shell/account-list.js.map +1 -0
  141. package/dist/components/{account-menu-profile.js → shell/account-menu-profile.js} +7 -7
  142. package/dist/components/shell/account-menu-profile.js.map +1 -0
  143. package/dist/components/{account-menu.js → shell/account-menu.js} +4 -4
  144. package/dist/components/shell/account-menu.js.map +1 -0
  145. package/dist/components/{account-settings-dialog.js → shell/account-settings-dialog.js} +9 -8
  146. package/dist/components/shell/account-settings-dialog.js.map +1 -0
  147. package/dist/components/{app-shell.js → shell/app-shell.js} +1 -1
  148. package/dist/components/shell/app-shell.js.map +1 -0
  149. package/dist/components/{aside.js → shell/aside.js} +12 -10
  150. package/dist/components/shell/aside.js.map +1 -0
  151. package/dist/components/{auth-wall.js → shell/auth-wall.js} +4 -6
  152. package/dist/components/shell/auth-wall.js.map +1 -0
  153. package/dist/components/{bottom-tab-bar.js → shell/bottom-tab-bar.js} +4 -4
  154. package/dist/components/shell/bottom-tab-bar.js.map +1 -0
  155. package/dist/components/{chat-composer.js → shell/chat-composer.js} +16 -14
  156. package/dist/components/shell/chat-composer.js.map +1 -0
  157. package/dist/components/{chat-message.js → shell/chat-message.js} +4 -4
  158. package/dist/components/shell/chat-message.js.map +1 -0
  159. package/dist/components/{chat-panel.js → shell/chat-panel.js} +3 -3
  160. package/dist/components/shell/chat-panel.js.map +1 -0
  161. package/dist/components/shell/chat-stream-text.js.map +1 -0
  162. package/dist/components/{chat-typing.js → shell/chat-typing.js} +4 -3
  163. package/dist/components/shell/chat-typing.js.map +1 -0
  164. package/dist/components/{footer.js → shell/footer.js} +27 -25
  165. package/dist/components/shell/footer.js.map +1 -0
  166. package/dist/components/{header-controls.js → shell/header-controls.js} +25 -23
  167. package/dist/components/shell/header-controls.js.map +1 -0
  168. package/dist/components/shell/hotbar.js +158 -0
  169. package/dist/components/shell/hotbar.js.map +1 -0
  170. package/dist/components/{list-rows.js → shell/list-rows.js} +1 -1
  171. package/dist/components/shell/list-rows.js.map +1 -0
  172. package/dist/components/{logo.js → shell/logo.js} +4 -3
  173. package/dist/components/shell/logo.js.map +1 -0
  174. package/dist/components/{mobile-app-bar.js → shell/mobile-app-bar.js} +5 -5
  175. package/dist/components/shell/mobile-app-bar.js.map +1 -0
  176. package/dist/components/{nav-badge.js → shell/nav-badge.js} +1 -1
  177. package/dist/components/shell/nav-badge.js.map +1 -0
  178. package/dist/components/{nav-collapse.js → shell/nav-collapse.js} +8 -7
  179. package/dist/components/shell/nav-collapse.js.map +1 -0
  180. package/dist/components/shell/nav-link.js.map +1 -0
  181. package/dist/components/shell/nav-model.js.map +1 -0
  182. package/dist/components/{page-frame.js → shell/page-frame.js} +2 -2
  183. package/dist/components/shell/page-frame.js.map +1 -0
  184. package/dist/components/{resource-error.js → shell/resource-error.js} +5 -5
  185. package/dist/components/shell/resource-error.js.map +1 -0
  186. package/dist/components/{section-nav.js → shell/section-nav.js} +4 -4
  187. package/dist/components/shell/section-nav.js.map +1 -0
  188. package/dist/components/shell/settled.js.map +1 -0
  189. package/dist/components/shell/shell-icons.js +42 -0
  190. package/dist/components/shell/shell-icons.js.map +1 -0
  191. package/dist/components/{shell-nav.js → shell/shell-nav.js} +5 -5
  192. package/dist/components/shell/shell-nav.js.map +1 -0
  193. package/dist/components/{smart-header.js → shell/smart-header.js} +2 -2
  194. package/dist/components/shell/smart-header.js.map +1 -0
  195. package/dist/components/shell/status-screen.js +145 -0
  196. package/dist/components/shell/status-screen.js.map +1 -0
  197. package/dist/components/{system-banner.js → shell/system-banner.js} +8 -8
  198. package/dist/components/shell/system-banner.js.map +1 -0
  199. package/dist/components/{top-bar.js → shell/top-bar.js} +2 -2
  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/{workspace-tab.js → shell/workspace-tab.js} +6 -5
  203. package/dist/components/shell/workspace-tab.js.map +1 -0
  204. package/dist/generated/accent.js +10 -10
  205. package/dist/generated/accent.js.map +1 -1
  206. package/dist/generated/accordion.js +6 -2
  207. package/dist/generated/accordion.js.map +1 -1
  208. package/dist/generated/account-list.js +4 -4
  209. package/dist/generated/account-list.js.map +1 -1
  210. package/dist/generated/account-settings-dialog.js +6 -2
  211. package/dist/generated/account-settings-dialog.js.map +1 -1
  212. package/dist/generated/alert-dialog.js +1 -1
  213. package/dist/generated/alert-dialog.js.map +1 -1
  214. package/dist/generated/alert.js +3 -10
  215. package/dist/generated/alert.js.map +1 -1
  216. package/dist/generated/aside.js +7 -0
  217. package/dist/generated/aside.js.map +1 -1
  218. package/dist/generated/badge.js +2 -11
  219. package/dist/generated/badge.js.map +1 -1
  220. package/dist/generated/band.js +10 -10
  221. package/dist/generated/band.js.map +1 -1
  222. package/dist/generated/breadcrumb.js +1 -1
  223. package/dist/generated/breadcrumb.js.map +1 -1
  224. package/dist/generated/button-group.js +3 -3
  225. package/dist/generated/button-group.js.map +1 -1
  226. package/dist/generated/button.js +4 -20
  227. package/dist/generated/button.js.map +1 -1
  228. package/dist/generated/calendar.js +5 -5
  229. package/dist/generated/calendar.js.map +1 -1
  230. package/dist/generated/card.js +1 -1
  231. package/dist/generated/card.js.map +1 -1
  232. package/dist/generated/carousel.js +1 -1
  233. package/dist/generated/carousel.js.map +1 -1
  234. package/dist/generated/chat-composer.js +9 -2
  235. package/dist/generated/chat-composer.js.map +1 -1
  236. package/dist/generated/chat-message.js +25 -19
  237. package/dist/generated/chat-message.js.map +1 -1
  238. package/dist/generated/checkbox.js +1 -1
  239. package/dist/generated/checkbox.js.map +1 -1
  240. package/dist/generated/command-palette.js +10 -1
  241. package/dist/generated/command-palette.js.map +1 -1
  242. package/dist/generated/command.js +8 -6
  243. package/dist/generated/command.js.map +1 -1
  244. package/dist/generated/confirm-dialog.js +8 -8
  245. package/dist/generated/confirm-dialog.js.map +1 -1
  246. package/dist/generated/context-menu.js +7 -5
  247. package/dist/generated/context-menu.js.map +1 -1
  248. package/dist/generated/copy.js +97 -0
  249. package/dist/generated/copy.js.map +1 -0
  250. package/dist/generated/date-time-picker.js +10 -0
  251. package/dist/generated/date-time-picker.js.map +1 -1
  252. package/dist/generated/dialog.js +2 -2
  253. package/dist/generated/dialog.js.map +1 -1
  254. package/dist/generated/drawer.js +6 -6
  255. package/dist/generated/drawer.js.map +1 -1
  256. package/dist/generated/dropdown-menu.js +7 -5
  257. package/dist/generated/dropdown-menu.js.map +1 -1
  258. package/dist/generated/empty.js +5 -5
  259. package/dist/generated/empty.js.map +1 -1
  260. package/dist/generated/field.js +9 -7
  261. package/dist/generated/field.js.map +1 -1
  262. package/dist/generated/footer.js +45 -0
  263. package/dist/generated/footer.js.map +1 -0
  264. package/dist/generated/header-controls.js +5 -10
  265. package/dist/generated/header-controls.js.map +1 -1
  266. package/dist/generated/hover-card.js +1 -1
  267. package/dist/generated/hover-card.js.map +1 -1
  268. package/dist/generated/icon-button.js +4 -2
  269. package/dist/generated/icon-button.js.map +1 -1
  270. package/dist/generated/icons.js +36 -0
  271. package/dist/generated/icons.js.map +1 -0
  272. package/dist/generated/info-tip.js +5 -0
  273. package/dist/generated/info-tip.js.map +1 -0
  274. package/dist/generated/input-group.js +10 -10
  275. package/dist/generated/input-group.js.map +1 -1
  276. package/dist/generated/input-otp.js +2 -2
  277. package/dist/generated/input-otp.js.map +1 -1
  278. package/dist/generated/input.js +4 -4
  279. package/dist/generated/input.js.map +1 -1
  280. package/dist/generated/item.js +11 -11
  281. package/dist/generated/item.js.map +1 -1
  282. package/dist/generated/kbd.js +1 -1
  283. package/dist/generated/kbd.js.map +1 -1
  284. package/dist/generated/key-value.js +7 -1
  285. package/dist/generated/key-value.js.map +1 -1
  286. package/dist/generated/label.js +1 -1
  287. package/dist/generated/label.js.map +1 -1
  288. package/dist/generated/logo.js +9 -0
  289. package/dist/generated/logo.js.map +1 -0
  290. package/dist/generated/menu.js +7 -0
  291. package/dist/generated/menu.js.map +1 -0
  292. package/dist/generated/menubar.js +10 -8
  293. package/dist/generated/menubar.js.map +1 -1
  294. package/dist/generated/navigation-menu.js +11 -5
  295. package/dist/generated/navigation-menu.js.map +1 -1
  296. package/dist/generated/orientation.js +5 -0
  297. package/dist/generated/orientation.js.map +1 -0
  298. package/dist/generated/pagination.js +15 -0
  299. package/dist/generated/pagination.js.map +1 -0
  300. package/dist/generated/popover-form.js +5 -0
  301. package/dist/generated/popover-form.js.map +1 -1
  302. package/dist/generated/popover.js +1 -1
  303. package/dist/generated/popover.js.map +1 -1
  304. package/dist/generated/primitives.js +7 -0
  305. package/dist/generated/primitives.js.map +1 -0
  306. package/dist/generated/radio-group.js +5 -1
  307. package/dist/generated/radio-group.js.map +1 -1
  308. package/dist/generated/section-descriptor.js +7 -0
  309. package/dist/generated/section-descriptor.js.map +1 -0
  310. package/dist/generated/select.js +16 -10
  311. package/dist/generated/select.js.map +1 -1
  312. package/dist/generated/settings.js +2 -7
  313. package/dist/generated/settings.js.map +1 -1
  314. package/dist/generated/sheet.js +1 -1
  315. package/dist/generated/sheet.js.map +1 -1
  316. package/dist/generated/sidebar.js +24 -12
  317. package/dist/generated/sidebar.js.map +1 -1
  318. package/dist/generated/size.js +12 -0
  319. package/dist/generated/size.js.map +1 -0
  320. package/dist/generated/skeleton.js +1 -1
  321. package/dist/generated/skeleton.js.map +1 -1
  322. package/dist/generated/slider.js +2 -2
  323. package/dist/generated/slider.js.map +1 -1
  324. package/dist/generated/slot.js +5 -0
  325. package/dist/generated/slot.js.map +1 -0
  326. package/dist/generated/smart-header.js +2 -0
  327. package/dist/generated/smart-header.js.map +1 -1
  328. package/dist/generated/sonner.js +11 -13
  329. package/dist/generated/sonner.js.map +1 -1
  330. package/dist/generated/spinner.js +5 -0
  331. package/dist/generated/spinner.js.map +1 -0
  332. package/dist/generated/status-screen.js +27 -0
  333. package/dist/generated/status-screen.js.map +1 -0
  334. package/dist/generated/switch.js +2 -2
  335. package/dist/generated/switch.js.map +1 -1
  336. package/dist/generated/system-banner.js +6 -16
  337. package/dist/generated/system-banner.js.map +1 -1
  338. package/dist/generated/table.js +9 -9
  339. package/dist/generated/table.js.map +1 -1
  340. package/dist/generated/tabs.js +2 -2
  341. package/dist/generated/tabs.js.map +1 -1
  342. package/dist/generated/textarea.js +1 -1
  343. package/dist/generated/textarea.js.map +1 -1
  344. package/dist/generated/toggle-group.js +9 -0
  345. package/dist/generated/toggle-group.js.map +1 -0
  346. package/dist/generated/toggle.js +1 -9
  347. package/dist/generated/toggle.js.map +1 -1
  348. package/dist/generated/tone.js +12 -0
  349. package/dist/generated/tone.js.map +1 -0
  350. package/dist/generated/tooltip.js +1 -1
  351. package/dist/generated/tooltip.js.map +1 -1
  352. package/dist/generated/workspace-tab.js +3 -3
  353. package/dist/generated/workspace-tab.js.map +1 -1
  354. package/dist/icons/icon-shapes.js +10 -0
  355. package/dist/icons/icon-shapes.js.map +1 -0
  356. package/dist/{components → icons}/select-chevron.js +2 -1
  357. package/dist/icons/select-chevron.js.map +1 -0
  358. package/dist/icons/ui-icons.js +23 -0
  359. package/dist/icons/ui-icons.js.map +1 -0
  360. package/dist/index.d.ts +203 -155
  361. package/dist/index.js +97 -96
  362. package/dist/lib/cn.js +1 -0
  363. package/dist/lib/cn.js.map +1 -1
  364. package/dist/primitives/use-floating.js.map +1 -1
  365. package/dist/primitives/use-roving-focus.js.map +1 -1
  366. package/package.json +2 -2
  367. package/styles/ev.css +13 -76
  368. package/styles/theme.css +133 -66
  369. package/styles/tokens.css +157 -149
  370. package/dist/components/accordion.js.map +0 -1
  371. package/dist/components/account-list.js.map +0 -1
  372. package/dist/components/account-menu-profile.js.map +0 -1
  373. package/dist/components/account-menu.js.map +0 -1
  374. package/dist/components/account-settings-dialog.js.map +0 -1
  375. package/dist/components/alert-dialog.js.map +0 -1
  376. package/dist/components/alert.js.map +0 -1
  377. package/dist/components/animated-number-columns.js.map +0 -1
  378. package/dist/components/animated-number.js.map +0 -1
  379. package/dist/components/app-shell.js.map +0 -1
  380. package/dist/components/aside.js.map +0 -1
  381. package/dist/components/auth-wall.js.map +0 -1
  382. package/dist/components/avatar.js.map +0 -1
  383. package/dist/components/badge.js +0 -25
  384. package/dist/components/badge.js.map +0 -1
  385. package/dist/components/band.js.map +0 -1
  386. package/dist/components/bottom-tab-bar.js.map +0 -1
  387. package/dist/components/breadcrumb.js.map +0 -1
  388. package/dist/components/button-group.js.map +0 -1
  389. package/dist/components/button.js.map +0 -1
  390. package/dist/components/calendar.js.map +0 -1
  391. package/dist/components/card.js.map +0 -1
  392. package/dist/components/carousel.js.map +0 -1
  393. package/dist/components/chat-composer.js.map +0 -1
  394. package/dist/components/chat-message.js.map +0 -1
  395. package/dist/components/chat-panel.js.map +0 -1
  396. package/dist/components/chat-stream-text.js.map +0 -1
  397. package/dist/components/chat-typing.js.map +0 -1
  398. package/dist/components/checkbox.js.map +0 -1
  399. package/dist/components/collapsible.js.map +0 -1
  400. package/dist/components/command-palette.js.map +0 -1
  401. package/dist/components/command.js.map +0 -1
  402. package/dist/components/confirm-dialog.js.map +0 -1
  403. package/dist/components/container.js.map +0 -1
  404. package/dist/components/context-menu.js.map +0 -1
  405. package/dist/components/date-time-picker.js.map +0 -1
  406. package/dist/components/dialog.js.map +0 -1
  407. package/dist/components/drawer.js.map +0 -1
  408. package/dist/components/dropdown-menu.js.map +0 -1
  409. package/dist/components/empty.js.map +0 -1
  410. package/dist/components/field-context.js.map +0 -1
  411. package/dist/components/field.js.map +0 -1
  412. package/dist/components/footer.js.map +0 -1
  413. package/dist/components/form-row.js.map +0 -1
  414. package/dist/components/form.js.map +0 -1
  415. package/dist/components/header-controls.js.map +0 -1
  416. package/dist/components/hover-card.js.map +0 -1
  417. package/dist/components/icon-button.js.map +0 -1
  418. package/dist/components/info-tip.js.map +0 -1
  419. package/dist/components/input-group.js.map +0 -1
  420. package/dist/components/input-otp.js.map +0 -1
  421. package/dist/components/input.js.map +0 -1
  422. package/dist/components/item.js.map +0 -1
  423. package/dist/components/kbd.js.map +0 -1
  424. package/dist/components/key-value.js.map +0 -1
  425. package/dist/components/label.js.map +0 -1
  426. package/dist/components/list-rows.js.map +0 -1
  427. package/dist/components/logo.js.map +0 -1
  428. package/dist/components/menubar.js.map +0 -1
  429. package/dist/components/mobile-app-bar.js.map +0 -1
  430. package/dist/components/native-select.js.map +0 -1
  431. package/dist/components/nav-badge.js.map +0 -1
  432. package/dist/components/nav-collapse.js.map +0 -1
  433. package/dist/components/nav-link.js.map +0 -1
  434. package/dist/components/nav-model.js.map +0 -1
  435. package/dist/components/navigation-menu.js.map +0 -1
  436. package/dist/components/page-frame.js.map +0 -1
  437. package/dist/components/pagination.js.map +0 -1
  438. package/dist/components/popover-form.js.map +0 -1
  439. package/dist/components/popover.js.map +0 -1
  440. package/dist/components/progress.js.map +0 -1
  441. package/dist/components/radio-group.js.map +0 -1
  442. package/dist/components/resource-error.js.map +0 -1
  443. package/dist/components/scroll-area.js.map +0 -1
  444. package/dist/components/section-descriptor.js.map +0 -1
  445. package/dist/components/section-nav.js.map +0 -1
  446. package/dist/components/select-chevron.js.map +0 -1
  447. package/dist/components/select-listbox.js.map +0 -1
  448. package/dist/components/select.js.map +0 -1
  449. package/dist/components/separator.js.map +0 -1
  450. package/dist/components/settings.js.map +0 -1
  451. package/dist/components/settled.js.map +0 -1
  452. package/dist/components/sheet.js.map +0 -1
  453. package/dist/components/shell-icons.js +0 -57
  454. package/dist/components/shell-icons.js.map +0 -1
  455. package/dist/components/shell-nav.js.map +0 -1
  456. package/dist/components/sidebar.js.map +0 -1
  457. package/dist/components/skeleton.js.map +0 -1
  458. package/dist/components/slider.js.map +0 -1
  459. package/dist/components/smart-header.js.map +0 -1
  460. package/dist/components/sonner.js.map +0 -1
  461. package/dist/components/spinner.js +0 -23
  462. package/dist/components/spinner.js.map +0 -1
  463. package/dist/components/status-item.js.map +0 -1
  464. package/dist/components/status-screen.js +0 -145
  465. package/dist/components/status-screen.js.map +0 -1
  466. package/dist/components/switch.js.map +0 -1
  467. package/dist/components/system-banner.js.map +0 -1
  468. package/dist/components/table.js.map +0 -1
  469. package/dist/components/tabs.js.map +0 -1
  470. package/dist/components/textarea.js.map +0 -1
  471. package/dist/components/toggle-group.js.map +0 -1
  472. package/dist/components/toggle.js.map +0 -1
  473. package/dist/components/tooltip.js.map +0 -1
  474. package/dist/components/top-bar.js.map +0 -1
  475. package/dist/components/ui-icons.js +0 -77
  476. package/dist/components/ui-icons.js.map +0 -1
  477. package/dist/components/use-count-tween.js.map +0 -1
  478. package/dist/components/use-shell-nav.js.map +0 -1
  479. package/dist/components/workspace-tab.js.map +0 -1
  480. /package/dist/components/{field-context.js → atomic/field-context.js} +0 -0
  481. /package/dist/components/{chat-stream-text.js → shell/chat-stream-text.js} +0 -0
  482. /package/dist/components/{nav-link.js → shell/nav-link.js} +0 -0
  483. /package/dist/components/{nav-model.js → shell/nav-model.js} +0 -0
  484. /package/dist/components/{settled.js → shell/settled.js} +0 -0
  485. /package/dist/components/{use-shell-nav.js → shell/use-shell-nav.js} +0 -0
@@ -12,13 +12,14 @@ import {
12
12
  ACCOUNT_SETTINGS_DIALOG_PANEL,
13
13
  ACCOUNT_SETTINGS_DIALOG_SIDEBAR,
14
14
  ACCOUNT_SETTINGS_DIALOG_TABS,
15
- ACCOUNT_SETTINGS_DIALOG_TITLE
16
- } from "../generated/account-settings-dialog.js";
17
- import { cn } from "../lib/cn.js";
18
- import { Dialog, DialogClose, DialogContent, DialogDescription, DialogTitle } from "./dialog.js";
19
- import { Tabs, TabsContent, TabsList, TabsTrigger } from "./tabs.js";
20
- import { IconButton } from "./icon-button.js";
21
- import { UiIcon } from "./ui-icons.js";
15
+ ACCOUNT_SETTINGS_DIALOG_TITLE,
16
+ ACCOUNT_SETTINGS_DIALOG_LABELS
17
+ } from "../../generated/account-settings-dialog.js";
18
+ import { cn } from "../../lib/cn.js";
19
+ import { Dialog, DialogClose, DialogContent, DialogDescription, DialogTitle } from "../atomic/dialog.js";
20
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "../atomic/tabs.js";
21
+ import { IconButton } from "../derived/icon-button.js";
22
+ import { UiIcon } from "../../icons/ui-icons.js";
22
23
  function AccountSettingsDialog({
23
24
  open,
24
25
  defaultOpen,
@@ -71,7 +72,7 @@ function AccountSettingsDialog({
71
72
  ]
72
73
  }
73
74
  ),
74
- /* @__PURE__ */ jsx(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { "aria-label": labels.close ?? "Close", className: ACCOUNT_SETTINGS_DIALOG_CLOSE, children: /* @__PURE__ */ jsx(UiIcon, { name: "x" }) }) })
75
+ /* @__PURE__ */ jsx(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { "aria-label": labels.close ?? ACCOUNT_SETTINGS_DIALOG_LABELS.close, className: ACCOUNT_SETTINGS_DIALOG_CLOSE, children: /* @__PURE__ */ jsx(UiIcon, { name: "x" }) }) })
75
76
  ]
76
77
  }
77
78
  )
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/account-settings-dialog.tsx"],"sourcesContent":["import * as React from \"react\";\nimport {\n ACCOUNT_SETTINGS_DIALOG_CLOSE,\n ACCOUNT_SETTINGS_DIALOG_CONTENT,\n ACCOUNT_SETTINGS_DIALOG_DESCRIPTION,\n ACCOUNT_SETTINGS_DIALOG_ENTRY,\n ACCOUNT_SETTINGS_DIALOG_FOOTER,\n ACCOUNT_SETTINGS_DIALOG_HEADING,\n ACCOUNT_SETTINGS_DIALOG_LIST,\n ACCOUNT_SETTINGS_DIALOG_PANE,\n ACCOUNT_SETTINGS_DIALOG_PANEL,\n ACCOUNT_SETTINGS_DIALOG_SIDEBAR,\n ACCOUNT_SETTINGS_DIALOG_TABS,\n ACCOUNT_SETTINGS_DIALOG_TITLE,\n ACCOUNT_SETTINGS_DIALOG_LABELS,\n} from \"../../generated/account-settings-dialog\";\nimport { cn } from \"../../lib/cn\";\nimport { Dialog, DialogClose, DialogContent, DialogDescription, DialogTitle } from \"../atomic/dialog\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"../atomic/tabs\";\nimport { IconButton } from \"../derived/icon-button\";\nimport { UiIcon } from \"../../icons/ui-icons\";\n\nexport interface AccountSettingsSection {\n id: string;\n label: React.ReactNode;\n icon?: React.ReactNode;\n content: React.ReactNode;\n}\n\nexport interface AccountSettingsDialogLabels {\n /** The close button. Default `\"Close\"`. */\n close?: string;\n}\n\nexport interface AccountSettingsDialogProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** The heading of the content pane. */\n title: React.ReactNode;\n description?: React.ReactNode;\n /** One sidebar entry each; the active one's `content` fills the pane. */\n sections: readonly AccountSettingsSection[];\n value?: string;\n defaultValue?: string;\n onValueChange?: (id: string) => void;\n /** Pinned under the sidebar entries: sign out, language. */\n sidebarFooter?: React.ReactNode;\n labels?: AccountSettingsDialogLabels;\n className?: string;\n}\n\n/**\n * The account modal: a vertical tab rail on the left, the active section on\n * the right. Sections are the caller's, so Profile and Security (or any other)\n * are built from `SettingsSection` and `SettingsRow` inside `content`.\n */\nexport function AccountSettingsDialog({\n open,\n defaultOpen,\n onOpenChange,\n title,\n description,\n sections,\n value,\n defaultValue,\n onValueChange,\n sidebarFooter,\n labels = {},\n className,\n}: AccountSettingsDialogProps) {\n const first = sections[0]?.id ?? \"\";\n return (\n <Dialog\n {...(open !== undefined ? { open } : {})}\n {...(defaultOpen !== undefined ? { defaultOpen } : {})}\n {...(onOpenChange ? { onOpenChange } : {})}\n >\n <DialogContent\n showCloseButton={false}\n className={cn(ACCOUNT_SETTINGS_DIALOG_CONTENT, className)}\n >\n <Tabs\n orientation=\"vertical\"\n {...(value !== undefined ? { value } : { defaultValue: defaultValue ?? first })}\n {...(onValueChange ? { onValueChange } : {})}\n className={ACCOUNT_SETTINGS_DIALOG_TABS}\n >\n <div className={ACCOUNT_SETTINGS_DIALOG_SIDEBAR}>\n <TabsList className={ACCOUNT_SETTINGS_DIALOG_LIST}>\n {sections.map((s) => (\n <TabsTrigger key={s.id} value={s.id} className={ACCOUNT_SETTINGS_DIALOG_ENTRY}>\n {s.icon}\n {s.label}\n </TabsTrigger>\n ))}\n </TabsList>\n {sidebarFooter != null && (\n <div className={ACCOUNT_SETTINGS_DIALOG_FOOTER}>{sidebarFooter}</div>\n )}\n </div>\n <div className={ACCOUNT_SETTINGS_DIALOG_PANE}>\n <div className={ACCOUNT_SETTINGS_DIALOG_HEADING}>\n <DialogTitle className={ACCOUNT_SETTINGS_DIALOG_TITLE}>{title}</DialogTitle>\n {description != null && (\n <DialogDescription className={ACCOUNT_SETTINGS_DIALOG_DESCRIPTION}>{description}</DialogDescription>\n )}\n </div>\n {sections.map((s) => (\n <TabsContent key={s.id} value={s.id} className={ACCOUNT_SETTINGS_DIALOG_PANEL}>\n {s.content}\n </TabsContent>\n ))}\n </div>\n </Tabs>\n <DialogClose asChild>\n <IconButton aria-label={labels.close ?? ACCOUNT_SETTINGS_DIALOG_LABELS.close} className={ACCOUNT_SETTINGS_DIALOG_CLOSE}>\n <UiIcon name=\"x\" />\n </IconButton>\n </DialogClose>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"AAyFY,cAEI,YAFJ;AAzFZ,YAAY,WAAW;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,UAAU;AACnB,SAAS,QAAQ,aAAa,eAAe,mBAAmB,mBAAmB;AACnF,SAAS,MAAM,aAAa,UAAU,mBAAmB;AACzD,SAAS,kBAAkB;AAC3B,SAAS,cAAc;AAqChB,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,CAAC;AAAA,EACV;AACF,GAA+B;AAC7B,QAAM,QAAQ,SAAS,CAAC,GAAG,MAAM;AACjC,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,MACrC,GAAI,gBAAgB,SAAY,EAAE,YAAY,IAAI,CAAC;AAAA,MACnD,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,MAExC;AAAA,QAAC;AAAA;AAAA,UACC,iBAAiB;AAAA,UACjB,WAAW,GAAG,iCAAiC,SAAS;AAAA,UAExD;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,aAAY;AAAA,gBACX,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,EAAE,cAAc,gBAAgB,MAAM;AAAA,gBAC5E,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;AAAA,gBAC1C,WAAW;AAAA,gBAEX;AAAA,uCAAC,SAAI,WAAW,iCACd;AAAA,wCAAC,YAAS,WAAW,8BAClB,mBAAS,IAAI,CAAC,MACb,qBAAC,eAAuB,OAAO,EAAE,IAAI,WAAW,+BAC7C;AAAA,wBAAE;AAAA,sBACF,EAAE;AAAA,yBAFa,EAAE,EAGpB,CACD,GACH;AAAA,oBACC,iBAAiB,QAChB,oBAAC,SAAI,WAAW,gCAAiC,yBAAc;AAAA,qBAEnE;AAAA,kBACA,qBAAC,SAAI,WAAW,8BACd;AAAA,yCAAC,SAAI,WAAW,iCACd;AAAA,0CAAC,eAAY,WAAW,+BAAgC,iBAAM;AAAA,sBAC7D,eAAe,QACd,oBAAC,qBAAkB,WAAW,qCAAsC,uBAAY;AAAA,uBAEpF;AAAA,oBACC,SAAS,IAAI,CAAC,MACb,oBAAC,eAAuB,OAAO,EAAE,IAAI,WAAW,+BAC7C,YAAE,WADa,EAAE,EAEpB,CACD;AAAA,qBACH;AAAA;AAAA;AAAA,YACF;AAAA,YACA,oBAAC,eAAY,SAAO,MAClB,8BAAC,cAAW,cAAY,OAAO,SAAS,+BAA+B,OAAO,WAAW,+BACvF,8BAAC,UAAO,MAAK,KAAI,GACnB,GACF;AAAA;AAAA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1,6 +1,6 @@
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
4
  const AT = {
5
5
  md: {
6
6
  rail: "hidden md:flex",
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/app-shell.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\n\n/** Where the shell swaps the bottom tab bar for the rail. */\nexport type ShellBreakpoint = \"md\" | \"lg\";\n\nexport interface AppShellProps extends React.ComponentProps<\"div\"> {\n /** The desktop rail — a `ShellNav`. Shown from `breakpoint` up. */\n rail?: React.ReactNode;\n /** The phone's tab bar — a `BottomTabBar`. Pinned to the viewport bottom below `breakpoint`. */\n tabBar?: React.ReactNode;\n /** A `TopBar`, pinned over the column from `breakpoint` up (a phone titles its screen with `MobileAppBar`). */\n topBar?: React.ReactNode;\n /** Strips above the page (`SystemBanner`s). An empty slot takes no room. */\n banner?: React.ReactNode;\n /** Right of the content column: an `AsidePanel` and its `AsideRail`, side by side. Sticks like the rail. */\n aside?: React.ReactNode;\n /** Default `lg`. */\n breakpoint?: ShellBreakpoint;\n /** Props for the `<main>` the page renders into (an `id` for a skip link, say). */\n mainProps?: React.ComponentProps<\"main\">;\n}\n\n// Tailwind only sees whole class strings, so each breakpoint spells its own.\nconst AT = {\n md: {\n rail: \"hidden md:flex\",\n tabBar: \"md:hidden\",\n topBar: \"hidden md:block\",\n reserve: \"pb-[calc(var(--shell-tab-bar-h)+env(safe-area-inset-bottom,0px))] md:pb-0\",\n banner: \"md:px-8\",\n },\n lg: {\n rail: \"hidden lg:flex\",\n tabBar: \"lg:hidden\",\n topBar: \"hidden lg:block\",\n reserve: \"pb-[calc(var(--shell-tab-bar-h)+env(safe-area-inset-bottom,0px))] lg:pb-0\",\n banner: \"lg:px-8\",\n },\n} as const;\n\nconst present = (node: React.ReactNode) => node !== null && node !== undefined && node !== false;\n\n/**\n * The signed-in app's frame: a rail beside a content column on a wide screen, a\n * bottom tab bar under it on a phone. Layout only — the nav, the top bar, the banners\n * and the page are slots, so the shell knows nothing about routes, roles or data.\n *\n * Fills the viewport less `--ev-shell-offset` (the room a host shell's own header\n * takes); the rail sticks under that offset at full remaining height and scrolls\n * by itself when it cannot fit. The column reserves the tab bar's height plus\n * the bottom safe area, so the bar never covers content.\n */\nexport function AppShell({\n rail,\n tabBar,\n topBar,\n banner,\n aside,\n breakpoint = \"lg\",\n mainProps,\n className,\n children,\n ...props\n}: AppShellProps) {\n const at = AT[breakpoint];\n return (\n <div\n data-slot=\"app-shell\"\n data-breakpoint={breakpoint}\n className={cn(\n \"flex min-h-[calc(100dvh-var(--ev-shell-offset,0px))] bg-background\",\n className,\n )}\n {...props}\n >\n {present(rail) && (\n <div\n data-slot=\"app-shell-rail\"\n className={cn(\n \"sticky top-[var(--ev-shell-offset,0px)] h-[calc(100dvh-var(--ev-shell-offset,0px))] shrink-0 self-start\",\n at.rail,\n )}\n >\n {rail}\n </div>\n )}\n <div\n data-slot=\"app-shell-content\"\n className={cn(\"flex min-w-0 flex-1 flex-col\", present(tabBar) && at.reserve)}\n >\n {present(topBar) && (\n <div\n data-slot=\"app-shell-top-bar\"\n className={cn(\"sticky top-[var(--ev-shell-offset,0px)] z-30\", at.topBar)}\n >\n {topBar}\n </div>\n )}\n {present(banner) && (\n <div\n data-slot=\"app-shell-banner\"\n className={cn(\"flex flex-col gap-2 px-4 pt-4 empty:hidden\", at.banner)}\n >\n {banner}\n </div>\n )}\n <main {...mainProps} className={cn(\"min-w-0 flex-1\", mainProps?.className)}>\n {children}\n </main>\n </div>\n {present(aside) && (\n <div\n data-slot=\"app-shell-aside\"\n className=\"sticky top-[var(--ev-shell-offset,0px)] flex h-[calc(100dvh-var(--ev-shell-offset,0px))] shrink-0 self-start\"\n >\n {aside}\n </div>\n )}\n {present(tabBar) && (\n <div\n data-slot=\"app-shell-tab-bar\"\n className={cn(\"fixed inset-x-0 bottom-0 z-40\", at.tabBar)}\n >\n {tabBar}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"AA6EQ,cAUF,YAVE;AA7ER,YAAY,WAAW;AACvB,SAAS,UAAU;AAuBnB,MAAM,KAAK;AAAA,EACT,IAAI;AAAA,IACF,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,QAAQ;AAAA,EACV;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,QAAQ;AAAA,EACV;AACF;AAEA,MAAM,UAAU,CAAC,SAA0B,SAAS,QAAQ,SAAS,UAAa,SAAS;AAYpF,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAkB;AAChB,QAAM,KAAK,GAAG,UAAU;AACxB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,mBAAiB;AAAA,MACjB,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA,gBAAQ,IAAI,KACX;AAAA,UAAC;AAAA;AAAA,YACC,aAAU;AAAA,YACV,WAAW;AAAA,cACT;AAAA,cACA,GAAG;AAAA,YACL;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,QAEF;AAAA,UAAC;AAAA;AAAA,YACC,aAAU;AAAA,YACV,WAAW,GAAG,gCAAgC,QAAQ,MAAM,KAAK,GAAG,OAAO;AAAA,YAE1E;AAAA,sBAAQ,MAAM,KACb;AAAA,gBAAC;AAAA;AAAA,kBACC,aAAU;AAAA,kBACV,WAAW,GAAG,gDAAgD,GAAG,MAAM;AAAA,kBAEtE;AAAA;AAAA,cACH;AAAA,cAED,QAAQ,MAAM,KACb;AAAA,gBAAC;AAAA;AAAA,kBACC,aAAU;AAAA,kBACV,WAAW,GAAG,8CAA8C,GAAG,MAAM;AAAA,kBAEpE;AAAA;AAAA,cACH;AAAA,cAEF,oBAAC,UAAM,GAAG,WAAW,WAAW,GAAG,kBAAkB,WAAW,SAAS,GACtE,UACH;AAAA;AAAA;AAAA,QACF;AAAA,QACC,QAAQ,KAAK,KACZ;AAAA,UAAC;AAAA;AAAA,YACC,aAAU;AAAA,YACV,WAAU;AAAA,YAET;AAAA;AAAA,QACH;AAAA,QAED,QAAQ,MAAM,KACb;AAAA,UAAC;AAAA;AAAA,YACC,aAAU;AAAA,YACV,WAAW,GAAG,iCAAiC,GAAG,MAAM;AAAA,YAEvD;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
@@ -1,7 +1,7 @@
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 {
6
6
  ASIDE_BODY,
7
7
  ASIDE_FOOTER,
@@ -13,12 +13,14 @@ import {
13
13
  ASIDE_PANEL_SHEET,
14
14
  ASIDE_RAIL_BASE,
15
15
  ASIDE_RAIL_SPACER,
16
- asidePanelSideClasses
17
- } from "../generated/aside.js";
18
- import { Drawer, DrawerContent } from "./drawer.js";
19
- import { IconButton } from "./icon-button.js";
20
- import { Sheet, SheetContent } from "./sheet.js";
21
- import { UiIcon } from "./ui-icons.js";
16
+ asidePanelSideClasses,
17
+ ASIDE_HEADER_LABELS
18
+ } from "../../generated/aside.js";
19
+ import { Drawer, DrawerContent } from "../atomic/drawer.js";
20
+ import { IconButton } from "../derived/icon-button.js";
21
+ import { Sheet, SheetContent } from "../atomic/sheet.js";
22
+ import { UiIcon } from "../../icons/ui-icons.js";
23
+ import * as copy from "../../generated/copy.js";
22
24
  function AsideHeader({ title, onBack, onClose, actions, labels = {}, className, ...props }) {
23
25
  return /* @__PURE__ */ jsxs(
24
26
  "div",
@@ -27,10 +29,10 @@ function AsideHeader({ title, onBack, onClose, actions, labels = {}, className,
27
29
  className: cn(ASIDE_HEADER_BASE, className),
28
30
  ...props,
29
31
  children: [
30
- onBack && /* @__PURE__ */ jsx(IconButton, { "aria-label": labels.back ?? "Back", size: "sm", onClick: onBack, children: /* @__PURE__ */ jsx(UiIcon, { name: "chevron-right", className: ASIDE_HEADER_BACK_ICON }) }),
32
+ onBack && /* @__PURE__ */ jsx(IconButton, { "aria-label": labels.back ?? ASIDE_HEADER_LABELS.back, size: "sm", onClick: onBack, children: /* @__PURE__ */ jsx(UiIcon, { name: "chevron-right", className: ASIDE_HEADER_BACK_ICON }) }),
31
33
  /* @__PURE__ */ jsx("h2", { className: ASIDE_HEADER_TITLE, children: title }),
32
34
  actions,
33
- onClose && /* @__PURE__ */ jsx(IconButton, { "aria-label": labels.close ?? "Close", size: "sm", onClick: onClose, children: /* @__PURE__ */ jsx(UiIcon, { name: "x" }) })
35
+ onClose && /* @__PURE__ */ jsx(IconButton, { "aria-label": labels.close ?? ASIDE_HEADER_LABELS.close, size: "sm", onClick: onClose, children: /* @__PURE__ */ jsx(UiIcon, { name: "x" }) })
34
36
  ]
35
37
  }
36
38
  );
@@ -41,7 +43,7 @@ function AsideRail({
41
43
  value,
42
44
  onValueChange,
43
45
  className,
44
- "aria-label": ariaLabel = "Panels",
46
+ "aria-label": ariaLabel = copy.ASIDE_RAIL,
45
47
  ...props
46
48
  }) {
47
49
  const button = (item) => /* @__PURE__ */ jsx(
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/aside.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport {\n ASIDE_BODY,\n ASIDE_FOOTER,\n ASIDE_HEADER_BACK_ICON,\n ASIDE_HEADER_BASE,\n ASIDE_HEADER_TITLE,\n ASIDE_PANEL_DOCKED,\n ASIDE_PANEL_DRAWER,\n ASIDE_PANEL_SHEET,\n ASIDE_RAIL_BASE,\n ASIDE_RAIL_SPACER,\n asidePanelSideClasses,\n type AsidePanelSide,\n ASIDE_HEADER_LABELS,\n} from \"../../generated/aside\";\nimport { Drawer, DrawerContent } from \"../atomic/drawer\";\nimport { IconButton } from \"../derived/icon-button\";\nimport { Sheet, SheetContent } from \"../atomic/sheet\";\nimport { UiIcon } from \"../../icons/ui-icons\";\nimport type { AsidePanelMode } from \"../../generated/aside\";\nimport * as copy from \"../../generated/copy\";\n\nexport interface AsideHeaderLabels {\n back?: string;\n close?: string;\n}\n\nexport interface AsideHeaderProps extends Omit<React.ComponentProps<\"div\">, \"title\"> {\n title: React.ReactNode;\n /** Shows the back button first. */\n onBack?: () => void;\n /** Shows the close button last. */\n onClose?: () => void;\n /** `IconButton`s between the title and the close button: pin, more. */\n actions?: React.ReactNode;\n labels?: AsideHeaderLabels;\n}\n\n/** The 44 px title row of an aside. */\nexport function AsideHeader({ title, onBack, onClose, actions, labels = {}, className, ...props }: AsideHeaderProps) {\n return (\n <div\n data-slot=\"aside-header\"\n className={cn(ASIDE_HEADER_BASE, className)}\n {...props}\n >\n {onBack && (\n <IconButton aria-label={labels.back ?? ASIDE_HEADER_LABELS.back} size=\"sm\" onClick={onBack}>\n <UiIcon name=\"chevron-right\" className={ASIDE_HEADER_BACK_ICON} />\n </IconButton>\n )}\n <h2 className={ASIDE_HEADER_TITLE}>{title}</h2>\n {actions}\n {onClose && (\n <IconButton aria-label={labels.close ?? ASIDE_HEADER_LABELS.close} size=\"sm\" onClick={onClose}>\n <UiIcon name=\"x\" />\n </IconButton>\n )}\n </div>\n );\n}\n\nexport interface AsideRailItem {\n id: string;\n /** Names the button and fills its tooltip. */\n label: string;\n icon: React.ReactNode;\n}\n\nexport interface AsideRailProps extends Omit<React.ComponentProps<\"div\">, \"onChange\"> {\n items: readonly AsideRailItem[];\n /** Pinned to the bottom, e.g. settings. */\n endItems?: readonly AsideRailItem[];\n /** The open aside's id; `null` when all are closed. */\n value: string | null;\n /** Pressing the open item's button asks for `null`. */\n onValueChange: (id: string | null) => void;\n /** Accessible name of the rail. Default `\"Panels\"`. */\n \"aria-label\"?: string;\n}\n\n/** The 44 px strip of icon buttons that opens and closes the asides. */\nexport function AsideRail({\n items,\n endItems = [],\n value,\n onValueChange,\n className,\n \"aria-label\": ariaLabel = copy.ASIDE_RAIL,\n ...props\n}: AsideRailProps) {\n const button = (item: AsideRailItem) => (\n <IconButton\n key={item.id}\n aria-label={item.label}\n tooltip={item.label}\n pressed={value === item.id}\n onClick={() => onValueChange(value === item.id ? null : item.id)}\n >\n {item.icon}\n </IconButton>\n );\n return (\n <div\n role=\"group\"\n aria-label={ariaLabel}\n data-slot=\"aside-rail\"\n className={cn(ASIDE_RAIL_BASE, className)}\n {...props}\n >\n {items.map(button)}\n <span className={ASIDE_RAIL_SPACER} />\n {endItems.map(button)}\n </div>\n );\n}\n\nfunction useAtLeast(query: string): boolean {\n return React.useSyncExternalStore(\n (notify) => {\n if (typeof window.matchMedia !== \"function\") return () => {};\n const mq = window.matchMedia(query);\n mq.addEventListener(\"change\", notify);\n return () => mq.removeEventListener(\"change\", notify);\n },\n () => typeof window.matchMedia !== \"function\" || window.matchMedia(query).matches,\n // Server and first paint assume a wide screen; a phone swaps to the drawer on hydrate.\n () => true,\n );\n}\n\nexport type { AsidePanelMode };\n\nexport interface AsidePanelProps extends Omit<React.ComponentProps<\"aside\">, \"title\"> {\n /** Names the panel. */\n \"aria-label\": string;\n mode?: AsidePanelMode;\n /** Which edge of the screen it hugs. Default `right`. */\n side?: AsidePanelSide;\n open?: boolean;\n /**\n * Escape, the scrim and the drawer drag call it with `false`. A docked panel\n * is only dismissable this way where it falls back to the drawer (below `md`).\n */\n onOpenChange?: (open: boolean) => void;\n /** An `AsideHeader`. */\n header?: React.ReactNode;\n /** Sticky under the body: actions. */\n footer?: React.ReactNode;\n /**\n * Below this width the panel floats on a drawer so the content keeps its room.\n * `false` keeps it docked (or on a sheet) at every width, for a framed preview\n * or an embedded layout where the viewport says nothing about the room.\n */\n collapseBelow?: \"md\" | false;\n /** Docked 380 (260 for a left navigation), overlay 420: a width class overrides it. */\n className?: string;\n}\n\n/**\n * A side panel. `docked` sits in the layout and takes room from the content;\n * `overlay` floats over a scrim on a Sheet. Below `md` both use a bottom Drawer.\n * The edge facing the content is the only border.\n */\nexport function AsidePanel({\n mode = \"docked\",\n side = \"right\",\n open = true,\n onOpenChange,\n header,\n footer,\n collapseBelow = \"md\",\n className,\n children,\n ...props\n}: AsidePanelProps) {\n const viewportWide = useAtLeast(\"(min-width: 768px)\");\n const wide = collapseBelow === false || viewportWide;\n const body = (\n <>\n {header}\n <div data-slot=\"aside-body\" className={ASIDE_BODY}>\n {children}\n </div>\n {footer != null && (\n <div data-slot=\"aside-footer\" className={ASIDE_FOOTER}>\n {footer}\n </div>\n )}\n </>\n );\n\n if (mode === \"docked\" && wide) {\n if (!open) return null;\n return (\n <aside\n data-slot=\"aside-panel\"\n data-mode=\"docked\"\n data-side={side}\n className={cn(ASIDE_PANEL_DOCKED, asidePanelSideClasses[side], className)}\n {...props}\n >\n {body}\n </aside>\n );\n }\n\n // Below md there is no room beside the content, so a docked panel floats like an overlay.\n const label = props[\"aria-label\"];\n if (!wide) {\n return (\n <Drawer open={open} {...(onOpenChange ? { onOpenChange } : {})} direction=\"bottom\">\n <DrawerContent aria-label={label} className={ASIDE_PANEL_DRAWER}>\n {body}\n </DrawerContent>\n </Drawer>\n );\n }\n return (\n <Sheet open={open} {...(onOpenChange ? { onOpenChange } : {})}>\n <SheetContent\n side={side}\n aria-label={label}\n className={cn(ASIDE_PANEL_SHEET, className)}\n >\n {body}\n </SheetContent>\n </Sheet>\n );\n}\n"],"mappings":"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","names":[]}
@@ -7,7 +7,8 @@ import {
7
7
  EmptyHeader,
8
8
  EmptyMedia,
9
9
  EmptyTitle
10
- } from "./empty.js";
10
+ } from "../atomic/empty.js";
11
+ import { iconShapes } from "../../icons/icon-shapes.js";
11
12
  function AuthWall({ title, description, children, ...props }) {
12
13
  return /* @__PURE__ */ jsxs(Empty, { ...props, children: [
13
14
  /* @__PURE__ */ jsxs(EmptyHeader, { children: [
@@ -19,7 +20,7 @@ function AuthWall({ title, description, children, ...props }) {
19
20
  ] });
20
21
  }
21
22
  function LockIcon() {
22
- return /* @__PURE__ */ jsxs(
23
+ return /* @__PURE__ */ jsx(
23
24
  "svg",
24
25
  {
25
26
  viewBox: "0 0 24 24",
@@ -29,10 +30,7 @@ function LockIcon() {
29
30
  strokeLinecap: "round",
30
31
  strokeLinejoin: "round",
31
32
  "aria-hidden": true,
32
- children: [
33
- /* @__PURE__ */ jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }),
34
- /* @__PURE__ */ jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })
35
- ]
33
+ children: iconShapes("lock")
36
34
  }
37
35
  );
38
36
  }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/auth-wall.tsx"],"sourcesContent":["import * as React from \"react\";\nimport {\n Empty,\n EmptyContent,\n EmptyDescription,\n EmptyHeader,\n EmptyMedia,\n EmptyTitle,\n} from \"../atomic/empty\";\nimport { iconShapes } from \"../../icons/icon-shapes\";\n\n/**\n * What a section shows a caller it is not for: an `Empty` with a lock, a title, why,\n * and an action slot. A guest gets the sign-in button there; a signed-in caller\n * without the permission gets no action, or the host's own (request access).\n */\nexport interface AuthWallProps extends Omit<React.ComponentProps<\"div\">, \"title\"> {\n title: React.ReactNode;\n description: React.ReactNode;\n}\n\nexport function AuthWall({ title, description, children, ...props }: AuthWallProps) {\n return (\n <Empty {...props}>\n <EmptyHeader>\n <EmptyMedia variant=\"icon\">\n <LockIcon />\n </EmptyMedia>\n <EmptyTitle>{title}</EmptyTitle>\n <EmptyDescription>{description}</EmptyDescription>\n </EmptyHeader>\n <EmptyContent>{children}</EmptyContent>\n </Empty>\n );\n}\n\nfunction LockIcon() {\n return (\n <svg\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 {iconShapes(\"lock\")}\n </svg>\n );\n}\n"],"mappings":"AAwBM,SAEI,KAFJ;AAxBN,YAAY,WAAW;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAYpB,SAAS,SAAS,EAAE,OAAO,aAAa,UAAU,GAAG,MAAM,GAAkB;AAClF,SACE,qBAAC,SAAO,GAAG,OACT;AAAA,yBAAC,eACC;AAAA,0BAAC,cAAW,SAAQ,QAClB,8BAAC,YAAS,GACZ;AAAA,MACA,oBAAC,cAAY,iBAAM;AAAA,MACnB,oBAAC,oBAAkB,uBAAY;AAAA,OACjC;AAAA,IACA,oBAAC,gBAAc,UAAS;AAAA,KAC1B;AAEJ;AAEA,SAAS,WAAW;AAClB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAa;AAAA,MACb,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAW;AAAA,MAEV,qBAAW,MAAM;AAAA;AAAA,EACpB;AAEJ;","names":[]}
@@ -1,7 +1,7 @@
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
5
  import { NavBadge } from "./nav-badge.js";
6
6
  import { labelTitle, NavLink } from "./nav-link.js";
7
7
  import { resolveActiveNavItem } from "./nav-model.js";
@@ -25,7 +25,7 @@ function BottomTabBar({
25
25
  "data-slot": "tab-bar",
26
26
  "aria-label": labels.nav ?? "Main",
27
27
  className: cn(
28
- "relative box-content flex h-(--shell-tab-bar-h) items-center border-t border-border bg-secondary px-2 pb-[env(safe-area-inset-bottom,0px)]",
28
+ "relative box-content flex h-(--shell-tab-bar-h) items-center border-t border-border bg-card px-2 pb-[env(safe-area-inset-bottom,0px)]",
29
29
  className
30
30
  ),
31
31
  ...props,
@@ -58,10 +58,10 @@ function BottomTabBar({
58
58
  onItemIntent,
59
59
  onNavigate,
60
60
  className: cn(
61
- "flex min-w-0 flex-1 flex-col items-center justify-center gap-0.5 rounded-lg py-1 font-medium transition-colors",
61
+ "flex min-w-0 flex-1 flex-col items-center justify-center gap-0.5 rounded-row py-1 font-medium transition-colors",
62
62
  "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-secondary",
63
63
  active ? "text-primary-ink" : "text-ink-soft hover:text-ink",
64
- item.disabled && "cursor-not-allowed opacity-50"
64
+ item.disabled && "cursor-not-allowed opacity-(--disabled-opacity)"
65
65
  ),
66
66
  children: [
67
67
  /* @__PURE__ */ jsxs("span", { className: "relative shrink-0", children: [
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/bottom-tab-bar.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 { resolveActiveNavItem, type NavItem } from \"./nav-model\";\nimport { usePendingNavigation } from \"./use-shell-nav\";\n\nexport interface BottomTabBarLabels {\n /** Accessible name of the bar. Default `\"Main\"`. */\n nav?: string;\n /** Spoken text of a numeric badge, given the real count. Default `\"{n} new\"`. */\n badge?: (count: number) => string;\n}\n\nexport interface BottomTabBarProps\n extends Omit<React.ComponentProps<\"nav\">, \"children\">,\n NavLinkCallbacks {\n /**\n * The tabs, in order. Five is the most a phone holds — every label gets a\n * fifth of ~390px. A tab standing in for several rail rows lists their paths\n * in `also`. `trailing` is not drawn here; `badge` sits on the icon's corner.\n */\n items: readonly NavItem[];\n pathname: string;\n linkComponent?: React.ElementType;\n labels?: BottomTabBarLabels;\n}\n\n/**\n * The mobile tab bar: equal tabs, one rule that slides between them, and a\n * corner badge. Position-agnostic — `AppShell` pins it to the bottom of the\n * viewport and hides it from its breakpoint up; the bar itself reserves the\n * bottom safe area under its `--shell-tab-bar-h`.\n *\n * The rule is a single node translated by whole tab widths (it is exactly one\n * tab wide, so the two cannot drift); on a route no tab claims it fades out\n * where it stands. That is why each tab is `min-w-0`: a long label must\n * truncate, never widen its tab off the rule's arithmetic.\n */\nexport function BottomTabBar({\n items,\n pathname,\n linkComponent,\n onItemIntent,\n onNavigate,\n labels = {},\n className,\n ...props\n}: BottomTabBarProps) {\n const [pendingId, markPending] = usePendingNavigation(pathname);\n const currentId =\n (pendingId !== null && items.some((i) => i.id === pendingId) ? pendingId : undefined) ??\n resolveActiveNavItem(items, pathname)?.id;\n const at = items.findIndex((i) => i.id === currentId);\n return (\n <nav\n data-slot=\"tab-bar\"\n aria-label={labels.nav ?? \"Main\"}\n className={cn(\n \"relative box-content flex h-(--shell-tab-bar-h) items-center border-t border-border bg-card px-2 pb-[env(safe-area-inset-bottom,0px)]\",\n className,\n )}\n {...props}\n >\n <span\n data-slot=\"tab-bar-marker\"\n data-state={at >= 0 ? \"active\" : \"idle\"}\n aria-hidden\n className=\"pointer-events-none absolute left-2 top-0 flex justify-center\"\n // `left-2` + `1rem` restate the bar's `px-2`: the rule is one tab wide.\n style={{\n width: `calc((100% - 1rem) / ${Math.max(items.length, 1)})`,\n translate: `${Math.max(at, 0) * 100}% 0`,\n }}\n >\n <span className=\"h-0.5 w-10 rounded-full bg-primary-ink\" />\n </span>\n {items.map((item) => {\n const Icon = item.icon;\n const active = item.id === currentId;\n return (\n <NavLink\n key={item.id}\n item={item}\n current={active}\n pending={item.id === pendingId}\n linkComponent={linkComponent}\n markPending={markPending}\n onItemIntent={onItemIntent}\n onNavigate={onNavigate}\n className={cn(\n \"flex min-w-0 flex-1 flex-col items-center justify-center gap-0.5 rounded-row py-1 font-medium transition-colors\",\n \"outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-secondary\",\n active ? \"text-primary-ink\" : \"text-ink-soft hover:text-ink\",\n item.disabled && \"cursor-not-allowed opacity-(--disabled-opacity)\",\n )}\n >\n <span className=\"relative shrink-0\">\n {Icon ? <Icon className=\"size-5\" /> : <span className=\"block size-5\" />}\n {typeof item.badge === \"number\" ? (\n <NavBadge\n count={item.badge}\n variant=\"corner\"\n {...(labels.badge ? { label: labels.badge } : {})}\n />\n ) : (\n item.badge\n )}\n </span>\n <span className=\"w-full truncate text-center text-xs\" title={labelTitle(item.label)}>\n {item.label}\n </span>\n </NavLink>\n );\n })}\n </nav>\n );\n}\n"],"mappings":";AA6EQ,cAsBI,YAtBJ;AA3ER,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB,SAAS,gBAAgB;AACzB,SAAS,YAAY,eAAsC;AAC3D,SAAS,4BAA0C;AACnD,SAAS,4BAA4B;AAkC9B,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,CAAC;AAAA,EACV;AAAA,EACA,GAAG;AACL,GAAsB;AACpB,QAAM,CAAC,WAAW,WAAW,IAAI,qBAAqB,QAAQ;AAC9D,QAAM,aACH,cAAc,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,SAAS,IAAI,YAAY,WAC3E,qBAAqB,OAAO,QAAQ,GAAG;AACzC,QAAM,KAAK,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,SAAS;AACpD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,cAAY,OAAO,OAAO;AAAA,MAC1B,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,aAAU;AAAA,YACV,cAAY,MAAM,IAAI,WAAW;AAAA,YACjC,eAAW;AAAA,YACX,WAAU;AAAA,YAEV,OAAO;AAAA,cACL,OAAO,wBAAwB,KAAK,IAAI,MAAM,QAAQ,CAAC,CAAC;AAAA,cACxD,WAAW,GAAG,KAAK,IAAI,IAAI,CAAC,IAAI,GAAG;AAAA,YACrC;AAAA,YAEA,8BAAC,UAAK,WAAU,0CAAyC;AAAA;AAAA,QAC3D;AAAA,QACC,MAAM,IAAI,CAAC,SAAS;AACnB,gBAAM,OAAO,KAAK;AAClB,gBAAM,SAAS,KAAK,OAAO;AAC3B,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC;AAAA,cACA,SAAS;AAAA,cACT,SAAS,KAAK,OAAO;AAAA,cACrB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA,WAAW;AAAA,gBACT;AAAA,gBACA;AAAA,gBACA,SAAS,qBAAqB;AAAA,gBAC9B,KAAK,YAAY;AAAA,cACnB;AAAA,cAEA;AAAA,qCAAC,UAAK,WAAU,qBACb;AAAA,yBAAO,oBAAC,QAAK,WAAU,UAAS,IAAK,oBAAC,UAAK,WAAU,gBAAe;AAAA,kBACpE,OAAO,KAAK,UAAU,WACrB;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO,KAAK;AAAA,sBACZ,SAAQ;AAAA,sBACP,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA;AAAA,kBACjD,IAEA,KAAK;AAAA,mBAET;AAAA,gBACA,oBAAC,UAAK,WAAU,uCAAsC,OAAO,WAAW,KAAK,KAAK,GAC/E,eAAK,OACR;AAAA;AAAA;AAAA,YA7BK,KAAK;AAAA,UA8BZ;AAAA,QAEJ,CAAC;AAAA;AAAA;AAAA,EACH;AAEJ;","names":[]}
@@ -10,21 +10,23 @@ import {
10
10
  CHAT_COMPOSER_SPACER,
11
11
  CHAT_COMPOSER_STREAMING,
12
12
  CHAT_COMPOSER_TOOLBAR,
13
- MODEL_CHIP_BASE
14
- } from "../generated/chat-composer.js";
15
- import { cn } from "../lib/cn.js";
16
- import { useControllableState } from "../primitives/use-controllable-state.js";
13
+ MODEL_CHIP_BASE,
14
+ CHAT_COMPOSER_LABELS
15
+ } from "../../generated/chat-composer.js";
16
+ import { cn } from "../../lib/cn.js";
17
+ import { useControllableState } from "../../primitives/use-controllable-state.js";
17
18
  import {
18
19
  DropdownMenu,
19
20
  DropdownMenuContent,
20
21
  DropdownMenuRadioGroup,
21
22
  DropdownMenuRadioItem,
22
23
  DropdownMenuTrigger
23
- } from "./dropdown-menu.js";
24
- import { IconButton } from "./icon-button.js";
25
- import { Textarea } from "./textarea.js";
26
- import { UiIcon } from "./ui-icons.js";
27
- function ModelChip({ models, value, onValueChange, "aria-label": ariaLabel = "Model", className }) {
24
+ } from "../atomic/dropdown-menu.js";
25
+ import { IconButton } from "../derived/icon-button.js";
26
+ import { Textarea } from "../atomic/textarea.js";
27
+ import { UiIcon } from "../../icons/ui-icons.js";
28
+ import * as copy from "../../generated/copy.js";
29
+ function ModelChip({ models, value, onValueChange, "aria-label": ariaLabel = copy.MODEL_CHIP, className }) {
28
30
  const current = models.find((m) => m.id === value);
29
31
  return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
30
32
  /* @__PURE__ */ jsxs(
@@ -49,7 +51,7 @@ function ChatComposer({
49
51
  onSend,
50
52
  streaming = false,
51
53
  onStop,
52
- placeholder = "Ask the assistant\u2026",
54
+ placeholder = copy.CHAT_COMPOSER_PLACEHOLDER,
53
55
  onAttach,
54
56
  attachments,
55
57
  tools,
@@ -92,7 +94,7 @@ function ChatComposer({
92
94
  value: text,
93
95
  disabled,
94
96
  placeholder,
95
- "aria-label": labels.field ?? "Message",
97
+ "aria-label": labels.field ?? CHAT_COMPOSER_LABELS.field,
96
98
  onChange: (e) => setText(e.target.value),
97
99
  onKeyDown: (e) => {
98
100
  if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing && e.keyCode !== 229) {
@@ -104,7 +106,7 @@ function ChatComposer({
104
106
  }
105
107
  ),
106
108
  /* @__PURE__ */ jsxs("div", { className: CHAT_COMPOSER_TOOLBAR, children: [
107
- onAttach && /* @__PURE__ */ jsx(IconButton, { "aria-label": labels.attach ?? "Attach file", size: "sm", onClick: onAttach, disabled, children: /* @__PURE__ */ jsx(UiIcon, { name: "plus" }) }),
109
+ onAttach && /* @__PURE__ */ jsx(IconButton, { "aria-label": labels.attach ?? CHAT_COMPOSER_LABELS.attach, size: "sm", onClick: onAttach, disabled, children: /* @__PURE__ */ jsx(UiIcon, { name: "plus" }) }),
108
110
  tools,
109
111
  /* @__PURE__ */ jsx("span", { className: CHAT_COMPOSER_SPACER }),
110
112
  hint != null && /* @__PURE__ */ jsx("span", { className: CHAT_COMPOSER_HINT, children: hint }),
@@ -112,7 +114,7 @@ function ChatComposer({
112
114
  IconButton,
113
115
  {
114
116
  variant: "outline",
115
- "aria-label": labels.stop ?? "Stop",
117
+ "aria-label": labels.stop ?? CHAT_COMPOSER_LABELS.stop,
116
118
  onClick: () => {
117
119
  onStop?.();
118
120
  root.current?.querySelector("textarea")?.focus();
@@ -123,7 +125,7 @@ function ChatComposer({
123
125
  IconButton,
124
126
  {
125
127
  variant: "outline",
126
- "aria-label": labels.send ?? "Send",
128
+ "aria-label": labels.send ?? CHAT_COMPOSER_LABELS.send,
127
129
  onClick: send,
128
130
  disabled: disabled || trimmed === "",
129
131
  children: /* @__PURE__ */ jsx(UiIcon, { name: "arrow-up" })
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/chat-composer.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n CHAT_COMPOSER_ATTACHMENTS,\n CHAT_COMPOSER_BASE,\n CHAT_COMPOSER_FIELD,\n CHAT_COMPOSER_HINT,\n CHAT_COMPOSER_IDLE,\n CHAT_COMPOSER_SPACER,\n CHAT_COMPOSER_STREAMING,\n CHAT_COMPOSER_TOOLBAR,\n MODEL_CHIP_BASE,\n CHAT_COMPOSER_LABELS,\n} from \"../../generated/chat-composer\";\nimport { cn } from \"../../lib/cn\";\nimport { useControllableState } from \"../../primitives/use-controllable-state\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuTrigger,\n} from \"../atomic/dropdown-menu\";\nimport { IconButton } from \"../derived/icon-button\";\nimport { Textarea } from \"../atomic/textarea\";\nimport { UiIcon } from \"../../icons/ui-icons\";\nimport * as copy from \"../../generated/copy\";\n\nexport interface ModelOption {\n id: string;\n label: string;\n}\n\nexport interface ModelChipProps {\n models: readonly ModelOption[];\n value: string;\n onValueChange: (id: string) => void;\n /** Names the menu. Default `\"Model\"`. */\n \"aria-label\"?: string;\n className?: string;\n}\n\n/** The small bordered button naming the model; opens a radio menu of the options. */\nexport function ModelChip({ models, value, onValueChange, \"aria-label\": ariaLabel = copy.MODEL_CHIP, className }: ModelChipProps) {\n const current = models.find((m) => m.id === value);\n return (\n <DropdownMenu>\n <DropdownMenuTrigger\n aria-label={`${ariaLabel}: ${current?.label ?? value}`}\n data-slot=\"model-chip\"\n className={cn(MODEL_CHIP_BASE, className)}\n >\n {current?.label ?? value}\n <UiIcon name=\"chevron-down\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n <DropdownMenuRadioGroup value={value} onValueChange={onValueChange}>\n {models.map((m) => (\n <DropdownMenuRadioItem key={m.id} value={m.id}>\n {m.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport interface ChatComposerLabels {\n /** Names the message field. Default `\"Message\"`. */\n field?: string;\n send?: string;\n stop?: string;\n attach?: string;\n}\n\nexport interface ChatComposerProps extends Omit<React.ComponentProps<\"div\">, \"onChange\" | \"defaultValue\"> {\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n /** Enter or the send button, with the trimmed text. The field clears afterwards. */\n onSend: (text: string) => void;\n /** The assistant is answering: the button becomes Stop. Enter still queues a follow-up. */\n streaming?: boolean;\n onStop?: () => void;\n placeholder?: string;\n /** Shows the attach button. */\n onAttach?: () => void;\n /** A row of `ChatAttachment`s above the field. */\n attachments?: React.ReactNode;\n /** Model chips and other toolbar controls, after the attach button. */\n tools?: React.ReactNode;\n /** A caption in the toolbar: \"Enter to send · Shift+Enter for a new line\". */\n hint?: React.ReactNode;\n disabled?: boolean;\n labels?: ChatComposerLabels;\n}\n\nexport function ChatComposer({\n value,\n defaultValue = \"\",\n onValueChange,\n onSend,\n streaming = false,\n onStop,\n placeholder = copy.CHAT_COMPOSER_PLACEHOLDER,\n onAttach,\n attachments,\n tools,\n hint,\n disabled = false,\n labels = {},\n className,\n ...props\n}: ChatComposerProps) {\n const [text, setText] = useControllableState<string>({\n ...(value !== undefined ? { value } : {}),\n defaultValue,\n ...(onValueChange ? { onChange: onValueChange } : {}),\n });\n const trimmed = text.trim();\n const root = React.useRef<HTMLDivElement>(null);\n\n const send = () => {\n if (trimmed === \"\" || disabled) return;\n onSend(trimmed);\n setText(\"\");\n };\n\n return (\n <div\n ref={root}\n data-slot=\"chat-composer\"\n data-state={streaming ? \"streaming\" : \"default\"}\n className={cn(\n CHAT_COMPOSER_BASE,\n streaming ? CHAT_COMPOSER_STREAMING : CHAT_COMPOSER_IDLE,\n className,\n )}\n {...props}\n >\n {attachments != null && <div className={CHAT_COMPOSER_ATTACHMENTS}>{attachments}</div>}\n <Textarea\n rows={1}\n value={text}\n disabled={disabled}\n placeholder={placeholder}\n aria-label={labels.field ?? CHAT_COMPOSER_LABELS.field}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n // Enter during IME composition confirms the candidate; it must not send. Safari reports the\n // confirming Enter after compositionend, with isComposing already false and keyCode 229.\n if (e.key === \"Enter\" && !e.shiftKey && !e.nativeEvent.isComposing && e.keyCode !== 229) {\n e.preventDefault();\n send();\n }\n }}\n className={CHAT_COMPOSER_FIELD}\n />\n <div className={CHAT_COMPOSER_TOOLBAR}>\n {onAttach && (\n <IconButton aria-label={labels.attach ?? CHAT_COMPOSER_LABELS.attach} size=\"sm\" onClick={onAttach} disabled={disabled}>\n <UiIcon name=\"plus\" />\n </IconButton>\n )}\n {tools}\n <span className={CHAT_COMPOSER_SPACER} />\n {hint != null && <span className={CHAT_COMPOSER_HINT}>{hint}</span>}\n {streaming ? (\n <IconButton\n variant=\"outline\"\n aria-label={labels.stop ?? CHAT_COMPOSER_LABELS.stop}\n onClick={() => {\n onStop?.();\n // The Stop button turns into Send, so focus would otherwise stay on a swapped-out element.\n root.current?.querySelector(\"textarea\")?.focus();\n }}\n >\n <UiIcon name=\"stop\" />\n </IconButton>\n ) : (\n <IconButton\n variant=\"outline\"\n aria-label={labels.send ?? CHAT_COMPOSER_LABELS.send}\n onClick={send}\n disabled={disabled || trimmed === \"\"}\n >\n <UiIcon name=\"arrow-up\" />\n </IconButton>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
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
5
  import {
6
6
  CHAT_ATTACHMENT_BASE,
7
7
  CHAT_ATTACHMENT_BODY,
@@ -39,10 +39,10 @@ import {
39
39
  chatBubbleVariantClasses,
40
40
  chatStatusDotClasses,
41
41
  chatToolMetaClasses
42
- } from "../generated/chat-message.js";
42
+ } from "../../generated/chat-message.js";
43
43
  import { ChatStreamText } from "./chat-stream-text.js";
44
- import { IconButton } from "./icon-button.js";
45
- import { UiIcon } from "./ui-icons.js";
44
+ import { IconButton } from "../derived/icon-button.js";
45
+ import { UiIcon } from "../../icons/ui-icons.js";
46
46
  function ChatBubble({ variant = "assistant", streaming = false, className, children, ...props }) {
47
47
  const [live, setLive] = React.useState(streaming);
48
48
  if (streaming && !live) setLive(true);
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/chat-message.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport {\n CHAT_ATTACHMENT_BASE,\n CHAT_ATTACHMENT_BODY,\n CHAT_ATTACHMENT_ICON,\n CHAT_ATTACHMENT_META,\n CHAT_ATTACHMENT_NAME,\n CHAT_ATTACHMENT_PROGRESS,\n CHAT_ATTACHMENT_PROGRESS_FILL,\n CHAT_ATTACHMENT_ROW,\n CHAT_BUBBLE_BASE,\n CHAT_MARKER_DOT,\n CHAT_MARKER_RULE,\n CHAT_MARKER_SEPARATOR,\n CHAT_MARKER_SEPARATOR_LABEL,\n CHAT_MARKER_STATUS,\n CHAT_MARKER_TOOL,\n CHAT_MARKER_TOOL_BODY,\n CHAT_MARKER_TOOL_BORDER,\n CHAT_MARKER_TOOL_CHECK,\n CHAT_MARKER_TOOL_DETAIL,\n CHAT_MARKER_TOOL_ERROR_BORDER,\n CHAT_MARKER_TOOL_ICON,\n CHAT_MARKER_TOOL_META,\n CHAT_MARKER_TOOL_TITLE,\n CHAT_MESSAGE_AVATAR,\n CHAT_MESSAGE_AVATAR_TILE,\n CHAT_MESSAGE_BASE,\n CHAT_MESSAGE_BODY,\n CHAT_MESSAGE_BODY_ASSISTANT,\n CHAT_MESSAGE_BODY_USER,\n CHAT_MESSAGE_HEADER,\n CHAT_MESSAGE_NAME,\n CHAT_MESSAGE_TIME,\n CHAT_MESSAGE_USER,\n chatBubbleVariantClasses,\n chatStatusDotClasses,\n chatToolMetaClasses,\n} from \"../../generated/chat-message\";\nimport type { ChatBubbleVariant, ChatStatusState, ChatToolState } from \"../../generated/chat-message\";\nimport { ChatStreamText } from \"./chat-stream-text\";\nimport { IconButton } from \"../derived/icon-button\";\nimport { UiIcon } from \"../../icons/ui-icons\";\nimport type { ChatAttachmentState, ChatAttachmentType, ChatMessageRole } from \"../../generated/chat-message\";\n\nexport type { ChatBubbleVariant };\n\nexport interface ChatBubbleProps extends React.ComponentProps<\"div\"> {\n variant?: ChatBubbleVariant;\n /**\n * Still receiving text: a soft caret pulses after it, and string children\n * fade in word by word (`ChatStreamText`). Stays set until the text is complete.\n */\n streaming?: boolean;\n}\n\n/** One block of message text; `assistant` has no box so long answers read as a page. */\nexport function ChatBubble({ variant = \"assistant\", streaming = false, className, children, ...props }: ChatBubbleProps) {\n // Once a bubble has streamed it keeps its word wrappers and its caret slot, so\n // the last words finish landing and the caret fades out instead of vanishing.\n const [live, setLive] = React.useState(streaming);\n if (streaming && !live) setLive(true);\n return (\n <div\n data-slot=\"chat-bubble\"\n data-variant={variant}\n data-streaming={streaming ? \"\" : undefined}\n data-caret={live ? \"\" : undefined}\n className={cn(CHAT_BUBBLE_BASE, chatBubbleVariantClasses[variant], className)}\n {...props}\n >\n {live && typeof children === \"string\" ? <ChatStreamText text={children} streaming={streaming} /> : children}\n </div>\n );\n}\n\nexport interface ChatMessageProps extends Omit<React.ComponentProps<\"div\">, \"role\"> {\n role: ChatMessageRole;\n /** \"Assistant\", \"You\". */\n name?: React.ReactNode;\n /** Already formatted: \"13:04\". */\n time?: React.ReactNode;\n /** The assistant's tile; a default sparkle tile when omitted. */\n avatar?: React.ReactNode;\n /** Drops the name row and the avatar, for a narrow dock. */\n compact?: boolean;\n}\n\n/** A turn: who spoke, when, then the bubbles and markers. Fades in and rises once when it mounts. */\nexport function ChatMessage({ role, name, time, avatar, compact = false, className, children, ...props }: ChatMessageProps) {\n const user = role === \"user\";\n return (\n <div\n data-slot=\"chat-message\"\n data-role={role}\n data-enter=\"rise\"\n className={cn(CHAT_MESSAGE_BASE, user && CHAT_MESSAGE_USER, className)}\n {...props}\n >\n {!user && !compact && (\n <div className={CHAT_MESSAGE_AVATAR}>\n {avatar ?? (\n <span className={CHAT_MESSAGE_AVATAR_TILE}>\n <UiIcon name=\"sparkles\" />\n </span>\n )}\n </div>\n )}\n <div className={cn(CHAT_MESSAGE_BODY, user ? CHAT_MESSAGE_BODY_USER : CHAT_MESSAGE_BODY_ASSISTANT)}>\n {!compact && (name != null || time != null) && (\n <div className={CHAT_MESSAGE_HEADER}>\n {name != null && <span className={CHAT_MESSAGE_NAME}>{name}</span>}\n {time != null && <span className={CHAT_MESSAGE_TIME}>{time}</span>}\n </div>\n )}\n {children}\n </div>\n </div>\n );\n}\n\nexport type ChatMarkerProps = Omit<React.ComponentProps<\"div\">, \"title\"> &\n (\n | { type: \"status\"; state?: ChatStatusState }\n | {\n type: \"tool\";\n state?: ChatToolState;\n /** The tool's name. */\n title: React.ReactNode;\n detail?: React.ReactNode;\n /** The right-hand note: \"Running…\", \"0.4s\", \"Failed · 1.2s\". */\n meta?: React.ReactNode;\n }\n | { type: \"separator\" }\n );\n\n/** The quiet lines between messages: progress, a tool call, or a day break. */\nexport function ChatMarker(allProps: ChatMarkerProps) {\n if (allProps.type === \"separator\") {\n const { type: _type, className, children, ...rest } = allProps;\n return (\n <div data-slot=\"chat-marker\" data-type=\"separator\" className={cn(CHAT_MARKER_SEPARATOR, className)} {...rest}>\n <span className={CHAT_MARKER_RULE} />\n <span className={CHAT_MARKER_SEPARATOR_LABEL}>{children}</span>\n <span className={CHAT_MARKER_RULE} />\n </div>\n );\n }\n if (allProps.type === \"status\") {\n const { type: _type, state = \"done\", className, children, ...rest } = allProps;\n return (\n <div\n data-slot=\"chat-marker\"\n data-type=\"status\"\n data-state={state}\n role={state === \"running\" ? \"status\" : undefined}\n className={cn(CHAT_MARKER_STATUS, className)}\n {...rest}\n >\n <span\n aria-hidden\n className={cn(CHAT_MARKER_DOT, chatStatusDotClasses[state])}\n />\n {children}\n </div>\n );\n }\n const { type: _type, state = \"done\", title, detail, meta, className, children, ...rest } = allProps;\n return (\n <div\n data-slot=\"chat-marker\"\n data-type=\"tool\"\n data-state={state}\n className={cn(\n CHAT_MARKER_TOOL,\n state === \"error\" ? CHAT_MARKER_TOOL_ERROR_BORDER : CHAT_MARKER_TOOL_BORDER,\n className,\n )}\n {...rest}\n >\n <UiIcon name={state === \"error\" ? \"alert\" : \"sparkles\"} className={CHAT_MARKER_TOOL_ICON} />\n <div className={CHAT_MARKER_TOOL_BODY}>\n <span className={CHAT_MARKER_TOOL_TITLE}>{title}</span>\n {detail != null && <span className={CHAT_MARKER_TOOL_DETAIL}>{detail}</span>}\n {children}\n </div>\n {meta != null && (\n <span className={cn(CHAT_MARKER_TOOL_META, chatToolMetaClasses[state])}>{meta}\n </span>\n )}\n {state === \"done\" && <UiIcon name=\"check\" className={CHAT_MARKER_TOOL_CHECK} />}\n </div>\n );\n}\n\nexport interface ChatAttachmentProps extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n type?: ChatAttachmentType;\n state?: ChatAttachmentState;\n name: string;\n /** \"PDF · 1.2 MB\"; while uploading, defaults to the percentage. */\n meta?: React.ReactNode;\n /** 0 to 100, while uploading. */\n progress?: number;\n /** Shows the remove button. */\n onRemove?: () => void;\n /** Default `\"Remove {name}\"`. */\n removeLabel?: string;\n}\n\n/** A card for a file in a message or in the composer. */\nexport function ChatAttachment({\n type = \"file\",\n state = \"ready\",\n name,\n meta,\n progress = 0,\n onRemove,\n removeLabel,\n className,\n ...props\n}: ChatAttachmentProps) {\n const pct = Math.min(100, Math.max(0, Math.round(progress)));\n return (\n <div\n data-slot=\"chat-attachment\"\n data-type={type}\n data-state={state}\n className={cn(CHAT_ATTACHMENT_BASE, className)}\n {...props}\n >\n <div className={CHAT_ATTACHMENT_ROW}>\n <span className={CHAT_ATTACHMENT_ICON}>\n <UiIcon name={type === \"image\" ? \"image\" : \"file\"} />\n </span>\n <div className={CHAT_ATTACHMENT_BODY}>\n <span className={CHAT_ATTACHMENT_NAME}>{name}</span>\n <span className={CHAT_ATTACHMENT_META}>{meta ?? (state === \"uploading\" ? `Uploading… ${pct}%` : null)}</span>\n </div>\n {onRemove && (\n <IconButton aria-label={removeLabel ?? `Remove ${name}`} size=\"sm\" onClick={onRemove}>\n <UiIcon name=\"x\" />\n </IconButton>\n )}\n </div>\n {state === \"uploading\" && (\n <div\n role=\"progressbar\"\n aria-label={name}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={pct}\n className={CHAT_ATTACHMENT_PROGRESS}\n >\n <div className={CHAT_ATTACHMENT_PROGRESS_FILL} style={{ width: `${pct}%` }} />\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["_type","className","children","rest","state"]}
@@ -1,10 +1,10 @@
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
5
  import { AsideHeader } from "./aside.js";
6
- import { IconButton } from "./icon-button.js";
7
- import { UiIcon } from "./ui-icons.js";
6
+ import { IconButton } from "../derived/icon-button.js";
7
+ import { UiIcon } from "../../icons/ui-icons.js";
8
8
  const PIN_SLACK = 24;
9
9
  function ChatPanel({ children, empty, composer, streaming = false, labels = {}, className, ...props }) {
10
10
  const scroller = React.useRef(null);
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/chat-panel.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { AsideHeader } from \"./aside\";\nimport { IconButton } from \"../derived/icon-button\";\nimport { UiIcon } from \"../../icons/ui-icons\";\n\n// Within this many pixels of the end still counts as \"at the end\": sub-pixel\n// scroll positions and a growing last line would otherwise unpin the reader.\nconst PIN_SLACK = 24;\n\nexport interface ChatPanelLabels {\n /** The scroll-to-end button. Default `\"Jump to latest\"`. */\n jump?: string;\n /** Names the log region. Default `\"Conversation\"`. */\n log?: string;\n}\n\nexport interface ChatPanelProps extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** `ChatMessage`s and `ChatMarker`s, oldest first. */\n children?: React.ReactNode;\n /** Shown instead of the log while there is nothing to read. */\n empty?: React.ReactNode;\n /** The composer, under the log. */\n composer?: React.ReactNode;\n /**\n * The last turn is still arriving. The log is marked busy, so a screen reader\n * waits for the finished text instead of announcing every chunk.\n */\n streaming?: boolean;\n labels?: ChatPanelLabels;\n}\n\n/**\n * The conversation: a scrolling log that follows new content while the reader\n * is at the end, and lets go the moment they scroll up. The jump button brings\n * them back. The log is a polite live region, so new turns are announced\n * without taking focus.\n */\nexport function ChatPanel({ children, empty, composer, streaming = false, labels = {}, className, ...props }: ChatPanelProps) {\n const scroller = React.useRef<HTMLDivElement>(null);\n const pinned = React.useRef(true);\n const [away, setAway] = React.useState(false);\n const [scrolled, setScrolled] = React.useState(false);\n // `count` would call `false` a child, and `{list.length > 0 && …}` is common.\n const isEmpty = React.Children.toArray(children).length === 0 && empty != null;\n\n const toEnd = () => {\n const el = scroller.current;\n if (el) el.scrollTop = el.scrollHeight;\n };\n\n // Streaming grows the last node's text without adding nodes, so watch characters too.\n React.useEffect(() => {\n const el = scroller.current;\n if (!el) return;\n const follow = () => {\n if (pinned.current) toEnd();\n };\n const mo = new MutationObserver(follow);\n mo.observe(el, { childList: true, subtree: true, characterData: true });\n const ro = typeof ResizeObserver === \"function\" ? new ResizeObserver(follow) : null;\n ro?.observe(el);\n toEnd();\n return () => {\n mo.disconnect();\n ro?.disconnect();\n };\n }, [isEmpty]);\n\n return (\n <div data-slot=\"chat-panel\" className={cn(\"flex min-h-0 flex-1 flex-col\", className)} {...props}>\n <div className=\"relative flex min-h-0 flex-1 flex-col\">\n {isEmpty ? (\n <div className=\"flex flex-1 flex-col justify-center px-4\">{empty}</div>\n ) : (\n <div\n ref={scroller}\n role=\"log\"\n aria-live=\"polite\"\n aria-busy={streaming}\n aria-label={labels.log ?? \"Conversation\"}\n tabIndex={0}\n data-slot=\"chat-log\"\n data-scrolled={scrolled ? \"\" : undefined}\n className=\"flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto p-4 outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring\"\n onScroll={(e) => {\n const el = e.currentTarget;\n const atEnd = el.scrollHeight - el.scrollTop - el.clientHeight <= PIN_SLACK;\n pinned.current = atEnd;\n setAway(!atEnd);\n setScrolled(el.scrollTop > 0);\n }}\n >\n {children}\n </div>\n )}\n {!isEmpty && (\n // Stays mounted so it can fade; hidden from the tree and the tab order until it matters.\n <IconButton\n variant=\"outline\"\n aria-label={labels.jump ?? \"Jump to latest\"}\n data-chat-jump={away ? \"visible\" : \"hidden\"}\n aria-hidden={!away}\n tabIndex={away ? 0 : -1}\n disabled={!away}\n className=\"absolute bottom-3 left-1/2 -translate-x-1/2\"\n onClick={() => {\n pinned.current = true;\n setAway(false);\n toEnd();\n // The button unmounts with `away`; keep focus in the conversation.\n scroller.current?.focus();\n }}\n >\n <UiIcon name=\"chevron-down\" />\n </IconButton>\n )}\n </div>\n {composer != null && <div className=\"shrink-0 px-4 pb-4\">{composer}</div>}\n </div>\n );\n}\n\nexport interface ChatDockLabels extends ChatPanelLabels {\n /** The launcher bar's name when collapsed. Default `\"Open assistant\"`. */\n open?: string;\n /** Default `\"Collapse\"`. */\n collapse?: string;\n}\n\nexport interface ChatDockProps extends Omit<React.ComponentProps<\"section\">, \"title\" | \"children\"> {\n title: React.ReactNode;\n expanded?: boolean;\n defaultExpanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** Header buttons before collapse: history. */\n actions?: React.ReactNode;\n /** The launcher bar's text when collapsed. */\n prompt?: string;\n children?: React.ReactNode;\n empty?: React.ReactNode;\n composer?: React.ReactNode;\n streaming?: boolean;\n labels?: ChatDockLabels;\n}\n\n/** The assistant docked in a column: a launcher bar when collapsed, header + conversation + composer when open. */\nexport function ChatDock({\n title,\n expanded,\n defaultExpanded = true,\n onExpandedChange,\n actions,\n prompt = \"Ask the assistant…\",\n children,\n empty,\n composer,\n streaming = false,\n labels = {},\n className,\n ...props\n}: ChatDockProps) {\n const [inner, setInner] = React.useState(defaultExpanded);\n const open = expanded ?? inner;\n const root = React.useRef<HTMLElement>(null);\n const moved = React.useRef(false);\n const set = (next: boolean) => {\n moved.current = true;\n setInner(next);\n onExpandedChange?.(next);\n };\n // The button that was pressed unmounts with its state; hand focus to the same job in the other one.\n React.useEffect(() => {\n if (!moved.current) return;\n moved.current = false;\n const target = open\n ? (root.current?.querySelector<HTMLElement>(\"textarea\") ?? root.current?.querySelector<HTMLElement>(\"[role=log]\"))\n : root.current?.querySelector<HTMLElement>(\"button\");\n target?.focus();\n }, [open]);\n if (!open) {\n return (\n <section ref={root} data-slot=\"chat-dock\" data-state=\"collapsed\" className={cn(\"bg-card\", className)} {...props}>\n <button\n type=\"button\"\n aria-label={labels.open ?? \"Open assistant\"}\n onClick={() => set(true)}\n className=\"flex h-11 w-full items-center gap-2 border-t border-border px-4 text-left text-body text-ink-soft outline-none hover:bg-hover focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring\"\n >\n <UiIcon name=\"sparkles\" />\n {prompt}\n </button>\n </section>\n );\n }\n return (\n <section ref={root} data-slot=\"chat-dock\" data-state=\"expanded\" className={cn(\"flex h-full min-h-0 flex-col bg-card\", className)} {...props}>\n <AsideHeader title={title} actions={actions} onClose={() => set(false)} labels={{ close: labels.collapse ?? \"Collapse\" }} />\n <ChatPanel empty={empty} composer={composer} streaming={streaming} labels={labels}>\n {children}\n </ChatPanel>\n </section>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/chat-stream-text.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\n// Words in one chunk start this far apart, up to STAGGER_CAP of them, so a burst\n// of text reads as a ripple instead of landing at once.\nconst STAGGER_STEP_MS = 28;\nconst STAGGER_CAP = 6;\n// Safety net for when `animationend` never fires (hidden tab, display: none).\nconst SETTLE_FALLBACK_MS = 900;\n\ninterface Unit {\n word: string;\n /** The whitespace that follows the word, kept outside the animated span. */\n gap: string;\n}\n\nfunction split(text: string): { lead: string; units: Unit[] } {\n const lead = /^\\s*/.exec(text)?.[0] ?? \"\";\n const units: Unit[] = [];\n for (const m of text.slice(lead.length).matchAll(/(\\S+)(\\s*)/g)) units.push({ word: m[1] ?? \"\", gap: m[2] ?? \"\" });\n return { lead, units };\n}\n\ninterface Progress {\n text: string;\n /** Units before this index are plain text; the rest are animating. */\n settled: number;\n /** Start delay per unit, fixed when the unit appears so re-renders never restart it. */\n delays: number[];\n}\n\nfunction delaysFor(from: number, to: number): number[] {\n return Array.from({ length: to - from }, (_, j) => Math.min(j, STAGGER_CAP) * STAGGER_STEP_MS);\n}\n\nexport interface ChatStreamTextProps extends Omit<React.ComponentProps<\"span\">, \"children\"> {\n /** The text so far. Pass the whole growing string; only the appended tail animates. */\n text: string;\n /**\n * The text is still growing. A string that is already complete when this\n * mounts as `false` shows at once, with no entrance.\n */\n streaming?: boolean;\n}\n\n/**\n * Text that arrives word by word. New words fade in from a soft blur and settle\n * (motion.css); words already on screen are never touched again. Once a word has\n * landed it folds into one plain text node, so a long reply costs a handful of\n * elements, not thousands. The text content stays exactly `text`.\n */\nexport function ChatStreamText({ text, streaming = false, ...props }: ChatStreamTextProps) {\n const parsed = split(text);\n const [progress, setProgress] = React.useState<Progress>(() => ({\n text,\n settled: streaming ? 0 : parsed.units.length,\n delays: delaysFor(0, parsed.units.length),\n }));\n\n let cur = progress;\n if (text !== progress.text) {\n // Anything but an append (edit, regenerate) starts over rather than patching words in place.\n const appended = text.startsWith(progress.text);\n const known = appended ? split(progress.text).units.length : 0;\n cur = {\n text,\n settled: appended ? progress.settled : 0,\n delays: [...(appended ? progress.delays.slice(0, known) : []), ...delaysFor(known, parsed.units.length)],\n };\n setProgress(cur);\n }\n\n const settle = React.useCallback((upTo: number) => {\n setProgress((p) => (upTo > p.settled ? { ...p, settled: upTo } : p));\n }, []);\n\n const total = parsed.units.length;\n React.useEffect(() => {\n if (streaming) return;\n const id = setTimeout(() => settle(total), SETTLE_FALLBACK_MS);\n return () => clearTimeout(id);\n }, [streaming, total, settle]);\n\n const settledText = parsed.lead + parsed.units.slice(0, cur.settled).map((u) => u.word + u.gap).join(\"\");\n return (\n <span\n data-slot=\"chat-stream-text\"\n onAnimationEnd={(e) => {\n const i = Number((e.target as HTMLElement).dataset[\"word\"]);\n if (Number.isInteger(i)) settle(i + 1);\n }}\n {...props}\n >\n {settledText}\n {parsed.units.slice(cur.settled).map((u, k) => {\n const i = cur.settled + k;\n return (\n <React.Fragment key={i}>\n <span data-slot=\"chat-word\" data-word={i} style={{ animationDelay: `${cur.delays[i] ?? 0}ms` }}>\n {u.word}\n </span>\n {u.gap}\n </React.Fragment>\n );\n })}\n </span>\n );\n}\n"],"mappings":";AAkGU,SACE,KADF;AAhGV,YAAY,WAAW;AAIvB,MAAM,kBAAkB;AACxB,MAAM,cAAc;AAEpB,MAAM,qBAAqB;AAQ3B,SAAS,MAAM,MAA+C;AAC5D,QAAM,OAAO,OAAO,KAAK,IAAI,IAAI,CAAC,KAAK;AACvC,QAAM,QAAgB,CAAC;AACvB,aAAW,KAAK,KAAK,MAAM,KAAK,MAAM,EAAE,SAAS,aAAa,EAAG,OAAM,KAAK,EAAE,MAAM,EAAE,CAAC,KAAK,IAAI,KAAK,EAAE,CAAC,KAAK,GAAG,CAAC;AACjH,SAAO,EAAE,MAAM,MAAM;AACvB;AAUA,SAAS,UAAU,MAAc,IAAsB;AACrD,SAAO,MAAM,KAAK,EAAE,QAAQ,KAAK,KAAK,GAAG,CAAC,GAAG,MAAM,KAAK,IAAI,GAAG,WAAW,IAAI,eAAe;AAC/F;AAkBO,SAAS,eAAe,EAAE,MAAM,YAAY,OAAO,GAAG,MAAM,GAAwB;AACzF,QAAM,SAAS,MAAM,IAAI;AACzB,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAmB,OAAO;AAAA,IAC9D;AAAA,IACA,SAAS,YAAY,IAAI,OAAO,MAAM;AAAA,IACtC,QAAQ,UAAU,GAAG,OAAO,MAAM,MAAM;AAAA,EAC1C,EAAE;AAEF,MAAI,MAAM;AACV,MAAI,SAAS,SAAS,MAAM;AAE1B,UAAM,WAAW,KAAK,WAAW,SAAS,IAAI;AAC9C,UAAM,QAAQ,WAAW,MAAM,SAAS,IAAI,EAAE,MAAM,SAAS;AAC7D,UAAM;AAAA,MACJ;AAAA,MACA,SAAS,WAAW,SAAS,UAAU;AAAA,MACvC,QAAQ,CAAC,GAAI,WAAW,SAAS,OAAO,MAAM,GAAG,KAAK,IAAI,CAAC,GAAI,GAAG,UAAU,OAAO,OAAO,MAAM,MAAM,CAAC;AAAA,IACzG;AACA,gBAAY,GAAG;AAAA,EACjB;AAEA,QAAM,SAAS,MAAM,YAAY,CAAC,SAAiB;AACjD,gBAAY,CAAC,MAAO,OAAO,EAAE,UAAU,EAAE,GAAG,GAAG,SAAS,KAAK,IAAI,CAAE;AAAA,EACrE,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQ,OAAO,MAAM;AAC3B,QAAM,UAAU,MAAM;AACpB,QAAI,UAAW;AACf,UAAM,KAAK,WAAW,MAAM,OAAO,KAAK,GAAG,kBAAkB;AAC7D,WAAO,MAAM,aAAa,EAAE;AAAA,EAC9B,GAAG,CAAC,WAAW,OAAO,MAAM,CAAC;AAE7B,QAAM,cAAc,OAAO,OAAO,OAAO,MAAM,MAAM,GAAG,IAAI,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE;AACvG,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,gBAAgB,CAAC,MAAM;AACrB,cAAM,IAAI,OAAQ,EAAE,OAAuB,QAAQ,MAAM,CAAC;AAC1D,YAAI,OAAO,UAAU,CAAC,EAAG,QAAO,IAAI,CAAC;AAAA,MACvC;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,QACA,OAAO,MAAM,MAAM,IAAI,OAAO,EAAE,IAAI,CAAC,GAAG,MAAM;AAC7C,gBAAM,IAAI,IAAI,UAAU;AACxB,iBACE,qBAAC,MAAM,UAAN,EACC;AAAA,gCAAC,UAAK,aAAU,aAAY,aAAW,GAAG,OAAO,EAAE,gBAAgB,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,GAC1F,YAAE,MACL;AAAA,YACC,EAAE;AAAA,eAJgB,CAKrB;AAAA,QAEJ,CAAC;AAAA;AAAA;AAAA,EACH;AAEJ;","names":[]}
@@ -1,8 +1,9 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
- import { CHAT_TYPING_BASE, CHAT_TYPING_DOT, CHAT_TYPING_STILL } from "../generated/chat-typing.js";
4
- import { cn } from "../lib/cn.js";
5
- function ChatTyping({ label = "Assistant is thinking", className, ...props }) {
3
+ import { CHAT_TYPING_BASE, CHAT_TYPING_DOT, CHAT_TYPING_STILL } from "../../generated/chat-typing.js";
4
+ import { cn } from "../../lib/cn.js";
5
+ import * as copy from "../../generated/copy.js";
6
+ function ChatTyping({ label = copy.CHAT_TYPING, className, ...props }) {
6
7
  return /* @__PURE__ */ jsxs(
7
8
  "span",
8
9
  {
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/shell/chat-typing.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { CHAT_TYPING_BASE, CHAT_TYPING_DOT, CHAT_TYPING_STILL } from \"../../generated/chat-typing\";\nimport { cn } from \"../../lib/cn\";\nimport * as copy from \"../../generated/copy\";\n\nexport interface ChatTypingProps extends Omit<React.ComponentProps<\"span\">, \"children\"> {\n /** Names the state for assistive tech. Default `\"Assistant is thinking\"`. */\n label?: string;\n}\n\n/**\n * The wait before the first token: three dots whose opacity ripples. Under\n * reduced motion CSS swaps them for a still \"…\". It is a status region, so a\n * screen reader hears the label once when it appears.\n */\nexport function ChatTyping({ label = copy.CHAT_TYPING, className, ...props }: ChatTypingProps) {\n return (\n <span\n role=\"status\"\n aria-label={label}\n data-slot=\"chat-typing\"\n className={cn(CHAT_TYPING_BASE, className)}\n {...props}\n >\n <span aria-hidden data-dot className={CHAT_TYPING_DOT} />\n <span aria-hidden data-dot className={CHAT_TYPING_DOT} />\n <span aria-hidden data-dot className={CHAT_TYPING_DOT} />\n <span aria-hidden data-still className={CHAT_TYPING_STILL}>\n …\n </span>\n </span>\n );\n}\n"],"mappings":"AAiBI,SAOE,KAPF;AAjBJ,YAAY,WAAW;AACvB,SAAS,kBAAkB,iBAAiB,yBAAyB;AACrE,SAAS,UAAU;AACnB,YAAY,UAAU;AAYf,SAAS,WAAW,EAAE,QAAQ,KAAK,aAAa,WAAW,GAAG,MAAM,GAAoB;AAC7F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,aAAU;AAAA,MACV,WAAW,GAAG,kBAAkB,SAAS;AAAA,MACxC,GAAG;AAAA,MAEJ;AAAA,4BAAC,UAAK,eAAW,MAAC,YAAQ,MAAC,WAAW,iBAAiB;AAAA,QACvD,oBAAC,UAAK,eAAW,MAAC,YAAQ,MAAC,WAAW,iBAAiB;AAAA,QACvD,oBAAC,UAAK,eAAW,MAAC,YAAQ,MAAC,WAAW,iBAAiB;AAAA,QACvD,oBAAC,UAAK,eAAW,MAAC,cAAU,MAAC,WAAW,mBAAmB,oBAE3D;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1,7 +1,9 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
- import { Container } from "./container.js";
4
- const HEADING = "font-mono text-xs text-ink uppercase tracking-widest mb-6";
3
+ import { Container } from "../atomic/container.js";
4
+ import * as copy from "../../generated/copy.js";
5
+ import { FOOTER_BRAND, FOOTER_COPYRIGHT, FOOTER_DESCRIPTION, FOOTER_GRID, FOOTER_HEADING, FOOTER_LEGAL_LINK, FOOTER_LEGAL_LINKS, FOOTER_LEGAL_SEPARATOR, FOOTER_LOCKUP, FOOTER_LOCKUP_TEXT, FOOTER_NAV_COLUMN, FOOTER_NAV_LINK, FOOTER_NAV_LIST, FOOTER_NEWSLETTER_BLURB, FOOTER_NEWSLETTER_COLUMN, FOOTER_OFFICES_LIST, FOOTER_OFFICE_NAME, FOOTER_ROOT, FOOTER_TAGLINE, FOOTER_VERSION, FOOTER_WIDE_COLUMN } from "../../generated/footer.js";
6
+ const HEADING = FOOTER_HEADING;
5
7
  function Footer({
6
8
  lockup,
7
9
  brand,
@@ -11,10 +13,10 @@ function Footer({
11
13
  copyright,
12
14
  nav = [],
13
15
  offices = [],
14
- officesHeading = "Offices",
16
+ officesHeading = copy.FOOTER_OFFICES,
15
17
  legalLinks = [],
16
18
  newsletter,
17
- newsletterHeading = "Newsletter",
19
+ newsletterHeading = copy.FOOTER_NEWSLETTER,
18
20
  newsletterBlurb = "",
19
21
  version,
20
22
  commitHref,
@@ -24,47 +26,47 @@ function Footer({
24
26
  const L = linkComponent ?? "a";
25
27
  const composed = brand !== void 0 || mark !== void 0;
26
28
  const hasBrandColumn = lockup !== void 0 || composed || description !== void 0 || legalLinks.length > 0;
27
- return /* @__PURE__ */ jsxs("footer", { "data-slot": "footer", className: "bg-background border-t border-ink/10 py-16", children: [
29
+ return /* @__PURE__ */ jsxs("footer", { "data-slot": "footer", className: FOOTER_ROOT, children: [
28
30
  children,
29
31
  /* @__PURE__ */ jsxs(Container, { children: [
30
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-8 gap-y-8 lg:grid-cols-12 mb-12", children: [
31
- hasBrandColumn && /* @__PURE__ */ jsxs("div", { className: "col-span-2 lg:col-span-3", children: [
32
+ /* @__PURE__ */ jsxs("div", { className: FOOTER_GRID, children: [
33
+ hasBrandColumn && /* @__PURE__ */ jsxs("div", { className: FOOTER_WIDE_COLUMN, children: [
32
34
  lockup !== void 0 ? /* @__PURE__ */ jsx("div", { "data-slot": "footer-lockup", className: "mb-6", children: lockup }) : composed && /* @__PURE__ */ jsx(FooterLockup, { brand, mark, tagline }),
33
- description !== void 0 && /* @__PURE__ */ jsx("p", { className: "text-ink/40 text-xs font-light max-w-sm leading-relaxed mb-6", children: description }),
34
- legalLinks.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex gap-4 text-xs font-mono text-primary-ink", children: legalLinks.map((link, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
35
- i > 0 && /* @__PURE__ */ jsx("span", { className: "text-ink/20", children: "|" }),
36
- /* @__PURE__ */ jsx(L, { href: link.href, className: "hover:underline", children: link.label })
35
+ description !== void 0 && /* @__PURE__ */ jsx("p", { className: FOOTER_DESCRIPTION, children: description }),
36
+ legalLinks.length > 0 && /* @__PURE__ */ jsx("div", { className: FOOTER_LEGAL_LINKS, children: legalLinks.map((link, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
37
+ i > 0 && /* @__PURE__ */ jsx("span", { className: FOOTER_LEGAL_SEPARATOR, children: "|" }),
38
+ /* @__PURE__ */ jsx(L, { href: link.href, className: FOOTER_LEGAL_LINK, children: link.label })
37
39
  ] }, link.label)) })
38
40
  ] }),
39
- nav.map((group) => /* @__PURE__ */ jsxs("nav", { "aria-label": `Footer ${group.heading} links`, className: "lg:col-span-2", children: [
41
+ nav.map((group) => /* @__PURE__ */ jsxs("nav", { "aria-label": `Footer ${group.heading} links`, className: FOOTER_NAV_COLUMN, children: [
40
42
  /* @__PURE__ */ jsx("h4", { className: HEADING, children: group.heading }),
41
- /* @__PURE__ */ jsx("ul", { className: "space-y-3", children: group.links.map((link) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
43
+ /* @__PURE__ */ jsx("ul", { className: FOOTER_NAV_LIST, children: group.links.map((link) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
42
44
  L,
43
45
  {
44
46
  href: link.href,
45
- className: "text-xs font-light text-ink/70 hover:text-primary-ink transition-colors",
47
+ className: FOOTER_NAV_LINK,
46
48
  children: link.label
47
49
  }
48
50
  ) }, link.href)) })
49
51
  ] }, group.heading)),
50
- offices.length > 0 && /* @__PURE__ */ jsxs("div", { className: "col-span-2 lg:col-span-3", children: [
52
+ offices.length > 0 && /* @__PURE__ */ jsxs("div", { className: FOOTER_WIDE_COLUMN, children: [
51
53
  /* @__PURE__ */ jsx("h4", { className: HEADING, children: officesHeading }),
52
- /* @__PURE__ */ jsx("ul", { className: "space-y-4 text-xs text-ink/70 font-light leading-relaxed", children: offices.map((office) => /* @__PURE__ */ jsxs("li", { children: [
53
- /* @__PURE__ */ jsx("strong", { className: "text-ink block font-mono text-[10px] uppercase tracking-wider mb-1", children: office.name }),
54
+ /* @__PURE__ */ jsx("ul", { className: FOOTER_OFFICES_LIST, children: offices.map((office) => /* @__PURE__ */ jsxs("li", { children: [
55
+ /* @__PURE__ */ jsx("strong", { className: FOOTER_OFFICE_NAME, children: office.name }),
54
56
  office.address
55
57
  ] }, office.name)) })
56
58
  ] }),
57
- newsletter && /* @__PURE__ */ jsxs("div", { className: "col-span-2 lg:col-span-2", children: [
59
+ newsletter && /* @__PURE__ */ jsxs("div", { className: FOOTER_NEWSLETTER_COLUMN, children: [
58
60
  /* @__PURE__ */ jsx("h4", { className: HEADING, children: newsletterHeading }),
59
- /* @__PURE__ */ jsx("p", { className: "text-sm sm:text-xs font-light leading-relaxed text-ink/70 mb-4", children: newsletterBlurb }),
61
+ /* @__PURE__ */ jsx("p", { className: FOOTER_NEWSLETTER_BLURB, children: newsletterBlurb }),
60
62
  newsletter
61
63
  ] })
62
64
  ] }),
63
- (copyright !== void 0 || version !== void 0) && /* @__PURE__ */ jsx("div", { className: "border-t border-ink/10 pt-8 text-[10px] font-mono text-ink/40", children: /* @__PURE__ */ jsxs("p", { children: [
65
+ (copyright !== void 0 || version !== void 0) && /* @__PURE__ */ jsx("div", { className: FOOTER_COPYRIGHT, children: /* @__PURE__ */ jsxs("p", { children: [
64
66
  copyright,
65
67
  version && /* @__PURE__ */ jsxs(Fragment, { children: [
66
68
  copyright !== void 0 && " ",
67
- /* @__PURE__ */ jsx("a", { href: commitHref, className: "text-ink/30", children: version })
69
+ /* @__PURE__ */ jsx("a", { href: commitHref, className: FOOTER_VERSION, children: version })
68
70
  ] })
69
71
  ] }) })
70
72
  ] })
@@ -75,11 +77,11 @@ function FooterLockup({
75
77
  mark,
76
78
  tagline
77
79
  }) {
78
- return /* @__PURE__ */ jsxs("div", { "data-slot": "footer-lockup", className: "flex items-center gap-3 mb-6", children: [
80
+ return /* @__PURE__ */ jsxs("div", { "data-slot": "footer-lockup", className: FOOTER_LOCKUP, children: [
79
81
  mark,
80
- (brand !== void 0 || tagline !== void 0) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
81
- brand !== void 0 && /* @__PURE__ */ jsx("span", { className: "font-serif font-bold text-base tracking-wider text-ink", children: brand }),
82
- tagline !== void 0 && /* @__PURE__ */ jsx("span", { className: "text-[8px] font-mono tracking-[0.3em] text-primary-ink uppercase", children: tagline })
82
+ (brand !== void 0 || tagline !== void 0) && /* @__PURE__ */ jsxs("div", { className: FOOTER_LOCKUP_TEXT, children: [
83
+ brand !== void 0 && /* @__PURE__ */ jsx("span", { className: FOOTER_BRAND, children: brand }),
84
+ tagline !== void 0 && /* @__PURE__ */ jsx("span", { className: FOOTER_TAGLINE, children: tagline })
83
85
  ] })
84
86
  ] });
85
87
  }