@evinvest/uikit 0.32.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 (288) hide show
  1. package/README.md +21 -10
  2. package/dist/components/atomic/accordion.js +2 -1
  3. package/dist/components/atomic/accordion.js.map +1 -1
  4. package/dist/components/atomic/alert.js +4 -4
  5. package/dist/components/atomic/alert.js.map +1 -1
  6. package/dist/components/atomic/badge.js +4 -3
  7. package/dist/components/atomic/badge.js.map +1 -1
  8. package/dist/components/atomic/breadcrumb.js +7 -9
  9. package/dist/components/atomic/breadcrumb.js.map +1 -1
  10. package/dist/components/atomic/button.js +4 -3
  11. package/dist/components/atomic/button.js.map +1 -1
  12. package/dist/components/atomic/calendar.js +10 -25
  13. package/dist/components/atomic/calendar.js.map +1 -1
  14. package/dist/components/atomic/checkbox.js +2 -1
  15. package/dist/components/atomic/checkbox.js.map +1 -1
  16. package/dist/components/atomic/command.js +5 -20
  17. package/dist/components/atomic/command.js.map +1 -1
  18. package/dist/components/atomic/context-menu.js +6 -13
  19. package/dist/components/atomic/context-menu.js.map +1 -1
  20. package/dist/components/atomic/dialog.js +4 -2
  21. package/dist/components/atomic/dialog.js.map +1 -1
  22. package/dist/components/atomic/dropdown-menu.js +6 -14
  23. package/dist/components/atomic/dropdown-menu.js.map +1 -1
  24. package/dist/components/atomic/hover-card.js.map +1 -1
  25. package/dist/components/atomic/info-tip.js +8 -9
  26. package/dist/components/atomic/info-tip.js.map +1 -1
  27. package/dist/components/atomic/input-otp.js +2 -1
  28. package/dist/components/atomic/input-otp.js.map +1 -1
  29. package/dist/components/atomic/key-value.js +5 -4
  30. package/dist/components/atomic/key-value.js.map +1 -1
  31. package/dist/components/atomic/menubar.js +7 -18
  32. package/dist/components/atomic/menubar.js.map +1 -1
  33. package/dist/components/atomic/native-select.js +1 -1
  34. package/dist/components/atomic/native-select.js.map +1 -1
  35. package/dist/components/atomic/navigation-menu.js +6 -14
  36. package/dist/components/atomic/navigation-menu.js.map +1 -1
  37. package/dist/components/atomic/pagination.js +18 -19
  38. package/dist/components/atomic/pagination.js.map +1 -1
  39. package/dist/components/atomic/popover.js.map +1 -1
  40. package/dist/components/atomic/radio-group.js +5 -4
  41. package/dist/components/atomic/radio-group.js.map +1 -1
  42. package/dist/components/atomic/section-descriptor.js +5 -8
  43. package/dist/components/atomic/section-descriptor.js.map +1 -1
  44. package/dist/components/atomic/select-listbox.js +2 -2
  45. package/dist/components/atomic/select-listbox.js.map +1 -1
  46. package/dist/components/atomic/select.js +5 -13
  47. package/dist/components/atomic/select.js.map +1 -1
  48. package/dist/components/atomic/sheet.js +4 -2
  49. package/dist/components/atomic/sheet.js.map +1 -1
  50. package/dist/components/atomic/sidebar.js +7 -26
  51. package/dist/components/atomic/sidebar.js.map +1 -1
  52. package/dist/components/atomic/slider.js.map +1 -1
  53. package/dist/components/atomic/sonner.js +20 -18
  54. package/dist/components/atomic/sonner.js.map +1 -1
  55. package/dist/components/atomic/spinner.js +6 -3
  56. package/dist/components/atomic/spinner.js.map +1 -1
  57. package/dist/components/atomic/tabs.js.map +1 -1
  58. package/dist/components/atomic/toggle-group.js +2 -2
  59. package/dist/components/atomic/toggle-group.js.map +1 -1
  60. package/dist/components/atomic/toggle.js +3 -6
  61. package/dist/components/atomic/toggle.js.map +1 -1
  62. package/dist/components/atomic/tooltip.js.map +1 -1
  63. package/dist/components/derived/carousel.js +6 -6
  64. package/dist/components/derived/carousel.js.map +1 -1
  65. package/dist/components/derived/command-palette.js +8 -7
  66. package/dist/components/derived/command-palette.js.map +1 -1
  67. package/dist/components/derived/confirm-dialog.js +8 -13
  68. package/dist/components/derived/confirm-dialog.js.map +1 -1
  69. package/dist/components/derived/date-time-picker.js +10 -14
  70. package/dist/components/derived/date-time-picker.js.map +1 -1
  71. package/dist/components/derived/field.js.map +1 -1
  72. package/dist/components/derived/form.js +0 -1
  73. package/dist/components/derived/form.js.map +1 -1
  74. package/dist/components/derived/icon-button.js.map +1 -1
  75. package/dist/components/derived/item.js +0 -1
  76. package/dist/components/derived/item.js.map +1 -1
  77. package/dist/components/derived/popover-form.js +4 -3
  78. package/dist/components/derived/popover-form.js.map +1 -1
  79. package/dist/components/derived/settings.js +4 -4
  80. package/dist/components/derived/settings.js.map +1 -1
  81. package/dist/components/shell/account-menu-profile.js +1 -1
  82. package/dist/components/shell/account-menu-profile.js.map +1 -1
  83. package/dist/components/shell/account-settings-dialog.js +3 -2
  84. package/dist/components/shell/account-settings-dialog.js.map +1 -1
  85. package/dist/components/shell/aside.js +6 -4
  86. package/dist/components/shell/aside.js.map +1 -1
  87. package/dist/components/shell/auth-wall.js +3 -5
  88. package/dist/components/shell/auth-wall.js.map +1 -1
  89. package/dist/components/shell/bottom-tab-bar.js +3 -3
  90. package/dist/components/shell/bottom-tab-bar.js.map +1 -1
  91. package/dist/components/shell/chat-composer.js +9 -7
  92. package/dist/components/shell/chat-composer.js.map +1 -1
  93. package/dist/components/shell/chat-message.js.map +1 -1
  94. package/dist/components/shell/chat-typing.js +2 -1
  95. package/dist/components/shell/chat-typing.js.map +1 -1
  96. package/dist/components/shell/footer.js +26 -24
  97. package/dist/components/shell/footer.js.map +1 -1
  98. package/dist/components/shell/header-controls.js +17 -15
  99. package/dist/components/shell/header-controls.js.map +1 -1
  100. package/dist/components/shell/hotbar.js +158 -0
  101. package/dist/components/shell/hotbar.js.map +1 -0
  102. package/dist/components/shell/logo.js +3 -2
  103. package/dist/components/shell/logo.js.map +1 -1
  104. package/dist/components/shell/mobile-app-bar.js +4 -4
  105. package/dist/components/shell/mobile-app-bar.js.map +1 -1
  106. package/dist/components/shell/nav-collapse.js +6 -5
  107. package/dist/components/shell/nav-collapse.js.map +1 -1
  108. package/dist/components/shell/resource-error.js +2 -2
  109. package/dist/components/shell/resource-error.js.map +1 -1
  110. package/dist/components/shell/section-nav.js +3 -3
  111. package/dist/components/shell/section-nav.js.map +1 -1
  112. package/dist/components/shell/shell-icons.js +7 -22
  113. package/dist/components/shell/shell-icons.js.map +1 -1
  114. package/dist/components/shell/shell-nav.js +4 -4
  115. package/dist/components/shell/shell-nav.js.map +1 -1
  116. package/dist/components/shell/smart-header.js.map +1 -1
  117. package/dist/components/shell/status-screen.js +35 -35
  118. package/dist/components/shell/status-screen.js.map +1 -1
  119. package/dist/components/shell/system-banner.js +6 -6
  120. package/dist/components/shell/system-banner.js.map +1 -1
  121. package/dist/components/shell/workspace-tab.js +2 -1
  122. package/dist/components/shell/workspace-tab.js.map +1 -1
  123. package/dist/generated/accent.js +10 -10
  124. package/dist/generated/accent.js.map +1 -1
  125. package/dist/generated/accordion.js +6 -2
  126. package/dist/generated/accordion.js.map +1 -1
  127. package/dist/generated/account-list.js +4 -4
  128. package/dist/generated/account-list.js.map +1 -1
  129. package/dist/generated/account-settings-dialog.js +6 -2
  130. package/dist/generated/account-settings-dialog.js.map +1 -1
  131. package/dist/generated/alert-dialog.js +1 -1
  132. package/dist/generated/alert-dialog.js.map +1 -1
  133. package/dist/generated/alert.js +3 -10
  134. package/dist/generated/alert.js.map +1 -1
  135. package/dist/generated/aside.js +7 -0
  136. package/dist/generated/aside.js.map +1 -1
  137. package/dist/generated/badge.js +2 -11
  138. package/dist/generated/badge.js.map +1 -1
  139. package/dist/generated/band.js +10 -10
  140. package/dist/generated/band.js.map +1 -1
  141. package/dist/generated/breadcrumb.js +1 -1
  142. package/dist/generated/breadcrumb.js.map +1 -1
  143. package/dist/generated/button-group.js +3 -3
  144. package/dist/generated/button-group.js.map +1 -1
  145. package/dist/generated/button.js +4 -20
  146. package/dist/generated/button.js.map +1 -1
  147. package/dist/generated/calendar.js +5 -5
  148. package/dist/generated/calendar.js.map +1 -1
  149. package/dist/generated/card.js +1 -1
  150. package/dist/generated/card.js.map +1 -1
  151. package/dist/generated/carousel.js +1 -1
  152. package/dist/generated/carousel.js.map +1 -1
  153. package/dist/generated/chat-composer.js +9 -2
  154. package/dist/generated/chat-composer.js.map +1 -1
  155. package/dist/generated/chat-message.js +25 -19
  156. package/dist/generated/chat-message.js.map +1 -1
  157. package/dist/generated/checkbox.js +1 -1
  158. package/dist/generated/checkbox.js.map +1 -1
  159. package/dist/generated/command-palette.js +10 -1
  160. package/dist/generated/command-palette.js.map +1 -1
  161. package/dist/generated/command.js +8 -6
  162. package/dist/generated/command.js.map +1 -1
  163. package/dist/generated/confirm-dialog.js +8 -8
  164. package/dist/generated/confirm-dialog.js.map +1 -1
  165. package/dist/generated/context-menu.js +7 -5
  166. package/dist/generated/context-menu.js.map +1 -1
  167. package/dist/generated/copy.js +97 -0
  168. package/dist/generated/copy.js.map +1 -0
  169. package/dist/generated/date-time-picker.js +10 -0
  170. package/dist/generated/date-time-picker.js.map +1 -1
  171. package/dist/generated/dialog.js +2 -2
  172. package/dist/generated/dialog.js.map +1 -1
  173. package/dist/generated/drawer.js +6 -6
  174. package/dist/generated/drawer.js.map +1 -1
  175. package/dist/generated/dropdown-menu.js +7 -5
  176. package/dist/generated/dropdown-menu.js.map +1 -1
  177. package/dist/generated/empty.js +5 -5
  178. package/dist/generated/empty.js.map +1 -1
  179. package/dist/generated/field.js +9 -7
  180. package/dist/generated/field.js.map +1 -1
  181. package/dist/generated/footer.js +45 -0
  182. package/dist/generated/footer.js.map +1 -0
  183. package/dist/generated/header-controls.js +5 -10
  184. package/dist/generated/header-controls.js.map +1 -1
  185. package/dist/generated/hover-card.js +1 -1
  186. package/dist/generated/hover-card.js.map +1 -1
  187. package/dist/generated/icon-button.js +4 -2
  188. package/dist/generated/icon-button.js.map +1 -1
  189. package/dist/generated/icons.js +36 -0
  190. package/dist/generated/icons.js.map +1 -0
  191. package/dist/generated/info-tip.js +5 -0
  192. package/dist/generated/info-tip.js.map +1 -0
  193. package/dist/generated/input-group.js +10 -10
  194. package/dist/generated/input-group.js.map +1 -1
  195. package/dist/generated/input-otp.js +2 -2
  196. package/dist/generated/input-otp.js.map +1 -1
  197. package/dist/generated/input.js +4 -4
  198. package/dist/generated/input.js.map +1 -1
  199. package/dist/generated/item.js +11 -11
  200. package/dist/generated/item.js.map +1 -1
  201. package/dist/generated/kbd.js +1 -1
  202. package/dist/generated/kbd.js.map +1 -1
  203. package/dist/generated/key-value.js +7 -1
  204. package/dist/generated/key-value.js.map +1 -1
  205. package/dist/generated/label.js +1 -1
  206. package/dist/generated/label.js.map +1 -1
  207. package/dist/generated/logo.js +9 -0
  208. package/dist/generated/logo.js.map +1 -0
  209. package/dist/generated/menu.js +7 -0
  210. package/dist/generated/menu.js.map +1 -0
  211. package/dist/generated/menubar.js +10 -8
  212. package/dist/generated/menubar.js.map +1 -1
  213. package/dist/generated/navigation-menu.js +11 -5
  214. package/dist/generated/navigation-menu.js.map +1 -1
  215. package/dist/generated/orientation.js +5 -0
  216. package/dist/generated/orientation.js.map +1 -0
  217. package/dist/generated/pagination.js +15 -0
  218. package/dist/generated/pagination.js.map +1 -0
  219. package/dist/generated/popover-form.js +5 -0
  220. package/dist/generated/popover-form.js.map +1 -1
  221. package/dist/generated/popover.js +1 -1
  222. package/dist/generated/popover.js.map +1 -1
  223. package/dist/generated/primitives.js +7 -0
  224. package/dist/generated/primitives.js.map +1 -0
  225. package/dist/generated/radio-group.js +5 -1
  226. package/dist/generated/radio-group.js.map +1 -1
  227. package/dist/generated/section-descriptor.js +7 -0
  228. package/dist/generated/section-descriptor.js.map +1 -0
  229. package/dist/generated/select.js +16 -10
  230. package/dist/generated/select.js.map +1 -1
  231. package/dist/generated/settings.js +2 -7
  232. package/dist/generated/settings.js.map +1 -1
  233. package/dist/generated/sheet.js +1 -1
  234. package/dist/generated/sheet.js.map +1 -1
  235. package/dist/generated/sidebar.js +24 -12
  236. package/dist/generated/sidebar.js.map +1 -1
  237. package/dist/generated/size.js +12 -0
  238. package/dist/generated/size.js.map +1 -0
  239. package/dist/generated/skeleton.js +1 -1
  240. package/dist/generated/skeleton.js.map +1 -1
  241. package/dist/generated/slider.js +2 -2
  242. package/dist/generated/slider.js.map +1 -1
  243. package/dist/generated/slot.js +5 -0
  244. package/dist/generated/slot.js.map +1 -0
  245. package/dist/generated/smart-header.js +2 -0
  246. package/dist/generated/smart-header.js.map +1 -1
  247. package/dist/generated/sonner.js +11 -13
  248. package/dist/generated/sonner.js.map +1 -1
  249. package/dist/generated/spinner.js +5 -0
  250. package/dist/generated/spinner.js.map +1 -0
  251. package/dist/generated/status-screen.js +27 -0
  252. package/dist/generated/status-screen.js.map +1 -0
  253. package/dist/generated/switch.js +2 -2
  254. package/dist/generated/switch.js.map +1 -1
  255. package/dist/generated/system-banner.js +6 -16
  256. package/dist/generated/system-banner.js.map +1 -1
  257. package/dist/generated/table.js +9 -9
  258. package/dist/generated/table.js.map +1 -1
  259. package/dist/generated/tabs.js +2 -2
  260. package/dist/generated/tabs.js.map +1 -1
  261. package/dist/generated/textarea.js +1 -1
  262. package/dist/generated/textarea.js.map +1 -1
  263. package/dist/generated/toggle-group.js +9 -0
  264. package/dist/generated/toggle-group.js.map +1 -0
  265. package/dist/generated/toggle.js +1 -9
  266. package/dist/generated/toggle.js.map +1 -1
  267. package/dist/generated/tone.js +12 -0
  268. package/dist/generated/tone.js.map +1 -0
  269. package/dist/generated/tooltip.js +1 -1
  270. package/dist/generated/tooltip.js.map +1 -1
  271. package/dist/generated/workspace-tab.js +3 -3
  272. package/dist/generated/workspace-tab.js.map +1 -1
  273. package/dist/icons/icon-shapes.js +10 -0
  274. package/dist/icons/icon-shapes.js.map +1 -0
  275. package/dist/icons/select-chevron.js +2 -1
  276. package/dist/icons/select-chevron.js.map +1 -1
  277. package/dist/icons/ui-icons.js +3 -57
  278. package/dist/icons/ui-icons.js.map +1 -1
  279. package/dist/index.d.ts +203 -155
  280. package/dist/index.js +1 -0
  281. package/dist/lib/cn.js +1 -0
  282. package/dist/lib/cn.js.map +1 -1
  283. package/dist/primitives/use-floating.js.map +1 -1
  284. package/dist/primitives/use-roving-focus.js.map +1 -1
  285. package/package.json +1 -1
  286. package/styles/ev.css +13 -76
  287. package/styles/theme.css +133 -66
  288. package/styles/tokens.css +157 -149
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/derived/item.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { Slot } from \"../../primitives/slot\";\nimport { Separator } from \"../atomic/separator\";\nimport {\n ITEM_ACTIONS,\n ITEM_BASE,\n ITEM_CONTENT,\n ITEM_DESCRIPTION,\n ITEM_FOOTER,\n ITEM_GROUP,\n ITEM_HEADER,\n ITEM_MEDIA_BASE,\n ITEM_SEPARATOR,\n ITEM_TITLE,\n itemMediaVariants,\n itemSizes,\n itemVariants,\n type ItemMediaVariant,\n type ItemSize,\n type ItemVariant,\n} from \"../../generated/item\";\n\nexport type { ItemMediaVariant, ItemSize, ItemVariant };\n\nexport function ItemGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n role=\"list\"\n data-slot=\"item-group\"\n className={cn(ITEM_GROUP, className)}\n {...props}\n />\n );\n}\n\nexport function ItemSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n data-slot=\"item-separator\"\n orientation=\"horizontal\"\n className={cn(ITEM_SEPARATOR, className)}\n {...props}\n />\n );\n}\n\nexport interface ItemProps extends React.ComponentProps<\"div\"> {\n variant?: ItemVariant;\n size?: ItemSize;\n asChild?: boolean;\n}\n\nexport function Item({\n className,\n variant = \"bare\",\n size = \"md\",\n asChild = false,\n ...props\n}: ItemProps) {\n const Comp = asChild ? Slot : \"div\";\n return (\n <Comp\n data-slot=\"item\"\n data-variant={variant}\n data-size={size}\n className={cn(ITEM_BASE, itemVariants[variant], itemSizes[size], className)}\n {...(props as Record<string, unknown>)}\n />\n );\n}\n\nexport interface ItemMediaProps extends React.ComponentProps<\"div\"> {\n variant?: ItemMediaVariant;\n}\n\nexport function ItemMedia({\n className,\n variant = \"bare\",\n ...props\n}: ItemMediaProps) {\n return (\n <div\n data-slot=\"item-media\"\n data-variant={variant}\n className={cn(ITEM_MEDIA_BASE, itemMediaVariants[variant], className)}\n {...props}\n />\n );\n}\n\nexport function ItemContent({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-content\"\n className={cn(ITEM_CONTENT, className)}\n {...props}\n />\n );\n}\n\nexport function ItemTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-title\"\n className={cn(ITEM_TITLE, className)}\n {...props}\n />\n );\n}\n\nexport function ItemDescription({\n className,\n ...props\n}: React.ComponentProps<\"p\">) {\n return (\n <p\n data-slot=\"item-description\"\n className={cn(ITEM_DESCRIPTION, className)}\n {...props}\n />\n );\n}\n\nexport function ItemActions({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-actions\"\n className={cn(ITEM_ACTIONS, className)}\n {...props}\n />\n );\n}\n\nexport function ItemHeader({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-header\"\n className={cn(ITEM_HEADER, className)}\n {...props}\n />\n );\n}\n\nexport function ItemFooter({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-footer\"\n className={cn(ITEM_FOOTER, className)}\n {...props}\n />\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/derived/item.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { Slot } from \"../../primitives/slot\";\nimport { Separator } from \"../atomic/separator\";\nimport {\n ITEM_ACTIONS,\n ITEM_BASE,\n ITEM_CONTENT,\n ITEM_DESCRIPTION,\n ITEM_FOOTER,\n ITEM_GROUP,\n ITEM_HEADER,\n ITEM_MEDIA_BASE,\n ITEM_SEPARATOR,\n ITEM_TITLE,\n itemMediaVariants,\n itemSizes,\n itemVariants,\n type ItemMediaVariant,\n type ItemSize,\n type ItemVariant,\n} from \"../../generated/item\";\n\nexport type { ItemMediaVariant, ItemSize, ItemVariant };\n\nexport function ItemGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n role=\"list\"\n data-slot=\"item-group\"\n className={cn(ITEM_GROUP, className)}\n {...props}\n />\n );\n}\n\nexport function ItemSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n orientation=\"horizontal\"\n className={cn(ITEM_SEPARATOR, className)}\n {...props}\n />\n );\n}\n\nexport interface ItemProps extends React.ComponentProps<\"div\"> {\n variant?: ItemVariant;\n size?: ItemSize;\n asChild?: boolean;\n}\n\nexport function Item({\n className,\n variant = \"bare\",\n size = \"md\",\n asChild = false,\n ...props\n}: ItemProps) {\n const Comp = asChild ? Slot : \"div\";\n return (\n <Comp\n data-slot=\"item\"\n data-variant={variant}\n data-size={size}\n className={cn(ITEM_BASE, itemVariants[variant], itemSizes[size], className)}\n {...(props as Record<string, unknown>)}\n />\n );\n}\n\nexport interface ItemMediaProps extends React.ComponentProps<\"div\"> {\n variant?: ItemMediaVariant;\n}\n\nexport function ItemMedia({\n className,\n variant = \"bare\",\n ...props\n}: ItemMediaProps) {\n return (\n <div\n data-slot=\"item-media\"\n data-variant={variant}\n className={cn(ITEM_MEDIA_BASE, itemMediaVariants[variant], className)}\n {...props}\n />\n );\n}\n\nexport function ItemContent({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-content\"\n className={cn(ITEM_CONTENT, className)}\n {...props}\n />\n );\n}\n\nexport function ItemTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-title\"\n className={cn(ITEM_TITLE, className)}\n {...props}\n />\n );\n}\n\nexport function ItemDescription({\n className,\n ...props\n}: React.ComponentProps<\"p\">) {\n return (\n <p\n data-slot=\"item-description\"\n className={cn(ITEM_DESCRIPTION, className)}\n {...props}\n />\n );\n}\n\nexport function ItemActions({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-actions\"\n className={cn(ITEM_ACTIONS, className)}\n {...props}\n />\n );\n}\n\nexport function ItemHeader({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-header\"\n className={cn(ITEM_HEADER, className)}\n {...props}\n />\n );\n}\n\nexport function ItemFooter({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-footer\"\n className={cn(ITEM_FOOTER, className)}\n {...props}\n />\n );\n}\n"],"mappings":"AA2BI;AA3BJ,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAC1B;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,OAIK;AAIA,SAAS,UAAU,EAAE,WAAW,GAAG,MAAM,GAAgC;AAC9E,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,WAAW,GAAG,YAAY,SAAS;AAAA,MAClC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA,GAAG;AACL,GAA2C;AACzC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAY;AAAA,MACZ,WAAW,GAAG,gBAAgB,SAAS;AAAA,MACtC,GAAG;AAAA;AAAA,EACN;AAEJ;AAQO,SAAS,KAAK;AAAA,EACnB;AAAA,EACA,UAAU;AAAA,EACV,OAAO;AAAA,EACP,UAAU;AAAA,EACV,GAAG;AACL,GAAc;AACZ,QAAM,OAAO,UAAU,OAAO;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,gBAAc;AAAA,MACd,aAAW;AAAA,MACX,WAAW,GAAG,WAAW,aAAa,OAAO,GAAG,UAAU,IAAI,GAAG,SAAS;AAAA,MACzE,GAAI;AAAA;AAAA,EACP;AAEJ;AAMO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA,UAAU;AAAA,EACV,GAAG;AACL,GAAmB;AACjB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,gBAAc;AAAA,MACd,WAAW,GAAG,iBAAiB,kBAAkB,OAAO,GAAG,SAAS;AAAA,MACnE,GAAG;AAAA;AAAA,EACN;AAEJ;AAEO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAAgC;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,cAAc,SAAS;AAAA,MACpC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEO,SAAS,UAAU,EAAE,WAAW,GAAG,MAAM,GAAgC;AAC9E,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,YAAY,SAAS;AAAA,MAClC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,GAAG;AACL,GAA8B;AAC5B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,kBAAkB,SAAS;AAAA,MACxC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAAgC;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,cAAc,SAAS;AAAA,MACpC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,GAAG;AACL,GAAgC;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,aAAa,SAAS;AAAA,MACnC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,GAAG;AACL,GAAgC;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,aAAa,SAAS;AAAA,MACnC,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
@@ -7,7 +7,8 @@ import {
7
7
  POPOVER_FORM_CONTENT,
8
8
  POPOVER_FORM_FIELDS,
9
9
  POPOVER_FORM_FORM,
10
- POPOVER_FORM_TITLE
10
+ POPOVER_FORM_TITLE,
11
+ POPOVER_FORM_LABELS
11
12
  } from "../../generated/popover-form.js";
12
13
  import { useControllableState } from "../../primitives/use-controllable-state.js";
13
14
  import { Button } from "../atomic/button.js";
@@ -46,8 +47,8 @@ function PopoverForm({
46
47
  /* @__PURE__ */ jsx("h3", { id: titleId, className: POPOVER_FORM_TITLE, children: title }),
47
48
  /* @__PURE__ */ jsx("div", { className: POPOVER_FORM_FIELDS, children }),
48
49
  /* @__PURE__ */ jsxs("div", { className: POPOVER_FORM_ACTIONS, children: [
49
- /* @__PURE__ */ jsx(Button, { type: "reset", variant: "ghost", size: "sm", children: labels.reset ?? "Reset" }),
50
- /* @__PURE__ */ jsx(Button, { type: "submit", variant: "primary", size: "sm", children: labels.submit ?? "Apply" })
50
+ /* @__PURE__ */ jsx(Button, { type: "reset", variant: "ghost", size: "sm", children: labels.reset ?? POPOVER_FORM_LABELS.reset }),
51
+ /* @__PURE__ */ jsx(Button, { type: "submit", variant: "primary", size: "sm", children: labels.submit ?? POPOVER_FORM_LABELS.submit })
51
52
  ] })
52
53
  ]
53
54
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/derived/popover-form.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport {\n POPOVER_FORM_ACTIONS,\n POPOVER_FORM_CONTENT,\n POPOVER_FORM_FIELDS,\n POPOVER_FORM_FORM,\n POPOVER_FORM_TITLE,\n} from \"../../generated/popover-form\";\nimport { useControllableState } from \"../../primitives/use-controllable-state\";\nimport { Button } from \"../atomic/button\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../atomic/popover\";\n\nexport interface PopoverFormLabels {\n submit?: string;\n reset?: string;\n}\n\nexport interface PopoverFormProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** The button that opens the form; wrapped with `asChild`, so pass one element. */\n trigger: React.ReactNode;\n title: React.ReactNode;\n /** The fields: `Field`s with an `Input`, `Select` or `Checkbox`. */\n children: React.ReactNode;\n /** Called on submit; the popover closes afterwards. */\n onSubmit?: (event: React.FormEvent<HTMLFormElement>) => void;\n /** Called when Reset is pressed; native fields are reset by the browser first. */\n onReset?: () => void;\n labels?: PopoverFormLabels;\n className?: string;\n}\n\n/** A filter-style form in a popover: a title, fields, Reset and Apply. */\nexport function PopoverForm({\n open,\n defaultOpen = false,\n onOpenChange,\n trigger,\n title,\n children,\n onSubmit,\n onReset,\n labels = {},\n className,\n}: PopoverFormProps) {\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n const titleId = React.useId();\n return (\n <Popover open={isOpen} onOpenChange={setOpen}>\n <PopoverTrigger asChild>{trigger}</PopoverTrigger>\n <PopoverContent align=\"start\" className={cn(POPOVER_FORM_CONTENT, className)} aria-labelledby={titleId} role=\"dialog\">\n <form\n className={POPOVER_FORM_FORM}\n onSubmit={(e) => {\n e.preventDefault();\n onSubmit?.(e);\n setOpen(false);\n }}\n onReset={() => onReset?.()}\n >\n <h3 id={titleId} className={POPOVER_FORM_TITLE}>\n {title}\n </h3>\n <div className={POPOVER_FORM_FIELDS}>{children}</div>\n <div className={POPOVER_FORM_ACTIONS}>\n <Button type=\"reset\" variant=\"ghost\" size=\"sm\">\n {labels.reset ?? \"Reset\"}\n </Button>\n <Button type=\"submit\" variant=\"primary\" size=\"sm\">\n {labels.submit ?? \"Apply\"}\n </Button>\n </div>\n </form>\n </PopoverContent>\n </Popover>\n );\n}\n"],"mappings":";AA0DM,cAeI,YAfJ;AAxDN,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,4BAA4B;AACrC,SAAS,cAAc;AACvB,SAAS,SAAS,gBAAgB,sBAAsB;AAyBjD,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,CAAC;AAAA,EACV;AACF,GAAqB;AACnB,QAAM,CAAC,QAAQ,OAAO,IAAI,qBAA8B;AAAA,IACtD,GAAI,SAAS,SAAY,EAAE,OAAO,KAAK,IAAI,CAAC;AAAA,IAC5C,cAAc;AAAA,IACd,GAAI,eAAe,EAAE,UAAU,aAAa,IAAI,CAAC;AAAA,EACnD,CAAC;AACD,QAAM,UAAU,MAAM,MAAM;AAC5B,SACE,qBAAC,WAAQ,MAAM,QAAQ,cAAc,SACnC;AAAA,wBAAC,kBAAe,SAAO,MAAE,mBAAQ;AAAA,IACjC,oBAAC,kBAAe,OAAM,SAAQ,WAAW,GAAG,sBAAsB,SAAS,GAAG,mBAAiB,SAAS,MAAK,UAC3G;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,QACX,UAAU,CAAC,MAAM;AACf,YAAE,eAAe;AACjB,qBAAW,CAAC;AACZ,kBAAQ,KAAK;AAAA,QACf;AAAA,QACA,SAAS,MAAM,UAAU;AAAA,QAEzB;AAAA,8BAAC,QAAG,IAAI,SAAS,WAAW,oBACzB,iBACH;AAAA,UACA,oBAAC,SAAI,WAAW,qBAAsB,UAAS;AAAA,UAC/C,qBAAC,SAAI,WAAW,sBACd;AAAA,gCAAC,UAAO,MAAK,SAAQ,SAAQ,SAAQ,MAAK,MACvC,iBAAO,SAAS,SACnB;AAAA,YACA,oBAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAC1C,iBAAO,UAAU,SACpB;AAAA,aACF;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/derived/popover-form.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport {\n POPOVER_FORM_ACTIONS,\n POPOVER_FORM_CONTENT,\n POPOVER_FORM_FIELDS,\n POPOVER_FORM_FORM,\n POPOVER_FORM_TITLE,\n POPOVER_FORM_LABELS,\n} from \"../../generated/popover-form\";\nimport { useControllableState } from \"../../primitives/use-controllable-state\";\nimport { Button } from \"../atomic/button\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../atomic/popover\";\n\nexport interface PopoverFormLabels {\n submit?: string;\n reset?: string;\n}\n\nexport interface PopoverFormProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** The button that opens the form; wrapped with `asChild`, so pass one element. */\n trigger: React.ReactNode;\n title: React.ReactNode;\n /** The fields: `Field`s with an `Input`, `Select` or `Checkbox`. */\n children: React.ReactNode;\n /** Called on submit; the popover closes afterwards. */\n onSubmit?: (event: React.FormEvent<HTMLFormElement>) => void;\n /** Called when Reset is pressed; native fields are reset by the browser first. */\n onReset?: () => void;\n labels?: PopoverFormLabels;\n className?: string;\n}\n\n/** A filter-style form in a popover: a title, fields, Reset and Apply. */\nexport function PopoverForm({\n open,\n defaultOpen = false,\n onOpenChange,\n trigger,\n title,\n children,\n onSubmit,\n onReset,\n labels = {},\n className,\n}: PopoverFormProps) {\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n const titleId = React.useId();\n return (\n <Popover open={isOpen} onOpenChange={setOpen}>\n <PopoverTrigger asChild>{trigger}</PopoverTrigger>\n <PopoverContent align=\"start\" className={cn(POPOVER_FORM_CONTENT, className)} aria-labelledby={titleId} role=\"dialog\">\n <form\n className={POPOVER_FORM_FORM}\n onSubmit={(e) => {\n e.preventDefault();\n onSubmit?.(e);\n setOpen(false);\n }}\n onReset={() => onReset?.()}\n >\n <h3 id={titleId} className={POPOVER_FORM_TITLE}>\n {title}\n </h3>\n <div className={POPOVER_FORM_FIELDS}>{children}</div>\n <div className={POPOVER_FORM_ACTIONS}>\n <Button type=\"reset\" variant=\"ghost\" size=\"sm\">\n {labels.reset ?? POPOVER_FORM_LABELS.reset}\n </Button>\n <Button type=\"submit\" variant=\"primary\" size=\"sm\">\n {labels.submit ?? POPOVER_FORM_LABELS.submit}\n </Button>\n </div>\n </form>\n </PopoverContent>\n </Popover>\n );\n}\n"],"mappings":";AA2DM,cAeI,YAfJ;AAzDN,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,4BAA4B;AACrC,SAAS,cAAc;AACvB,SAAS,SAAS,gBAAgB,sBAAsB;AAyBjD,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,CAAC;AAAA,EACV;AACF,GAAqB;AACnB,QAAM,CAAC,QAAQ,OAAO,IAAI,qBAA8B;AAAA,IACtD,GAAI,SAAS,SAAY,EAAE,OAAO,KAAK,IAAI,CAAC;AAAA,IAC5C,cAAc;AAAA,IACd,GAAI,eAAe,EAAE,UAAU,aAAa,IAAI,CAAC;AAAA,EACnD,CAAC;AACD,QAAM,UAAU,MAAM,MAAM;AAC5B,SACE,qBAAC,WAAQ,MAAM,QAAQ,cAAc,SACnC;AAAA,wBAAC,kBAAe,SAAO,MAAE,mBAAQ;AAAA,IACjC,oBAAC,kBAAe,OAAM,SAAQ,WAAW,GAAG,sBAAsB,SAAS,GAAG,mBAAiB,SAAS,MAAK,UAC3G;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,QACX,UAAU,CAAC,MAAM;AACf,YAAE,eAAe;AACjB,qBAAW,CAAC;AACZ,kBAAQ,KAAK;AAAA,QACf;AAAA,QACA,SAAS,MAAM,UAAU;AAAA,QAEzB;AAAA,8BAAC,QAAG,IAAI,SAAS,WAAW,oBACzB,iBACH;AAAA,UACA,oBAAC,SAAI,WAAW,qBAAsB,UAAS;AAAA,UAC/C,qBAAC,SAAI,WAAW,sBACd;AAAA,gCAAC,UAAO,MAAK,SAAQ,SAAQ,SAAQ,MAAK,MACvC,iBAAO,SAAS,oBAAoB,OACvC;AAAA,YACA,oBAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAC1C,iBAAO,UAAU,oBAAoB,QACxC;AAAA,aACF;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;","names":[]}
@@ -16,9 +16,9 @@ import {
16
16
  SETTINGS_SECTION_HEADER,
17
17
  SETTINGS_SECTION_HEADER_FLUSH,
18
18
  SETTINGS_SECTION_HEADING,
19
- SETTINGS_SECTION_TITLE,
20
- settingsSectionToneClasses
19
+ SETTINGS_SECTION_TITLE
21
20
  } from "../../generated/settings.js";
21
+ import { toneClasses } from "../../generated/tone.js";
22
22
  import { FormRow } from "../atomic/form-row.js";
23
23
  function SettingsLayout({ nav, className, children, ...props }) {
24
24
  return /* @__PURE__ */ jsxs(
@@ -41,7 +41,7 @@ function SettingsSection({
41
41
  title,
42
42
  description,
43
43
  action,
44
- tone = "default",
44
+ tone = "neutral",
45
45
  flush = false,
46
46
  className,
47
47
  children,
@@ -56,7 +56,7 @@ function SettingsSection({
56
56
  "aria-labelledby": headingId,
57
57
  className: cn(
58
58
  SETTINGS_SECTION_BASE,
59
- settingsSectionToneClasses[tone],
59
+ toneClasses[tone],
60
60
  className
61
61
  ),
62
62
  ...props,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/derived/settings.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport {\n SETTINGS_LAYOUT,\n SETTINGS_MAIN,\n SETTINGS_NAV,\n SETTINGS_ROW_INLINE,\n SETTINGS_SECTION_ACTION,\n SETTINGS_SECTION_BASE,\n SETTINGS_SECTION_BODY,\n SETTINGS_SECTION_BODY_FLUSH,\n SETTINGS_SECTION_BODY_PADDED,\n SETTINGS_SECTION_DESCRIPTION,\n SETTINGS_SECTION_HEADER,\n SETTINGS_SECTION_HEADER_FLUSH,\n SETTINGS_SECTION_HEADING,\n SETTINGS_SECTION_TITLE,\n settingsSectionToneClasses,\n type SettingsSectionTone,\n} from \"../../generated/settings\";\nimport { FormRow, type FormRowProps } from \"../atomic/form-row\";\n\nexport interface SettingsLayoutProps extends Omit<React.ComponentProps<\"div\">, \"title\"> {\n /** The section rail (`SectionNav`), 256 wide from `lg` up and on top below it. */\n nav: React.ReactNode;\n}\n\n/**\n * Rail on the left, cards in the main column; centres a 1408 px measure. The column is a\n * div: `AppShell` already renders the page's `<main>`.\n */\nexport function SettingsLayout({ nav, className, children, ...props }: SettingsLayoutProps) {\n return (\n <div\n data-slot=\"settings-layout\"\n className={cn(\n SETTINGS_LAYOUT,\n className,\n )}\n {...props}\n >\n <div data-slot=\"settings-nav\" className={SETTINGS_NAV}>\n {nav}\n </div>\n <div data-slot=\"settings-main\" className={SETTINGS_MAIN}>\n {children}\n </div>\n </div>\n );\n}\n\nexport interface SettingsSectionProps extends Omit<React.ComponentProps<\"section\">, \"title\"> {\n title: React.ReactNode;\n description?: React.ReactNode;\n /** Top-right control, e.g. a \"Create team\" button. */\n action?: React.ReactNode;\n /** `danger` draws the destructive-zone edge. */\n tone?: SettingsSectionTone;\n /** Rows run edge to edge with their hairlines; otherwise the body is padded. */\n flush?: boolean;\n}\n\n/** A settings card: title, a line saying what it is for, then the body. */\nexport function SettingsSection({\n title,\n description,\n action,\n tone = \"default\",\n flush = false,\n className,\n children,\n ...props\n}: SettingsSectionProps) {\n const headingId = React.useId();\n return (\n <section\n data-slot=\"settings-section\"\n data-tone={tone}\n aria-labelledby={headingId}\n className={cn(\n SETTINGS_SECTION_BASE,\n settingsSectionToneClasses[tone],\n className,\n )}\n {...props}\n >\n <header className={cn(SETTINGS_SECTION_HEADER, flush && SETTINGS_SECTION_HEADER_FLUSH)}>\n <div className={SETTINGS_SECTION_HEADING}>\n <h3 id={headingId} className={SETTINGS_SECTION_TITLE}>\n {title}\n </h3>\n {description != null && <p className={SETTINGS_SECTION_DESCRIPTION}>{description}</p>}\n </div>\n {action != null && <div className={SETTINGS_SECTION_ACTION}>{action}</div>}\n </header>\n {children != null && (\n <div className={cn(SETTINGS_SECTION_BODY, flush ? SETTINGS_SECTION_BODY_FLUSH : SETTINGS_SECTION_BODY_PADDED)}>\n {children}\n </div>\n )}\n </section>\n );\n}\n\nexport interface SettingsRowProps extends FormRowProps {\n /** Keeps label and control on one line at every width, control at the end: for a switch or a button. */\n inline?: boolean;\n}\n\n/** A `FormRow` for settings; `inline` suits toggles. */\nexport function SettingsRow({ inline = false, className, ...props }: SettingsRowProps) {\n return (\n <FormRow\n data-inline={inline}\n className={cn(\n inline && SETTINGS_ROW_INLINE,\n className,\n )}\n {...props}\n />\n );\n}\n"],"mappings":";AAmCI,SAQE,KARF;AAjCJ,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,eAAkC;AAWpC,SAAS,eAAe,EAAE,KAAK,WAAW,UAAU,GAAG,MAAM,GAAwB;AAC1F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ;AAAA,4BAAC,SAAI,aAAU,gBAAe,WAAW,cACtC,eACH;AAAA,QACA,oBAAC,SAAI,aAAU,iBAAgB,WAAW,eACvC,UACH;AAAA;AAAA;AAAA,EACF;AAEJ;AAcO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAyB;AACvB,QAAM,YAAY,MAAM,MAAM;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,aAAW;AAAA,MACX,mBAAiB;AAAA,MACjB,WAAW;AAAA,QACT;AAAA,QACA,2BAA2B,IAAI;AAAA,QAC/B;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ;AAAA,6BAAC,YAAO,WAAW,GAAG,yBAAyB,SAAS,6BAA6B,GACnF;AAAA,+BAAC,SAAI,WAAW,0BACd;AAAA,gCAAC,QAAG,IAAI,WAAW,WAAW,wBAC3B,iBACH;AAAA,YACC,eAAe,QAAQ,oBAAC,OAAE,WAAW,8BAA+B,uBAAY;AAAA,aACnF;AAAA,UACC,UAAU,QAAQ,oBAAC,SAAI,WAAW,yBAA0B,kBAAO;AAAA,WACtE;AAAA,QACC,YAAY,QACX,oBAAC,SAAI,WAAW,GAAG,uBAAuB,QAAQ,8BAA8B,4BAA4B,GACzG,UACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAQO,SAAS,YAAY,EAAE,SAAS,OAAO,WAAW,GAAG,MAAM,GAAqB;AACrF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAa;AAAA,MACb,WAAW;AAAA,QACT,UAAU;AAAA,QACV;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/derived/settings.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport {\n SETTINGS_LAYOUT,\n SETTINGS_MAIN,\n SETTINGS_NAV,\n SETTINGS_ROW_INLINE,\n SETTINGS_SECTION_ACTION,\n SETTINGS_SECTION_BASE,\n SETTINGS_SECTION_BODY,\n SETTINGS_SECTION_BODY_FLUSH,\n SETTINGS_SECTION_BODY_PADDED,\n SETTINGS_SECTION_DESCRIPTION,\n SETTINGS_SECTION_HEADER,\n SETTINGS_SECTION_HEADER_FLUSH,\n SETTINGS_SECTION_HEADING,\n SETTINGS_SECTION_TITLE,\n} from \"../../generated/settings\";\nimport { toneClasses, type Tone } from \"../../generated/tone\";\nimport { FormRow, type FormRowProps } from \"../atomic/form-row\";\n\nexport interface SettingsLayoutProps extends Omit<React.ComponentProps<\"div\">, \"title\"> {\n /** The section rail (`SectionNav`), 256 wide from `lg` up and on top below it. */\n nav: React.ReactNode;\n}\n\n/**\n * Rail on the left, cards in the main column; centres a 1408 px measure. The column is a\n * div: `AppShell` already renders the page's `<main>`.\n */\nexport function SettingsLayout({ nav, className, children, ...props }: SettingsLayoutProps) {\n return (\n <div\n data-slot=\"settings-layout\"\n className={cn(\n SETTINGS_LAYOUT,\n className,\n )}\n {...props}\n >\n <div data-slot=\"settings-nav\" className={SETTINGS_NAV}>\n {nav}\n </div>\n <div data-slot=\"settings-main\" className={SETTINGS_MAIN}>\n {children}\n </div>\n </div>\n );\n}\n\nexport interface SettingsSectionProps extends Omit<React.ComponentProps<\"section\">, \"title\"> {\n title: React.ReactNode;\n description?: React.ReactNode;\n /** Top-right control, e.g. a \"Create team\" button. */\n action?: React.ReactNode;\n /** `error` draws the destructive-zone edge. */\n tone?: Tone;\n /** Rows run edge to edge with their hairlines; otherwise the body is padded. */\n flush?: boolean;\n}\n\n/** A settings card: title, a line saying what it is for, then the body. */\nexport function SettingsSection({\n title,\n description,\n action,\n tone = \"neutral\",\n flush = false,\n className,\n children,\n ...props\n}: SettingsSectionProps) {\n const headingId = React.useId();\n return (\n <section\n data-slot=\"settings-section\"\n data-tone={tone}\n aria-labelledby={headingId}\n className={cn(\n SETTINGS_SECTION_BASE,\n toneClasses[tone],\n className,\n )}\n {...props}\n >\n <header className={cn(SETTINGS_SECTION_HEADER, flush && SETTINGS_SECTION_HEADER_FLUSH)}>\n <div className={SETTINGS_SECTION_HEADING}>\n <h3 id={headingId} className={SETTINGS_SECTION_TITLE}>\n {title}\n </h3>\n {description != null && <p className={SETTINGS_SECTION_DESCRIPTION}>{description}</p>}\n </div>\n {action != null && <div className={SETTINGS_SECTION_ACTION}>{action}</div>}\n </header>\n {children != null && (\n <div className={cn(SETTINGS_SECTION_BODY, flush ? SETTINGS_SECTION_BODY_FLUSH : SETTINGS_SECTION_BODY_PADDED)}>\n {children}\n </div>\n )}\n </section>\n );\n}\n\nexport interface SettingsRowProps extends FormRowProps {\n /** Keeps label and control on one line at every width, control at the end: for a switch or a button. */\n inline?: boolean;\n}\n\n/** A `FormRow` for settings; `inline` suits toggles. */\nexport function SettingsRow({ inline = false, className, ...props }: SettingsRowProps) {\n return (\n <FormRow\n data-inline={inline}\n className={cn(\n inline && SETTINGS_ROW_INLINE,\n className,\n )}\n {...props}\n />\n );\n}\n"],"mappings":";AAkCI,SAQE,KARF;AAhCJ,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,mBAA8B;AACvC,SAAS,eAAkC;AAWpC,SAAS,eAAe,EAAE,KAAK,WAAW,UAAU,GAAG,MAAM,GAAwB;AAC1F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ;AAAA,4BAAC,SAAI,aAAU,gBAAe,WAAW,cACtC,eACH;AAAA,QACA,oBAAC,SAAI,aAAU,iBAAgB,WAAW,eACvC,UACH;AAAA;AAAA;AAAA,EACF;AAEJ;AAcO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAyB;AACvB,QAAM,YAAY,MAAM,MAAM;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,aAAW;AAAA,MACX,mBAAiB;AAAA,MACjB,WAAW;AAAA,QACT;AAAA,QACA,YAAY,IAAI;AAAA,QAChB;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ;AAAA,6BAAC,YAAO,WAAW,GAAG,yBAAyB,SAAS,6BAA6B,GACnF;AAAA,+BAAC,SAAI,WAAW,0BACd;AAAA,gCAAC,QAAG,IAAI,WAAW,WAAW,wBAC3B,iBACH;AAAA,YACC,eAAe,QAAQ,oBAAC,OAAE,WAAW,8BAA+B,uBAAY;AAAA,aACnF;AAAA,UACC,UAAU,QAAQ,oBAAC,SAAI,WAAW,yBAA0B,kBAAO;AAAA,WACtE;AAAA,QACC,YAAY,QACX,oBAAC,SAAI,WAAW,GAAG,uBAAuB,QAAQ,8BAA8B,4BAA4B,GACzG,UACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAQO,SAAS,YAAY,EAAE,SAAS,OAAO,WAAW,GAAG,MAAM,GAAqB;AACrF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAa;AAAA,MACb,WAAW;AAAA,QACT,UAAU;AAAA,QACV;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
@@ -44,7 +44,7 @@ function ProfileTabs({
44
44
  onClick: () => onChange(t.id),
45
45
  onKeyDown: (e) => move(e, i),
46
46
  className: cn(
47
- "-mb-px h-8 flex-1 border-b px-3 text-body font-medium outline-none focus-visible:ring-2 focus-visible:ring-ring",
47
+ "-mb-px h-(--control-h-sm) flex-1 border-b px-3 text-body font-medium outline-none focus-visible:ring-2 focus-visible:ring-ring",
48
48
  selected ? "border-primary text-ink" : "border-transparent text-ink-mid hover:text-ink"
49
49
  ),
50
50
  children: t.label
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/shell/account-menu-profile.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { Avatar, AvatarFallback } from \"../atomic/avatar\";\nimport { Badge } from \"../atomic/badge\";\nimport {\n DropdownMenuItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n} from \"../atomic/dropdown-menu\";\nimport { Switch } from \"../atomic/switch\";\nimport { UiIcon } from \"../../icons/ui-icons\";\n\nexport interface AccountMenuTab {\n id: string;\n label: React.ReactNode;\n /** Shown instead of the menu body when this tab is current; the first tab is always the menu itself. */\n content?: React.ReactNode;\n}\n\nexport interface AccountMenuProfile {\n /** Under the name on the profile card, e.g. \"Free\". */\n plan?: string;\n /** Makes the card a menu item that runs this and closes the menu, e.g. to open the account settings. */\n onOpenProfile?: () => void;\n tabs?: readonly AccountMenuTab[];\n /** Names the tab row for assistive tech. Default `\"Sections\"`. */\n tabsLabel?: string;\n /** Current tab id (controlled). */\n tab?: string;\n onTabChange?: (id: string) => void;\n /** A row with a short value badge on the right (\"EN\"); picking it runs `onSelect`. */\n language?: { label: string; value: string; onSelect?: () => void };\n /** A row with a switch; the menu closes after a toggle. */\n darkTheme?: { label: string; checked: boolean; onCheckedChange: (checked: boolean) => void };\n /** A submenu of radio options; the current one's label shows on the row. */\n colorTheme?: {\n label: string;\n value: string;\n options: readonly { id: string; label: string }[];\n onValueChange: (id: string) => void;\n };\n /** Glyphs for the rows, so the kit carries no icon set. */\n icons?: { language?: React.ReactNode; darkTheme?: React.ReactNode; colorTheme?: React.ReactNode };\n}\n\n/**\n * The tabs are `menuitemradio` items in a group, not a tablist: a menu may only\n * hold items, and this way the menu's own arrow-key roving reaches them.\n * Selecting one does not close the menu.\n */\nexport function ProfileTabs({\n tabs,\n value,\n onChange,\n label = \"Sections\",\n}: {\n tabs: readonly AccountMenuTab[];\n value: string;\n onChange: (id: string) => void;\n label?: string | undefined;\n}) {\n const move = (e: React.KeyboardEvent<HTMLButtonElement>, index: number) => {\n const step = e.key === \"ArrowRight\" ? 1 : e.key === \"ArrowLeft\" ? -1 : 0;\n if (step === 0) return;\n // Up and Down belong to the menu; Left and Right stay in the row.\n e.stopPropagation();\n e.preventDefault();\n const target = (index + step + tabs.length) % tabs.length;\n const next = tabs[target];\n if (!next) return;\n onChange(next.id);\n e.currentTarget.parentElement?.querySelectorAll<HTMLElement>('[role=\"menuitemradio\"]')[target]?.focus();\n };\n return (\n <div role=\"group\" aria-label={label} data-slot=\"account-menu-tabs\" className=\"flex border-b border-border-subtle\">\n {tabs.map((t, i) => {\n const selected = t.id === value;\n return (\n <button\n key={t.id}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n tabIndex={-1}\n onClick={() => onChange(t.id)}\n onKeyDown={(e) => move(e, i)}\n className={cn(\n \"-mb-px h-8 flex-1 border-b px-3 text-body font-medium outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n selected ? \"border-primary text-ink\" : \"border-transparent text-ink-mid hover:text-ink\",\n )}\n >\n {t.label}\n </button>\n );\n })}\n </div>\n );\n}\n\nexport function ProfileCard({\n name,\n plan,\n initials,\n onOpen,\n}: {\n name: string;\n plan?: string | undefined;\n initials: string;\n onOpen?: (() => void) | undefined;\n}) {\n const content = (\n <>\n <Avatar className=\"size-14 shrink-0 rounded-full\">\n <AvatarFallback className=\"font-serif text-h2 font-light text-ink\">{initials.slice(0, 1)}</AvatarFallback>\n </Avatar>\n <span className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <span className=\"truncate text-body font-medium text-ink\">{name}</span>\n {plan && <span className=\"text-caption text-ink-soft\">{plan}</span>}\n </span>\n {onOpen && <UiIcon name=\"chevron-right\" className=\"size-4 text-ink-soft\" />}\n </>\n );\n if (!onOpen) {\n return (\n <div data-slot=\"account-menu-card\" className=\"flex w-full items-center gap-2.5 p-2\">\n {content}\n </div>\n );\n }\n // A real menu item: it joins the arrow-key order and closes the menu, so a dialog opened from it is not left under the menu.\n return (\n <DropdownMenuItem data-slot=\"account-menu-card\" className=\"h-auto gap-2.5 p-2\" onClick={onOpen}>\n {content}\n </DropdownMenuItem>\n );\n}\n\nexport function ProfileSettingRows({ profile }: { profile: AccountMenuProfile }) {\n const { language, darkTheme, colorTheme, icons } = profile;\n if (!language && !darkTheme && !colorTheme) return null;\n const currentColor = colorTheme?.options.find((o) => o.id === colorTheme.value)?.label;\n return (\n <>\n <DropdownMenuSeparator />\n {language && (\n <DropdownMenuItem onClick={() => language.onSelect?.()}>\n {icons?.language}\n <span className=\"flex-1\">{language.label}</span>\n <Badge>{language.value}</Badge>\n </DropdownMenuItem>\n )}\n {darkTheme && (\n <DropdownMenuItem\n role=\"menuitemcheckbox\"\n aria-checked={darkTheme.checked}\n onClick={() => darkTheme.onCheckedChange(!darkTheme.checked)}\n >\n {icons?.darkTheme}\n <span className=\"flex-1\">{darkTheme.label}</span>\n {/* Presentational: the row is the control, so the switch stays out of the tab order. */}\n <Switch checked={darkTheme.checked} tabIndex={-1} aria-hidden className=\"pointer-events-none\" />\n </DropdownMenuItem>\n )}\n {colorTheme && (\n <DropdownMenuSub>\n <DropdownMenuSubTrigger>\n {icons?.colorTheme}\n <span className=\"flex-1\">{colorTheme.label}</span>\n {currentColor && <span className=\"text-body-s text-ink-soft\">{currentColor}</span>}\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent>\n <DropdownMenuRadioGroup value={colorTheme.value} onValueChange={colorTheme.onValueChange}>\n {colorTheme.options.map((o) => (\n <DropdownMenuRadioItem key={o.id} value={o.id}>\n {o.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n )}\n </>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/shell/account-menu-profile.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { Avatar, AvatarFallback } from \"../atomic/avatar\";\nimport { Badge } from \"../atomic/badge\";\nimport {\n DropdownMenuItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n} from \"../atomic/dropdown-menu\";\nimport { Switch } from \"../atomic/switch\";\nimport { UiIcon } from \"../../icons/ui-icons\";\n\nexport interface AccountMenuTab {\n id: string;\n label: React.ReactNode;\n /** Shown instead of the menu body when this tab is current; the first tab is always the menu itself. */\n content?: React.ReactNode;\n}\n\nexport interface AccountMenuProfile {\n /** Under the name on the profile card, e.g. \"Free\". */\n plan?: string;\n /** Makes the card a menu item that runs this and closes the menu, e.g. to open the account settings. */\n onOpenProfile?: () => void;\n tabs?: readonly AccountMenuTab[];\n /** Names the tab row for assistive tech. Default `\"Sections\"`. */\n tabsLabel?: string;\n /** Current tab id (controlled). */\n tab?: string;\n onTabChange?: (id: string) => void;\n /** A row with a short value badge on the right (\"EN\"); picking it runs `onSelect`. */\n language?: { label: string; value: string; onSelect?: () => void };\n /** A row with a switch; the menu closes after a toggle. */\n darkTheme?: { label: string; checked: boolean; onCheckedChange: (checked: boolean) => void };\n /** A submenu of radio options; the current one's label shows on the row. */\n colorTheme?: {\n label: string;\n value: string;\n options: readonly { id: string; label: string }[];\n onValueChange: (id: string) => void;\n };\n /** Glyphs for the rows, so the kit carries no icon set. */\n icons?: { language?: React.ReactNode; darkTheme?: React.ReactNode; colorTheme?: React.ReactNode };\n}\n\n/**\n * The tabs are `menuitemradio` items in a group, not a tablist: a menu may only\n * hold items, and this way the menu's own arrow-key roving reaches them.\n * Selecting one does not close the menu.\n */\nexport function ProfileTabs({\n tabs,\n value,\n onChange,\n label = \"Sections\",\n}: {\n tabs: readonly AccountMenuTab[];\n value: string;\n onChange: (id: string) => void;\n label?: string | undefined;\n}) {\n const move = (e: React.KeyboardEvent<HTMLButtonElement>, index: number) => {\n const step = e.key === \"ArrowRight\" ? 1 : e.key === \"ArrowLeft\" ? -1 : 0;\n if (step === 0) return;\n // Up and Down belong to the menu; Left and Right stay in the row.\n e.stopPropagation();\n e.preventDefault();\n const target = (index + step + tabs.length) % tabs.length;\n const next = tabs[target];\n if (!next) return;\n onChange(next.id);\n e.currentTarget.parentElement?.querySelectorAll<HTMLElement>('[role=\"menuitemradio\"]')[target]?.focus();\n };\n return (\n <div role=\"group\" aria-label={label} data-slot=\"account-menu-tabs\" className=\"flex border-b border-border-subtle\">\n {tabs.map((t, i) => {\n const selected = t.id === value;\n return (\n <button\n key={t.id}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n tabIndex={-1}\n onClick={() => onChange(t.id)}\n onKeyDown={(e) => move(e, i)}\n className={cn(\n \"-mb-px h-(--control-h-sm) flex-1 border-b px-3 text-body font-medium outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n selected ? \"border-primary text-ink\" : \"border-transparent text-ink-mid hover:text-ink\",\n )}\n >\n {t.label}\n </button>\n );\n })}\n </div>\n );\n}\n\nexport function ProfileCard({\n name,\n plan,\n initials,\n onOpen,\n}: {\n name: string;\n plan?: string | undefined;\n initials: string;\n onOpen?: (() => void) | undefined;\n}) {\n const content = (\n <>\n <Avatar className=\"size-14 shrink-0 rounded-full\">\n <AvatarFallback className=\"font-serif text-h2 font-light text-ink\">{initials.slice(0, 1)}</AvatarFallback>\n </Avatar>\n <span className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <span className=\"truncate text-body font-medium text-ink\">{name}</span>\n {plan && <span className=\"text-caption text-ink-soft\">{plan}</span>}\n </span>\n {onOpen && <UiIcon name=\"chevron-right\" className=\"size-4 text-ink-soft\" />}\n </>\n );\n if (!onOpen) {\n return (\n <div data-slot=\"account-menu-card\" className=\"flex w-full items-center gap-2.5 p-2\">\n {content}\n </div>\n );\n }\n // A real menu item: it joins the arrow-key order and closes the menu, so a dialog opened from it is not left under the menu.\n return (\n <DropdownMenuItem data-slot=\"account-menu-card\" className=\"h-auto gap-2.5 p-2\" onClick={onOpen}>\n {content}\n </DropdownMenuItem>\n );\n}\n\nexport function ProfileSettingRows({ profile }: { profile: AccountMenuProfile }) {\n const { language, darkTheme, colorTheme, icons } = profile;\n if (!language && !darkTheme && !colorTheme) return null;\n const currentColor = colorTheme?.options.find((o) => o.id === colorTheme.value)?.label;\n return (\n <>\n <DropdownMenuSeparator />\n {language && (\n <DropdownMenuItem onClick={() => language.onSelect?.()}>\n {icons?.language}\n <span className=\"flex-1\">{language.label}</span>\n <Badge>{language.value}</Badge>\n </DropdownMenuItem>\n )}\n {darkTheme && (\n <DropdownMenuItem\n role=\"menuitemcheckbox\"\n aria-checked={darkTheme.checked}\n onClick={() => darkTheme.onCheckedChange(!darkTheme.checked)}\n >\n {icons?.darkTheme}\n <span className=\"flex-1\">{darkTheme.label}</span>\n {/* Presentational: the row is the control, so the switch stays out of the tab order. */}\n <Switch checked={darkTheme.checked} tabIndex={-1} aria-hidden className=\"pointer-events-none\" />\n </DropdownMenuItem>\n )}\n {colorTheme && (\n <DropdownMenuSub>\n <DropdownMenuSubTrigger>\n {icons?.colorTheme}\n <span className=\"flex-1\">{colorTheme.label}</span>\n {currentColor && <span className=\"text-body-s text-ink-soft\">{currentColor}</span>}\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent>\n <DropdownMenuRadioGroup value={colorTheme.value} onValueChange={colorTheme.onValueChange}>\n {colorTheme.options.map((o) => (\n <DropdownMenuRadioItem key={o.id} value={o.id}>\n {o.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n )}\n </>\n );\n}\n"],"mappings":"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","names":[]}
@@ -12,7 +12,8 @@ import {
12
12
  ACCOUNT_SETTINGS_DIALOG_PANEL,
13
13
  ACCOUNT_SETTINGS_DIALOG_SIDEBAR,
14
14
  ACCOUNT_SETTINGS_DIALOG_TABS,
15
- ACCOUNT_SETTINGS_DIALOG_TITLE
15
+ ACCOUNT_SETTINGS_DIALOG_TITLE,
16
+ ACCOUNT_SETTINGS_DIALOG_LABELS
16
17
  } from "../../generated/account-settings-dialog.js";
17
18
  import { cn } from "../../lib/cn.js";
18
19
  import { Dialog, DialogClose, DialogContent, DialogDescription, DialogTitle } from "../atomic/dialog.js";
@@ -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
  )
@@ -1 +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} 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 ?? \"Close\"} className={ACCOUNT_SETTINGS_DIALOG_CLOSE}>\n <UiIcon name=\"x\" />\n </IconButton>\n </DialogClose>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"AAwFY,cAEI,YAFJ;AAxFZ,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,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,SAAS,WAAW,+BAC1D,8BAAC,UAAO,MAAK,KAAI,GACnB,GACF;AAAA;AAAA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;","names":[]}
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":[]}
@@ -13,12 +13,14 @@ import {
13
13
  ASIDE_PANEL_SHEET,
14
14
  ASIDE_RAIL_BASE,
15
15
  ASIDE_RAIL_SPACER,
16
- asidePanelSideClasses
16
+ asidePanelSideClasses,
17
+ ASIDE_HEADER_LABELS
17
18
  } from "../../generated/aside.js";
18
19
  import { Drawer, DrawerContent } from "../atomic/drawer.js";
19
20
  import { IconButton } from "../derived/icon-button.js";
20
21
  import { Sheet, SheetContent } from "../atomic/sheet.js";
21
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(
@@ -1 +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} 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\";\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 ?? \"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 ?? \"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 = \"Panels\",\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 = \"docked\" | \"overlay\";\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":[]}
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":[]}
@@ -8,6 +8,7 @@ import {
8
8
  EmptyMedia,
9
9
  EmptyTitle
10
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
  }
@@ -1 +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\";\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\n// lucide `lock`, inlined so the kit keeps its zero-icon-dep footprint.\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 <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n );\n}\n"],"mappings":"AAuBM,SAEI,KAFJ;AAvBN,YAAY,WAAW;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAYA,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;AAGA,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,MAEX;AAAA,4BAAC,UAAK,GAAE,KAAI,GAAE,MAAK,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,QACxD,oBAAC,UAAK,GAAE,4BAA2B;AAAA;AAAA;AAAA,EACrC;AAEJ;","names":[]}
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":[]}
@@ -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: [
@@ -1 +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-secondary 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-lg 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-50\",\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":[]}
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,7 +10,8 @@ import {
10
10
  CHAT_COMPOSER_SPACER,
11
11
  CHAT_COMPOSER_STREAMING,
12
12
  CHAT_COMPOSER_TOOLBAR,
13
- MODEL_CHIP_BASE
13
+ MODEL_CHIP_BASE,
14
+ CHAT_COMPOSER_LABELS
14
15
  } from "../../generated/chat-composer.js";
15
16
  import { cn } from "../../lib/cn.js";
16
17
  import { useControllableState } from "../../primitives/use-controllable-state.js";
@@ -24,7 +25,8 @@ import {
24
25
  import { IconButton } from "../derived/icon-button.js";
25
26
  import { Textarea } from "../atomic/textarea.js";
26
27
  import { UiIcon } from "../../icons/ui-icons.js";
27
- function ModelChip({ models, value, onValueChange, "aria-label": ariaLabel = "Model", className }) {
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" })
@@ -1 +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} 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\";\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 = \"Model\", 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 = \"Ask the assistant…\",\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 ?? \"Message\"}\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 ?? \"Attach file\"} 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 ?? \"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 ?? \"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
+ {"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":[]}