@ctrl-ui/react 0.8.7 → 0.8.8

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 (351) hide show
  1. package/dist/action-bar.d.ts +15 -7
  2. package/dist/action-bar.js +40 -20
  3. package/dist/activity.js +8 -16
  4. package/dist/audio-recorder.d.ts +14 -4
  5. package/dist/audio-recorder.js +82 -29
  6. package/dist/audio-visualizer.js +1 -1
  7. package/dist/blocks/coding-agent.js +39 -39
  8. package/dist/blocks/design-canvas-inspector.js +2 -2
  9. package/dist/blocks/design-canvas.d.ts +5 -1
  10. package/dist/blocks/design-canvas.js +200 -94
  11. package/dist/blocks/discussion.d.ts +28 -0
  12. package/dist/blocks/discussion.js +67 -0
  13. package/dist/blocks/file-explorer-data.d.ts +1 -0
  14. package/dist/blocks/file-explorer-data.js +4 -1
  15. package/dist/blocks/file-explorer.d.ts +9 -1
  16. package/dist/blocks/file-explorer.js +461 -192
  17. package/dist/blocks/settings.d.ts +2 -1
  18. package/dist/blocks/settings.js +102 -80
  19. package/dist/blocks/team-chat.d.ts +12 -0
  20. package/dist/blocks/team-chat.js +26 -0
  21. package/dist/blocks/theme-toggle.js +23 -31
  22. package/dist/chat-composer-attachment.d.ts +4 -1
  23. package/dist/chat-composer-attachment.js +35 -10
  24. package/dist/chat-composer-editor/extensions/mention.d.ts +5 -1
  25. package/dist/chat-composer-editor/extensions/mention.js +58 -27
  26. package/dist/chat-composer-editor/ghost.js +2 -4
  27. package/dist/chat-composer-editor/types.d.ts +5 -0
  28. package/dist/chat-composer-editor.d.ts +1 -1
  29. package/dist/chat-composer-editor.js +57 -30
  30. package/dist/chat-composer.d.ts +13 -32
  31. package/dist/chat-composer.js +53 -13
  32. package/dist/chat-layout.d.ts +19 -0
  33. package/dist/chat-layout.js +91 -40
  34. package/dist/chat-message/social.d.ts +26 -0
  35. package/dist/chat-message/social.js +122 -0
  36. package/dist/chat-message.d.ts +28 -29
  37. package/dist/chat-message.js +106 -25
  38. package/dist/context.d.ts +2 -2
  39. package/dist/context.js +39 -24
  40. package/dist/dynamic-notification-canvas-loop.d.ts +24 -0
  41. package/dist/dynamic-notification-canvas-loop.js +113 -0
  42. package/dist/dynamic-notification-glass.js +23 -114
  43. package/dist/dynamic-notification-liquid.js +14 -118
  44. package/dist/dynamic-notification.d.ts +16 -8
  45. package/dist/dynamic-notification.js +86 -23
  46. package/dist/email/email-brand.d.ts +7 -4
  47. package/dist/email/email-brand.js +9 -6
  48. package/dist/email/email-code.d.ts +3 -2
  49. package/dist/email/email-code.js +11 -9
  50. package/dist/email/email-footer.d.ts +5 -3
  51. package/dist/email/email-footer.js +11 -5
  52. package/dist/email/email.d.ts +31 -9
  53. package/dist/email/email.js +50 -26
  54. package/dist/email/templates.d.ts +10 -9
  55. package/dist/email/templates.js +102 -38
  56. package/dist/email/theme.js +1 -1
  57. package/dist/environment-variables.d.ts +4 -2
  58. package/dist/environment-variables.js +52 -32
  59. package/dist/filter-bar/editor.js +20 -8
  60. package/dist/filter-bar/model.d.ts +1 -0
  61. package/dist/filter-bar/model.js +10 -1
  62. package/dist/filter-bar/motion.js +4 -4
  63. package/dist/filter-bar/parts.js +20 -9
  64. package/dist/filter-bar/types.d.ts +1 -0
  65. package/dist/filter-bar.js +20 -14
  66. package/dist/hooks/use-audio-recorder.js +12 -6
  67. package/dist/hooks/use-chat-composer.d.ts +19 -7
  68. package/dist/hooks/use-chat-composer.js +32 -5
  69. package/dist/hooks/use-chat-message.d.ts +28 -2
  70. package/dist/hooks/use-chat-message.js +41 -10
  71. package/dist/hooks/use-chat-thread-scroll.js +43 -7
  72. package/dist/hooks/use-color-area.d.ts +3 -3
  73. package/dist/hooks/use-color-area.js +13 -12
  74. package/dist/hooks/use-copy-to-clipboard.d.ts +2 -1
  75. package/dist/hooks/use-copy-to-clipboard.js +20 -20
  76. package/dist/hooks/use-dynamic-notification.d.ts +6 -2
  77. package/dist/hooks/use-dynamic-notification.js +26 -10
  78. package/dist/hooks/use-mobile.d.ts +3 -2
  79. package/dist/hooks/use-mobile.js +8 -4
  80. package/dist/hooks/use-textarea-trigger-menu.js +2 -1
  81. package/dist/hooks/use-trigger-menu.d.ts +54 -0
  82. package/dist/hooks/use-trigger-menu.js +102 -47
  83. package/dist/hooks/use-user-ask.d.ts +2 -0
  84. package/dist/hooks/use-user-ask.js +35 -41
  85. package/dist/inline-attachment.d.ts +6 -2
  86. package/dist/inline-attachment.js +36 -15
  87. package/dist/inline-citation.d.ts +12 -5
  88. package/dist/inline-citation.js +26 -17
  89. package/dist/knob-contracts/audio-recorder-knobs.d.ts +1 -1
  90. package/dist/knob-contracts/audio-recorder-knobs.js +2 -1
  91. package/dist/knob-contracts/audio-visualizer-knobs.d.ts +1 -1
  92. package/dist/knob-contracts/audio-visualizer-knobs.js +2 -1
  93. package/dist/knob-contracts/avatar-knobs.d.ts +1 -1
  94. package/dist/knob-contracts/avatar-knobs.js +6 -1
  95. package/dist/knob-contracts/badge-knobs.d.ts +1 -1
  96. package/dist/knob-contracts/badge-knobs.js +2 -1
  97. package/dist/knob-contracts/breadcrumb-knobs.d.ts +4 -0
  98. package/dist/knob-contracts/breadcrumb-knobs.js +8 -0
  99. package/dist/knob-contracts/button-knobs.d.ts +1 -1
  100. package/dist/knob-contracts/button-knobs.js +1 -0
  101. package/dist/knob-contracts/chat-message-knobs.d.ts +1 -1
  102. package/dist/knob-contracts/chat-message-knobs.js +8 -1
  103. package/dist/knob-contracts/code-diff-knobs.d.ts +1 -1
  104. package/dist/knob-contracts/code-diff-knobs.js +2 -0
  105. package/dist/knob-contracts/code-knobs.d.ts +1 -1
  106. package/dist/knob-contracts/code-knobs.js +2 -1
  107. package/dist/knob-contracts/dynamic-notification-knobs.d.ts +1 -1
  108. package/dist/knob-contracts/dynamic-notification-knobs.js +2 -0
  109. package/dist/knob-contracts/emoji-picker-knobs.d.ts +4 -0
  110. package/dist/knob-contracts/emoji-picker-knobs.js +10 -0
  111. package/dist/knob-contracts/field-knobs.d.ts +1 -1
  112. package/dist/knob-contracts/field-knobs.js +5 -1
  113. package/dist/knob-contracts/filter-bar-knobs.d.ts +1 -1
  114. package/dist/knob-contracts/filter-bar-knobs.js +1 -2
  115. package/dist/knob-contracts/markdown-knobs.d.ts +1 -1
  116. package/dist/knob-contracts/markdown-knobs.js +3 -1
  117. package/dist/knob-contracts/page-layout-knobs.d.ts +1 -1
  118. package/dist/knob-contracts/page-layout-knobs.js +2 -1
  119. package/dist/knob-contracts/popup-knobs.d.ts +1 -1
  120. package/dist/knob-contracts/popup-knobs.js +27 -0
  121. package/dist/knob-contracts/range-knobs.d.ts +1 -1
  122. package/dist/knob-contracts/range-knobs.js +1 -0
  123. package/dist/knob-contracts/rich-tooltip-knobs.d.ts +1 -1
  124. package/dist/knob-contracts/rich-tooltip-knobs.js +2 -1
  125. package/dist/knob-contracts/sidebar-knobs.d.ts +1 -1
  126. package/dist/knob-contracts/sidebar-knobs.js +27 -2
  127. package/dist/knob-contracts/spinner-knobs.d.ts +1 -1
  128. package/dist/knob-contracts/spinner-knobs.js +1 -1
  129. package/dist/knob-contracts/stepper-knobs.d.ts +1 -1
  130. package/dist/knob-contracts/stepper-knobs.js +4 -1
  131. package/dist/knob-contracts/switch-knobs.d.ts +1 -1
  132. package/dist/knob-contracts/switch-knobs.js +5 -0
  133. package/dist/knob-contracts/table-of-contents-knobs.d.ts +1 -1
  134. package/dist/knob-contracts/table-of-contents-knobs.js +2 -1
  135. package/dist/knob-contracts/tabs-knobs.d.ts +1 -1
  136. package/dist/knob-contracts/tabs-knobs.js +1 -0
  137. package/dist/knob-contracts/tree-knobs.d.ts +1 -1
  138. package/dist/knob-contracts/tree-knobs.js +2 -1
  139. package/dist/lib/cn.js +0 -4
  140. package/dist/lib/contrast.d.ts +1 -0
  141. package/dist/lib/contrast.js +17 -5
  142. package/dist/lib/dropzone-validation.js +41 -28
  143. package/dist/lib/env-file.d.ts +1 -1
  144. package/dist/lib/env-file.js +5 -5
  145. package/dist/lib/motion.d.ts +4 -0
  146. package/dist/lib/motion.js +15 -0
  147. package/dist/lib/phone-input-format.js +1 -1
  148. package/dist/lib/trigger-detect.js +6 -8
  149. package/dist/markdown-block.js +2 -1
  150. package/dist/popup-parts.d.ts +8 -0
  151. package/dist/popup-parts.js +43 -0
  152. package/dist/source-badge.js +3 -1
  153. package/dist/styles/code.css +0 -2
  154. package/dist/styles/effects.css +6 -32
  155. package/dist/styles/index.css +10 -5
  156. package/dist/styles/recipes/accordion.css +9 -6
  157. package/dist/styles/recipes/action-bar.css +0 -15
  158. package/dist/styles/recipes/activity.css +5 -11
  159. package/dist/styles/recipes/alert.css +4 -4
  160. package/dist/styles/recipes/audio-recorder.css +15 -3
  161. package/dist/styles/recipes/audio-visualizer.css +13 -2
  162. package/dist/styles/recipes/avatar.css +78 -1
  163. package/dist/styles/recipes/badge.css +14 -4
  164. package/dist/styles/recipes/breadcrumb.css +77 -0
  165. package/dist/styles/recipes/button-group.css +5 -7
  166. package/dist/styles/recipes/button-states.css +66 -0
  167. package/dist/styles/recipes/button.css +24 -83
  168. package/dist/styles/recipes/calendar.css +17 -23
  169. package/dist/styles/recipes/card.css +2 -2
  170. package/dist/styles/recipes/chat-composer-attachment.css +9 -3
  171. package/dist/styles/recipes/chat-composer.css +7 -10
  172. package/dist/styles/recipes/chat-layout.css +35 -0
  173. package/dist/styles/recipes/chat-message-social.css +123 -0
  174. package/dist/styles/recipes/chat-message.css +157 -37
  175. package/dist/styles/recipes/choice.css +18 -21
  176. package/dist/styles/recipes/code-diff.css +46 -33
  177. package/dist/styles/recipes/code.css +36 -16
  178. package/dist/styles/recipes/collapsible.css +7 -2
  179. package/dist/styles/recipes/color-picker-details.css +3 -4
  180. package/dist/styles/recipes/color-picker-values.css +9 -8
  181. package/dist/styles/recipes/color-picker.css +11 -2
  182. package/dist/styles/recipes/context.css +3 -3
  183. package/dist/styles/recipes/dockable-panel.css +7 -4
  184. package/dist/styles/recipes/dropzone.css +7 -8
  185. package/dist/styles/recipes/dynamic-notification-input.css +8 -5
  186. package/dist/styles/recipes/dynamic-notification-motion.css +12 -21
  187. package/dist/styles/recipes/dynamic-notification.css +40 -26
  188. package/dist/styles/recipes/emoji-picker.css +132 -0
  189. package/dist/styles/recipes/empty.css +5 -4
  190. package/dist/styles/recipes/environment-variables.css +4 -15
  191. package/dist/styles/recipes/field-parts.css +30 -24
  192. package/dist/styles/recipes/field.css +61 -26
  193. package/dist/styles/recipes/filter-bar.css +18 -31
  194. package/dist/styles/recipes/gradient-editor.css +18 -7
  195. package/dist/styles/recipes/infinite-canvas.css +0 -1
  196. package/dist/styles/recipes/inline-attachment.css +3 -3
  197. package/dist/styles/recipes/inline-citation.css +10 -4
  198. package/dist/styles/recipes/item.css +23 -9
  199. package/dist/styles/recipes/markdown-block.css +5 -4
  200. package/dist/styles/recipes/markdown.css +68 -26
  201. package/dist/styles/recipes/morphing-panel.css +8 -8
  202. package/dist/styles/recipes/page-layout.css +20 -12
  203. package/dist/styles/recipes/pagination.css +4 -5
  204. package/dist/styles/recipes/phone-input.css +12 -8
  205. package/dist/styles/recipes/popup-controls.css +166 -33
  206. package/dist/styles/recipes/popup-drawer.css +3 -14
  207. package/dist/styles/recipes/popup-lists.css +128 -27
  208. package/dist/styles/recipes/popup-motion.css +4 -45
  209. package/dist/styles/recipes/popup-toast.css +55 -26
  210. package/dist/styles/recipes/popup.css +139 -141
  211. package/dist/styles/recipes/range.css +54 -18
  212. package/dist/styles/recipes/resizable.css +2 -7
  213. package/dist/styles/recipes/rich-tooltip.css +24 -34
  214. package/dist/styles/recipes/scroll-area.css +8 -1
  215. package/dist/styles/recipes/sidebar-menu.css +149 -34
  216. package/dist/styles/recipes/sidebar-parts.css +154 -0
  217. package/dist/styles/recipes/sidebar.css +187 -128
  218. package/dist/styles/recipes/source-badge.css +1 -1
  219. package/dist/styles/recipes/spinner.css +8 -1
  220. package/dist/styles/recipes/stepper.css +31 -13
  221. package/dist/styles/recipes/switch.css +68 -23
  222. package/dist/styles/recipes/table-of-contents.css +9 -1
  223. package/dist/styles/recipes/table.css +14 -10
  224. package/dist/styles/recipes/tabs.css +17 -12
  225. package/dist/styles/recipes/task-list.css +7 -14
  226. package/dist/styles/recipes/thread-rail.css +42 -19
  227. package/dist/styles/recipes/timeline.css +2 -0
  228. package/dist/styles/recipes/toolbar.css +27 -25
  229. package/dist/styles/recipes/track-highlight.css +10 -7
  230. package/dist/styles/recipes/tree.css +31 -4
  231. package/dist/styles/recipes/user-ask-details.css +0 -1
  232. package/dist/styles/recipes/user-ask.css +4 -4
  233. package/dist/styles/theme.css +37 -16
  234. package/dist/task-list.d.ts +4 -1
  235. package/dist/task-list.js +24 -8
  236. package/dist/thread-rail.d.ts +1 -1
  237. package/dist/thread-rail.js +61 -19
  238. package/dist/transcript-divider.js +2 -1
  239. package/dist/ui/alert-dialog.js +1 -1
  240. package/dist/ui/alert.d.ts +3 -1
  241. package/dist/ui/alert.js +14 -8
  242. package/dist/ui/autocomplete.js +4 -2
  243. package/dist/ui/avatar.d.ts +8 -0
  244. package/dist/ui/avatar.js +23 -3
  245. package/dist/ui/badge.js +1 -1
  246. package/dist/ui/breadcrumb.d.ts +27 -0
  247. package/dist/ui/breadcrumb.js +88 -0
  248. package/dist/ui/button.d.ts +2 -1
  249. package/dist/ui/button.js +3 -3
  250. package/dist/ui/calendar.js +2 -2
  251. package/dist/ui/card.d.ts +3 -1
  252. package/dist/ui/card.js +12 -7
  253. package/dist/ui/checkbox.d.ts +2 -0
  254. package/dist/ui/code-diff.d.ts +1 -1
  255. package/dist/ui/code-diff.js +72 -28
  256. package/dist/ui/code.d.ts +5 -3
  257. package/dist/ui/code.js +28 -29
  258. package/dist/ui/collapsible.js +1 -1
  259. package/dist/ui/color-picker.d.ts +5 -2
  260. package/dist/ui/color-picker.js +85 -37
  261. package/dist/ui/combobox-disabled-selection.d.ts +1 -2
  262. package/dist/ui/combobox-disabled-selection.js +7 -9
  263. package/dist/ui/combobox.js +14 -6
  264. package/dist/ui/command.d.ts +8 -2
  265. package/dist/ui/command.js +30 -14
  266. package/dist/ui/context-menu.js +4 -1
  267. package/dist/ui/dialog.d.ts +2 -1
  268. package/dist/ui/dialog.js +4 -23
  269. package/dist/ui/dockable-panel-geometry.d.ts +1 -0
  270. package/dist/ui/dockable-panel-geometry.js +7 -1
  271. package/dist/ui/dockable-panel.d.ts +9 -6
  272. package/dist/ui/dockable-panel.js +63 -23
  273. package/dist/ui/drawer.js +1 -1
  274. package/dist/ui/dropdown-menu.js +5 -4
  275. package/dist/ui/dropzone.d.ts +2 -2
  276. package/dist/ui/dropzone.js +75 -16
  277. package/dist/ui/emoji-picker.d.ts +18 -0
  278. package/dist/ui/emoji-picker.js +136 -0
  279. package/dist/ui/empty.d.ts +3 -1
  280. package/dist/ui/empty.js +12 -7
  281. package/dist/ui/gradient-editor.d.ts +1 -1
  282. package/dist/ui/gradient-editor.js +37 -21
  283. package/dist/ui/hover-card.js +1 -1
  284. package/dist/ui/infinite-canvas.d.ts +3 -2
  285. package/dist/ui/infinite-canvas.js +63 -19
  286. package/dist/ui/input-group.d.ts +0 -3
  287. package/dist/ui/input-group.js +4 -14
  288. package/dist/ui/input-otp.d.ts +1 -1
  289. package/dist/ui/input-otp.js +32 -15
  290. package/dist/ui/input.js +4 -4
  291. package/dist/ui/item.d.ts +2 -1
  292. package/dist/ui/item.js +12 -8
  293. package/dist/ui/live-status.d.ts +7 -0
  294. package/dist/ui/live-status.js +17 -0
  295. package/dist/ui/markdown-elements.d.ts +6 -0
  296. package/dist/ui/markdown-elements.js +31 -1
  297. package/dist/ui/menubar.js +3 -3
  298. package/dist/ui/morphing-panel.js +3 -2
  299. package/dist/ui/native-select.d.ts +1 -1
  300. package/dist/ui/native-select.js +24 -11
  301. package/dist/ui/navigation-menu.js +1 -1
  302. package/dist/ui/page-layout.d.ts +2 -2
  303. package/dist/ui/page-layout.js +2 -4
  304. package/dist/ui/pagination.d.ts +7 -5
  305. package/dist/ui/pagination.js +19 -13
  306. package/dist/ui/phone-input.d.ts +1 -0
  307. package/dist/ui/phone-input.js +58 -60
  308. package/dist/ui/popover.js +1 -1
  309. package/dist/ui/radio-group.d.ts +2 -0
  310. package/dist/ui/resizable.d.ts +3 -2
  311. package/dist/ui/resizable.js +5 -3
  312. package/dist/ui/responsive-dialog.d.ts +1 -1
  313. package/dist/ui/responsive-dialog.js +4 -21
  314. package/dist/ui/rich-tooltip.d.ts +10 -4
  315. package/dist/ui/rich-tooltip.js +82 -34
  316. package/dist/ui/scroll-area.d.ts +1 -1
  317. package/dist/ui/scroll-area.js +43 -28
  318. package/dist/ui/select.js +1 -1
  319. package/dist/ui/sheet.js +1 -1
  320. package/dist/ui/sidebar-menu.d.ts +5 -1
  321. package/dist/ui/sidebar-menu.js +32 -34
  322. package/dist/ui/sidebar-provider.d.ts +10 -1
  323. package/dist/ui/sidebar-provider.js +39 -14
  324. package/dist/ui/sidebar-resize-rail.js +8 -4
  325. package/dist/ui/sidebar.d.ts +11 -6
  326. package/dist/ui/sidebar.js +47 -24
  327. package/dist/ui/slider.js +31 -22
  328. package/dist/ui/spinner.d.ts +3 -2
  329. package/dist/ui/spinner.js +3 -2
  330. package/dist/ui/stepper.d.ts +8 -1
  331. package/dist/ui/stepper.js +74 -25
  332. package/dist/ui/switch.d.ts +1 -0
  333. package/dist/ui/table-of-contents.d.ts +2 -2
  334. package/dist/ui/table-of-contents.js +20 -8
  335. package/dist/ui/table.js +4 -2
  336. package/dist/ui/textarea.d.ts +1 -1
  337. package/dist/ui/textarea.js +20 -9
  338. package/dist/ui/timeline.d.ts +3 -1
  339. package/dist/ui/timeline.js +17 -9
  340. package/dist/ui/toast.d.ts +11 -5
  341. package/dist/ui/toast.js +101 -55
  342. package/dist/ui/toolbar.d.ts +3 -2
  343. package/dist/ui/toolbar.js +4 -2
  344. package/dist/ui/tooltip.js +4 -21
  345. package/dist/ui/tree.js +121 -81
  346. package/dist/ui/trigger-menu.js +2 -1
  347. package/dist/user-ask.d.ts +10 -5
  348. package/dist/user-ask.js +32 -12
  349. package/package.json +5 -1
  350. package/dist/hooks/use-keyboard-navigation.d.ts +0 -3
  351. package/dist/hooks/use-keyboard-navigation.js +0 -22
@@ -1,11 +1,11 @@
1
1
  "use client";
2
2
  import { Button } from "../ui/button.js";
3
3
  import { InputGroup, InputGroupAddon } from "../ui/input-group.js";
4
- import { Empty, EmptyDescription, EmptyHeader, EmptyTitle } from "../ui/empty.js";
5
- import { Separator } from "../ui/separator.js";
6
4
  import { resizeDesignCanvasLayer } from "./design-canvas-data.js";
7
5
  import { NumberField, NumberFieldGroup, NumberFieldInput, NumberFieldScrubArea } from "../ui/number-field.js";
8
6
  import { ColorPicker, ColorPickerArea, ColorPickerContent, ColorPickerEyeDropper, ColorPickerHue, ColorPickerInput, ColorPickerTrigger } from "../ui/color-picker.js";
7
+ import { Empty, EmptyDescription, EmptyHeader, EmptyTitle } from "../ui/empty.js";
8
+ import { Separator } from "../ui/separator.js";
9
9
  import { Toggle } from "../ui/toggle.js";
10
10
  import { useState } from "react";
11
11
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -11,7 +11,11 @@ export type DesignCanvasBlockProps = Omit<ComponentProps<"div">, "children" | "d
11
11
  onSelectedLayerIdChange?: (layerId: string | null) => void;
12
12
  defaultTransform?: InfiniteCanvasTransform;
13
13
  layout?: "viewport" | "contained";
14
+ layersLabel?: string;
15
+ propertiesLabel?: string;
16
+ openLayersLabel?: string;
17
+ openPropertiesLabel?: string;
14
18
  };
15
- export declare function DesignCanvasBlock({ layers, defaultLayers, onLayersChange, selectedLayerId, defaultSelectedLayerId, onSelectedLayerIdChange, defaultTransform, layout, className, ...props }: DesignCanvasBlockProps): import("react").JSX.Element;
19
+ export declare function DesignCanvasBlock({ layers, defaultLayers, onLayersChange, selectedLayerId, defaultSelectedLayerId, onSelectedLayerIdChange, defaultTransform, layout, layersLabel, propertiesLabel, openLayersLabel, openPropertiesLabel, className, ...props }: DesignCanvasBlockProps): import("react").JSX.Element;
16
20
  //#endregion
17
21
  export type { DesignCanvasFill, DesignCanvasLayer, DesignCanvasLayerKind, DesignCanvasTool };
@@ -3,14 +3,15 @@ import { cn } from "../lib/cn.js";
3
3
  import { Button } from "../ui/button.js";
4
4
  import { ScrollArea } from "../ui/scroll-area.js";
5
5
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip.js";
6
- import { InfiniteCanvas, InfiniteCanvasContent, InfiniteCanvasControls, InfiniteCanvasItem } from "../ui/infinite-canvas.js";
7
- import { ResizableFloatingPanel } from "../ui/resizable.js";
8
- import { Toolbar, ToolbarButton, ToolbarGroup } from "../ui/toolbar.js";
9
6
  import { createDesignCanvasLayer, designCanvasFillColor, drawnDesignCanvasBounds } from "./design-canvas-data.js";
10
7
  import { DesignCanvasInspector } from "./design-canvas-inspector.js";
8
+ import { Drawer, DrawerContent, DrawerTitle } from "../ui/drawer.js";
9
+ import { InfiniteCanvas, InfiniteCanvasContent, InfiniteCanvasControls, InfiniteCanvasItem } from "../ui/infinite-canvas.js";
10
+ import { ResizableFloatingPanel } from "../ui/resizable.js";
11
+ import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator } from "../ui/toolbar.js";
11
12
  import { useRef, useState } from "react";
12
13
  import { jsx, jsxs } from "react/jsx-runtime";
13
- import { CircleIcon, FrameIcon, MousePointer2Icon, SquareIcon, TypeIcon } from "lucide-react";
14
+ import { CircleIcon, FrameIcon, LayersIcon, MousePointer2Icon, SlidersHorizontalIcon, SquareIcon, TypeIcon } from "lucide-react";
14
15
  //#region src/blocks/design-canvas.tsx
15
16
  const TOOLS = [
16
17
  {
@@ -74,6 +75,9 @@ const DEFAULT_TRANSFORM = {
74
75
  scale: 1
75
76
  };
76
77
  const CLICK_TOLERANCE_PX = 4;
78
+ const DELETE_KEYS = /* @__PURE__ */ new Set(["Delete", "Backspace"]);
79
+ const CANVAS_KEY_SHORTCUTS = `${TOOLS.map((entry) => entry.shortcut).join(" ")} Enter Delete Backspace Escape`;
80
+ const LAYER_KEY_SHORTCUTS = "Enter Space ArrowLeft ArrowRight ArrowUp ArrowDown Delete Backspace";
77
81
  function newLayerId(kind) {
78
82
  return `${kind}-${Math.random().toString(36).slice(2, 8)}`;
79
83
  }
@@ -83,12 +87,14 @@ function toolForShortcut(key) {
83
87
  function layerFromDraft(draft, id) {
84
88
  return createDesignCanvasLayer(draft.kind, drawnDesignCanvasBounds(draft.kind, draft.start, draft.end, draft.clickTolerance), id);
85
89
  }
86
- function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selectedLayerId, defaultSelectedLayerId = null, onSelectedLayerIdChange, defaultTransform = DEFAULT_TRANSFORM, layout = "viewport", className, ...props }) {
90
+ function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selectedLayerId, defaultSelectedLayerId = null, onSelectedLayerIdChange, defaultTransform = DEFAULT_TRANSFORM, layout = "viewport", layersLabel = "Layers", propertiesLabel = "Properties", openLayersLabel = "Show layers", openPropertiesLabel = "Show properties", className, ...props }) {
87
91
  const [internalLayers, setInternalLayers] = useState(defaultLayers);
88
92
  const [internalSelectedLayerId, setInternalSelectedLayerId] = useState(defaultSelectedLayerId);
89
93
  const transformRef = useRef(defaultTransform);
90
94
  const [tool, setTool] = useState("move");
91
95
  const [draft, setDraft] = useState(null);
96
+ const [layersOpen, setLayersOpen] = useState(false);
97
+ const [propertiesOpen, setPropertiesOpen] = useState(false);
92
98
  const currentLayers = layers ?? internalLayers;
93
99
  const currentSelectedLayerId = selectedLayerId === void 0 ? internalSelectedLayerId : selectedLayerId;
94
100
  const selectedLayer = currentLayers.find((layer) => layer.id === currentSelectedLayerId);
@@ -103,14 +109,33 @@ function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selecte
103
109
  function replaceLayer(next) {
104
110
  changeLayers(currentLayers.map((layer) => layer.id === next.id ? next : layer));
105
111
  }
106
- function worldPointAt(event) {
107
- const bounds = event.currentTarget.getBoundingClientRect();
112
+ function addLayer(layer) {
113
+ changeLayers([...currentLayers, layer]);
114
+ selectLayer(layer.id);
115
+ setTool("move");
116
+ }
117
+ function toWorldPoint(local) {
108
118
  const { x, y, scale } = transformRef.current;
109
119
  return {
110
- x: (event.clientX - bounds.left - x) / scale,
111
- y: (event.clientY - bounds.top - y) / scale
120
+ x: (local.x - x) / scale,
121
+ y: (local.y - y) / scale
112
122
  };
113
123
  }
124
+ function worldPointAt(event) {
125
+ const bounds = event.currentTarget.getBoundingClientRect();
126
+ return toWorldPoint({
127
+ x: event.clientX - bounds.left,
128
+ y: event.clientY - bounds.top
129
+ });
130
+ }
131
+ function addLayerAtViewportCenter(kind, canvas) {
132
+ const center = toWorldPoint({
133
+ x: canvas.clientWidth / 2,
134
+ y: canvas.clientHeight / 2
135
+ });
136
+ const bounds = drawnDesignCanvasBounds(kind, center, center, CLICK_TOLERANCE_PX / transformRef.current.scale);
137
+ addLayer(createDesignCanvasLayer(kind, bounds, newLayerId(kind)));
138
+ }
114
139
  function beginDrawOrDeselect(event) {
115
140
  if (event.defaultPrevented || event.target !== event.currentTarget) return;
116
141
  if (tool === "move") {
@@ -138,48 +163,63 @@ function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selecte
138
163
  }
139
164
  function commitDraft(event) {
140
165
  if (draft?.pointerId !== event.pointerId) return;
141
- const layer = layerFromDraft(draft, newLayerId(draft.kind));
142
166
  setDraft(null);
143
- changeLayers([...currentLayers, layer]);
144
- selectLayer(layer.id);
145
- setTool("move");
167
+ addLayer(layerFromDraft(draft, newLayerId(draft.kind)));
146
168
  }
147
169
  function cancelDraft(event) {
148
170
  if (draft?.pointerId === event.pointerId) setDraft(null);
149
171
  }
150
- function editSelectedLayerWithKey(event) {
151
- if (!selectedLayer) return false;
172
+ function editLayerWithKey(layer, event) {
152
173
  const nudge = NUDGE_DIRECTIONS[event.key];
153
- if (event.key === "Delete" || event.key === "Backspace") {
154
- changeLayers(currentLayers.filter((layer) => layer.id !== selectedLayer.id));
155
- selectLayer(null);
174
+ if (DELETE_KEYS.has(event.key)) {
175
+ changeLayers(currentLayers.filter((entry) => entry.id !== layer.id));
176
+ if (layer.id === currentSelectedLayerId) selectLayer(null);
156
177
  } else if (nudge) {
157
178
  const distance = event.shiftKey ? 10 : 1;
158
179
  replaceLayer({
159
- ...selectedLayer,
160
- x: selectedLayer.x + nudge.x * distance,
161
- y: selectedLayer.y + nudge.y * distance
180
+ ...layer,
181
+ x: layer.x + nudge.x * distance,
182
+ y: layer.y + nudge.y * distance
162
183
  });
163
184
  } else return false;
164
185
  return true;
165
186
  }
166
- function handleShortcut(event) {
187
+ function handleLayerKey(layer, event) {
167
188
  if (event.metaKey || event.ctrlKey || event.altKey) return;
189
+ if (event.key === "Enter" || event.key === " ") selectLayer(layer.id);
190
+ else if (!editLayerWithKey(layer, event)) return;
191
+ event.preventDefault();
192
+ if (DELETE_KEYS.has(event.key)) event.currentTarget.closest("[data-control-family=\"infinite-canvas\"][data-slot=\"root\"]")?.focus();
193
+ }
194
+ function handleShortcut(event) {
195
+ if (event.defaultPrevented || event.metaKey || event.ctrlKey || event.altKey) return;
168
196
  const shortcutTool = toolForShortcut(event.key);
169
197
  if (shortcutTool) setTool(shortcutTool);
170
198
  else if (event.key === "Escape") {
171
199
  setDraft(null);
172
200
  setTool("move");
173
201
  selectLayer(null);
174
- } else if (!editSelectedLayerWithKey(event)) return;
202
+ } else if (event.key === "Enter" && tool !== "move" && event.target === event.currentTarget) addLayerAtViewportCenter(tool, event.currentTarget);
203
+ else if (!selectedLayer || !editLayerWithKey(selectedLayer, event)) return;
175
204
  event.preventDefault();
176
205
  }
206
+ const layerList = /* @__PURE__ */ jsx(DesignCanvasLayerList, {
207
+ layers: currentLayers,
208
+ selectedLayerId: currentSelectedLayerId,
209
+ onSelect: selectLayer
210
+ });
211
+ const inspector = /* @__PURE__ */ jsx(DesignCanvasInspector, {
212
+ layer: selectedLayer,
213
+ onLayerChange: replaceLayer
214
+ });
215
+ const propertiesTitle = selectedLayer?.name ?? "Design";
177
216
  return /* @__PURE__ */ jsxs("div", {
178
217
  className: cn("@container/design-canvas relative isolate overflow-hidden bg-background text-foreground", layout === "contained" ? "h-full min-h-0" : "h-svh", className),
179
218
  ...props,
180
219
  children: [
181
220
  /* @__PURE__ */ jsxs(InfiniteCanvas, {
182
221
  "aria-label": "Design canvas",
222
+ "aria-keyshortcuts": CANVAS_KEY_SHORTCUTS,
183
223
  defaultTransform,
184
224
  onTransformChange: (next) => {
185
225
  transformRef.current = next;
@@ -202,12 +242,13 @@ function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selecte
202
242
  layer,
203
243
  selected: layer.id === currentSelectedLayerId,
204
244
  onSelect: () => selectLayer(layer.id),
245
+ onKeyDown: (event) => handleLayerKey(layer, event),
205
246
  onLayerChange: replaceLayer
206
247
  }, layer.id)), draft ? /* @__PURE__ */ jsx(DesignCanvasLayerNode, {
207
248
  layer: layerFromDraft(draft, "draft"),
208
249
  selected: true
209
250
  }) : null]
210
- }), /* @__PURE__ */ jsx(InfiniteCanvasControls, { className: "top-3 right-auto bottom-auto left-3 @4xl/design-canvas:left-1/2 @4xl/design-canvas:-translate-x-1/2" })]
251
+ }), /* @__PURE__ */ jsx(InfiniteCanvasControls, { className: "start-3 end-auto top-3 bottom-auto w-max @4xl/design-canvas:inset-x-0 @4xl/design-canvas:mx-auto" })]
211
252
  }),
212
253
  /* @__PURE__ */ jsx(ResizableFloatingPanel, {
213
254
  side: "left",
@@ -215,30 +256,10 @@ function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selecte
215
256
  minSize: 180,
216
257
  maxSize: 360,
217
258
  className: "hidden @4xl/design-canvas:flex",
218
- children: /* @__PURE__ */ jsxs("aside", {
219
- "aria-label": "Layers",
220
- className: "flex min-h-0 flex-1 flex-col",
221
- children: [/* @__PURE__ */ jsx("h2", {
222
- className: "flex h-11 shrink-0 items-center border-b px-3 text-caption font-medium",
223
- children: "Layers"
224
- }), /* @__PURE__ */ jsx(ScrollArea, {
225
- className: "min-h-0 flex-1",
226
- children: /* @__PURE__ */ jsx("ul", {
227
- className: "flex flex-col gap-0.5 p-2",
228
- children: currentLayers.toReversed().map((layer) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Button, {
229
- variant: "ghost",
230
- size: "sm",
231
- active: layer.id === currentSelectedLayerId,
232
- "aria-pressed": layer.id === currentSelectedLayerId,
233
- className: "w-full justify-start [&_svg]:size-3.5 [&_svg]:text-muted-foreground",
234
- onClick: () => selectLayer(layer.id),
235
- children: [LAYER_ICONS[layer.kind], /* @__PURE__ */ jsx("span", {
236
- className: "truncate",
237
- children: layer.name
238
- })]
239
- }) }, layer.id))
240
- })
241
- })]
259
+ children: /* @__PURE__ */ jsx(DesignCanvasPanel, {
260
+ label: layersLabel,
261
+ title: layersLabel,
262
+ children: layerList
242
263
  })
243
264
  }),
244
265
  /* @__PURE__ */ jsx(ResizableFloatingPanel, {
@@ -246,37 +267,133 @@ function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selecte
246
267
  minSize: 256,
247
268
  maxSize: 440,
248
269
  className: "hidden @xl/design-canvas:flex",
249
- children: /* @__PURE__ */ jsxs("aside", {
250
- "aria-label": "Properties",
251
- className: "flex min-h-0 flex-1 flex-col",
252
- children: [/* @__PURE__ */ jsx("h2", {
253
- className: "flex h-11 shrink-0 items-center border-b px-3 text-caption font-medium",
254
- children: /* @__PURE__ */ jsx("span", {
255
- className: "truncate",
256
- children: selectedLayer?.name ?? "Design"
257
- })
258
- }), /* @__PURE__ */ jsx(ScrollArea, {
259
- className: "min-h-0 flex-1",
260
- children: /* @__PURE__ */ jsx(DesignCanvasInspector, {
261
- layer: selectedLayer,
262
- onLayerChange: replaceLayer
263
- })
264
- })]
270
+ children: /* @__PURE__ */ jsx(DesignCanvasPanel, {
271
+ label: propertiesLabel,
272
+ title: propertiesTitle,
273
+ children: inspector
265
274
  })
266
275
  }),
267
- /* @__PURE__ */ jsx(DesignCanvasToolbar, {
268
- tool,
269
- onToolChange: setTool
270
- })
276
+ /* @__PURE__ */ jsx(Drawer, {
277
+ side: "left",
278
+ open: layersOpen,
279
+ onOpenChange: setLayersOpen,
280
+ children: /* @__PURE__ */ jsx(DrawerContent, {
281
+ side: "left",
282
+ className: "gap-0 p-0",
283
+ children: /* @__PURE__ */ jsx(DesignCanvasPanel, {
284
+ label: layersLabel,
285
+ title: layersLabel,
286
+ inDrawer: true,
287
+ children: layerList
288
+ })
289
+ })
290
+ }),
291
+ /* @__PURE__ */ jsx(Drawer, {
292
+ side: "right",
293
+ open: propertiesOpen,
294
+ onOpenChange: setPropertiesOpen,
295
+ children: /* @__PURE__ */ jsx(DrawerContent, {
296
+ side: "right",
297
+ className: "gap-0 p-0",
298
+ children: /* @__PURE__ */ jsx(DesignCanvasPanel, {
299
+ label: propertiesLabel,
300
+ title: propertiesTitle,
301
+ inDrawer: true,
302
+ children: inspector
303
+ })
304
+ })
305
+ }),
306
+ /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Toolbar, {
307
+ variant: "floating",
308
+ "aria-label": "Design tools",
309
+ className: "absolute start-4 bottom-4 w-max @4xl/design-canvas:inset-x-0 @4xl/design-canvas:mx-auto",
310
+ children: [
311
+ /* @__PURE__ */ jsx(ToolbarGroup, {
312
+ "aria-label": "Tools",
313
+ children: TOOLS.map((entry) => /* @__PURE__ */ jsx(DesignCanvasToolbarButton, {
314
+ label: entry.label,
315
+ hint: `${entry.label} · ${entry.shortcut}`,
316
+ pressed: tool === entry.tool,
317
+ onClick: () => setTool(entry.tool),
318
+ children: entry.icon
319
+ }, entry.tool))
320
+ }),
321
+ /* @__PURE__ */ jsx(ToolbarSeparator, { className: "@4xl/design-canvas:hidden" }),
322
+ /* @__PURE__ */ jsxs(ToolbarGroup, {
323
+ className: "@4xl/design-canvas:hidden",
324
+ children: [/* @__PURE__ */ jsx(DesignCanvasToolbarButton, {
325
+ label: openLayersLabel,
326
+ hint: openLayersLabel,
327
+ "aria-haspopup": "dialog",
328
+ "aria-expanded": layersOpen,
329
+ onClick: () => setLayersOpen(true),
330
+ children: /* @__PURE__ */ jsx(LayersIcon, {})
331
+ }), /* @__PURE__ */ jsx(DesignCanvasToolbarButton, {
332
+ label: openPropertiesLabel,
333
+ hint: openPropertiesLabel,
334
+ "aria-haspopup": "dialog",
335
+ "aria-expanded": propertiesOpen,
336
+ className: "@xl/design-canvas:hidden",
337
+ onClick: () => setPropertiesOpen(true),
338
+ children: /* @__PURE__ */ jsx(SlidersHorizontalIcon, {})
339
+ })]
340
+ })
341
+ ]
342
+ }) })
271
343
  ]
272
344
  });
273
345
  }
274
- function DesignCanvasLayerNode({ layer, selected, onSelect, onLayerChange }) {
346
+ function DesignCanvasPanel({ label, title, inDrawer = false, children }) {
347
+ const titleClassName = "flex h-11 shrink-0 items-center border-b px-3 text-caption font-medium";
348
+ const titleText = /* @__PURE__ */ jsx("span", {
349
+ className: "truncate",
350
+ title,
351
+ children: title
352
+ });
353
+ return /* @__PURE__ */ jsxs("aside", {
354
+ "aria-label": label,
355
+ className: "flex min-h-0 flex-1 flex-col",
356
+ children: [inDrawer ? /* @__PURE__ */ jsx(DrawerTitle, {
357
+ className: titleClassName,
358
+ children: titleText
359
+ }) : /* @__PURE__ */ jsx("h2", {
360
+ className: titleClassName,
361
+ children: titleText
362
+ }), /* @__PURE__ */ jsx(ScrollArea, {
363
+ className: "min-h-0 flex-1",
364
+ children
365
+ })]
366
+ });
367
+ }
368
+ function DesignCanvasLayerList({ layers, selectedLayerId, onSelect }) {
369
+ return /* @__PURE__ */ jsx("ul", {
370
+ className: "flex flex-col gap-0.5 p-2",
371
+ children: layers.toReversed().map((layer) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Button, {
372
+ variant: "ghost",
373
+ size: "sm",
374
+ active: layer.id === selectedLayerId,
375
+ "aria-pressed": layer.id === selectedLayerId,
376
+ className: "w-full justify-start [&_svg]:size-3.5 [&_svg]:text-muted-foreground",
377
+ onClick: () => onSelect(layer.id),
378
+ children: [LAYER_ICONS[layer.kind], /* @__PURE__ */ jsx("span", {
379
+ className: "truncate",
380
+ title: layer.name,
381
+ children: layer.name
382
+ })]
383
+ }) }, layer.id))
384
+ });
385
+ }
386
+ function DesignCanvasLayerNode({ layer, selected, onSelect, onKeyDown, onLayerChange }) {
275
387
  const fillColor = designCanvasFillColor(layer.fill);
388
+ const interactive = onSelect !== void 0;
276
389
  return /* @__PURE__ */ jsxs(InfiniteCanvasItem, {
277
390
  x: layer.x,
278
391
  y: layer.y,
279
392
  "aria-label": layer.name,
393
+ role: interactive ? "button" : void 0,
394
+ tabIndex: interactive ? 0 : void 0,
395
+ "aria-pressed": interactive ? selected : void 0,
396
+ "aria-keyshortcuts": interactive ? LAYER_KEY_SHORTCUTS : void 0,
280
397
  "data-selected": selected || void 0,
281
398
  className: "outline-primary data-selected:outline-2",
282
399
  style: {
@@ -286,6 +403,7 @@ function DesignCanvasLayerNode({ layer, selected, onSelect, onLayerChange }) {
286
403
  opacity: layer.opacity / 100
287
404
  },
288
405
  onPointerDown: onSelect,
406
+ onKeyDown,
289
407
  onPositionChange: onLayerChange && ((position) => onLayerChange({
290
408
  ...layer,
291
409
  x: Math.round(position.x),
@@ -293,7 +411,7 @@ function DesignCanvasLayerNode({ layer, selected, onSelect, onLayerChange }) {
293
411
  })),
294
412
  children: [
295
413
  layer.kind === "frame" ? /* @__PURE__ */ jsx("span", {
296
- className: "absolute bottom-full left-0 mb-1 whitespace-nowrap text-caption text-muted-foreground",
414
+ className: "absolute start-0 bottom-full mb-1 whitespace-nowrap text-caption text-muted-foreground",
297
415
  children: layer.name
298
416
  }) : null,
299
417
  layer.kind === "text" ? /* @__PURE__ */ jsx("p", {
@@ -308,7 +426,7 @@ function DesignCanvasLayerNode({ layer, selected, onSelect, onLayerChange }) {
308
426
  }
309
427
  }),
310
428
  selected ? /* @__PURE__ */ jsxs("span", {
311
- className: "absolute top-full left-1/2 mt-1.5 -translate-x-1/2 rounded-sm bg-primary px-1 text-[10px] leading-4 whitespace-nowrap text-primary-foreground tabular-nums",
429
+ className: "absolute inset-x-0 top-full mx-auto mt-1.5 w-max rounded-sm bg-primary px-1 text-micro whitespace-nowrap text-primary-foreground tabular-nums",
312
430
  children: [
313
431
  layer.width,
314
432
  " × ",
@@ -318,29 +436,17 @@ function DesignCanvasLayerNode({ layer, selected, onSelect, onLayerChange }) {
318
436
  ]
319
437
  });
320
438
  }
321
- function DesignCanvasToolbar({ tool, onToolChange }) {
322
- return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(Toolbar, {
323
- variant: "floating",
324
- "aria-label": "Design tools",
325
- className: "absolute bottom-4 left-4 w-max @4xl/design-canvas:left-1/2 @4xl/design-canvas:-translate-x-1/2",
326
- children: /* @__PURE__ */ jsx(ToolbarGroup, {
327
- "aria-label": "Tools",
328
- children: TOOLS.map((entry) => /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
329
- render: /* @__PURE__ */ jsx(ToolbarButton, {
330
- "aria-label": entry.label,
331
- iconOnly: true,
332
- "aria-pressed": tool === entry.tool,
333
- "data-pressed": tool === entry.tool ? "" : void 0,
334
- onClick: () => onToolChange(entry.tool)
335
- }),
336
- children: entry.icon
337
- }), /* @__PURE__ */ jsxs(TooltipContent, { children: [
338
- entry.label,
339
- " · ",
340
- entry.shortcut
341
- ] })] }, entry.tool))
342
- })
343
- }) });
439
+ function DesignCanvasToolbarButton({ label, hint, pressed, children, ...props }) {
440
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
441
+ render: /* @__PURE__ */ jsx(ToolbarButton, {
442
+ ...props,
443
+ "aria-label": label,
444
+ iconOnly: true,
445
+ "aria-pressed": pressed,
446
+ "data-pressed": pressed ? "" : void 0
447
+ }),
448
+ children
449
+ }), /* @__PURE__ */ jsx(TooltipContent, { children: hint })] });
344
450
  }
345
451
  //#endregion
346
452
  export { DesignCanvasBlock };
@@ -0,0 +1,28 @@
1
+ import { ChatComposer } from "../chat-composer.js";
2
+ import { ChatMessage } from "../chat-message.js";
3
+ import { ComponentProps, ReactNode } from "react";
4
+ //#region src/blocks/discussion.d.ts
5
+ export type DiscussionComposerProps = Omit<ComponentProps<typeof ChatComposer>, "submitKey" | "children"> & {
6
+ label: string;
7
+ placeholder?: string;
8
+ submitLabel?: ReactNode;
9
+ secondaryAction?: ReactNode;
10
+ hint?: ReactNode;
11
+ autoFocus?: boolean;
12
+ };
13
+ export declare function DiscussionComposer({ label, placeholder, submitLabel, secondaryAction, hint, autoFocus, ...props }: DiscussionComposerProps): import("react").JSX.Element;
14
+ export type DiscussionCommentProps = Omit<ComponentProps<typeof ChatMessage>, "from" | "layout" | "authorLabel" | "children"> & {
15
+ author: string;
16
+ avatar?: ReactNode;
17
+ sentAt: string;
18
+ timeLabel: ReactNode;
19
+ edited?: boolean;
20
+ children: ReactNode;
21
+ actions?: ReactNode;
22
+ onReply?: () => void;
23
+ replyLabel?: ReactNode;
24
+ replies?: ReactNode;
25
+ replyComposer?: ReactNode;
26
+ };
27
+ export declare function DiscussionComment({ author, avatar, sentAt, timeLabel, edited, children, actions, onReply, replyLabel, replies, replyComposer, ...props }: DiscussionCommentProps): import("react").JSX.Element;
28
+ //#endregion
@@ -0,0 +1,67 @@
1
+ "use client";
2
+ import { Button } from "../ui/button.js";
3
+ import { ChatComposer, ChatComposerShell, ChatComposerSubmit, ChatComposerTextarea, ChatComposerToolbar } from "../chat-composer.js";
4
+ import { ChatMessageReplies } from "../chat-message/social.js";
5
+ import { ChatMessage, ChatMessageActions, ChatMessageAuthor, ChatMessageAvatar, ChatMessageBody, ChatMessageContent, ChatMessageFooter, ChatMessageHeader, ChatMessageRow, ChatMessageTime } from "../chat-message.js";
6
+ import { Kbd, KbdGroup } from "../ui/kbd.js";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { CornerDownRightIcon } from "lucide-react";
9
+ //#region src/blocks/discussion.tsx
10
+ function DiscussionComposer({ label, placeholder, submitLabel = "Post", secondaryAction, hint = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(KbdGroup, { children: [/* @__PURE__ */ jsx(Kbd, { children: "⌘" }), /* @__PURE__ */ jsx(Kbd, { children: "Enter" })] }), /* @__PURE__ */ jsx("span", { children: "to post" })] }), autoFocus, ...props }) {
11
+ return /* @__PURE__ */ jsx(ChatComposer, {
12
+ submitKey: "mod-enter",
13
+ ...props,
14
+ children: /* @__PURE__ */ jsxs(ChatComposerShell, { children: [/* @__PURE__ */ jsx(ChatComposerTextarea, {
15
+ "aria-label": label,
16
+ placeholder,
17
+ autoFocus,
18
+ "aria-keyshortcuts": "Meta+Enter Control+Enter"
19
+ }), /* @__PURE__ */ jsxs(ChatComposerToolbar, { children: [/* @__PURE__ */ jsx("span", {
20
+ className: "flex min-w-0 items-center gap-1.5 text-caption text-muted-foreground",
21
+ children: hint
22
+ }), /* @__PURE__ */ jsxs("span", {
23
+ className: "flex items-center gap-2",
24
+ children: [secondaryAction, /* @__PURE__ */ jsx(ChatComposerSubmit, { children: submitLabel })]
25
+ })] })] })
26
+ });
27
+ }
28
+ function initials(name) {
29
+ return name.split(/\s+/).slice(0, 2).map((word) => word.charAt(0).toUpperCase()).join("");
30
+ }
31
+ function DiscussionComment({ author, avatar, sentAt, timeLabel, edited = false, children, actions, onReply, replyLabel = "Reply", replies, replyComposer, ...props }) {
32
+ const hasReplies = Boolean(replies) || Boolean(replyComposer);
33
+ return /* @__PURE__ */ jsx(ChatMessage, {
34
+ from: "participant",
35
+ layout: "flat",
36
+ authorLabel: author,
37
+ ...props,
38
+ children: /* @__PURE__ */ jsxs(ChatMessageRow, { children: [
39
+ /* @__PURE__ */ jsx(ChatMessageAvatar, { children: avatar ?? /* @__PURE__ */ jsx("span", {
40
+ "aria-hidden": "true",
41
+ children: initials(author)
42
+ }) }),
43
+ /* @__PURE__ */ jsxs(ChatMessageBody, { children: [
44
+ /* @__PURE__ */ jsxs(ChatMessageHeader, { children: [
45
+ /* @__PURE__ */ jsx(ChatMessageAuthor, { children: author }),
46
+ /* @__PURE__ */ jsx(ChatMessageTime, {
47
+ dateTime: sentAt,
48
+ children: timeLabel
49
+ }),
50
+ edited ? /* @__PURE__ */ jsx("span", { children: "(edited)" }) : null
51
+ ] }),
52
+ /* @__PURE__ */ jsx(ChatMessageContent, { children }),
53
+ onReply ? /* @__PURE__ */ jsx(ChatMessageFooter, { children: /* @__PURE__ */ jsxs(Button, {
54
+ variant: "ghost",
55
+ size: "xs",
56
+ onClick: onReply,
57
+ className: "-ms-2",
58
+ children: [/* @__PURE__ */ jsx(CornerDownRightIcon, { "aria-hidden": "true" }), replyLabel]
59
+ }) }) : null,
60
+ hasReplies ? /* @__PURE__ */ jsxs(ChatMessageReplies, { children: [replies, replyComposer] }) : null
61
+ ] }),
62
+ actions ? /* @__PURE__ */ jsx(ChatMessageActions, { children: actions }) : null
63
+ ] })
64
+ });
65
+ }
66
+ //#endregion
67
+ export { DiscussionComment, DiscussionComposer };
@@ -52,5 +52,6 @@ export declare function groupFileExplorerItems<T extends {
52
52
  label: string;
53
53
  items: T[];
54
54
  }[];
55
+ export declare function orderFileExplorerEntries(entries: readonly FileExplorerEntry[]): FileExplorerEntry[];
55
56
  export declare function searchFileExplorer(location: FileExplorerLocation, query: string): readonly FileExplorerSearchResult[];
56
57
  //#endregion
@@ -52,6 +52,9 @@ function groupFileExplorerItems(items) {
52
52
  items: groupedItems
53
53
  }));
54
54
  }
55
+ function orderFileExplorerEntries(entries) {
56
+ return groupFileExplorerItems(entries).flatMap((group) => group.items);
57
+ }
55
58
  function searchFileExplorer(location, query) {
56
59
  const normalizedQuery = query.trim().toLocaleLowerCase();
57
60
  if (!normalizedQuery) return [];
@@ -71,4 +74,4 @@ function searchFileExplorer(location, query) {
71
74
  return results;
72
75
  }
73
76
  //#endregion
74
- export { groupFileExplorerItems, resolveFileExplorer, searchFileExplorer };
77
+ export { groupFileExplorerItems, orderFileExplorerEntries, resolveFileExplorer, searchFileExplorer };
@@ -16,9 +16,17 @@ export type FileExplorerBlockProps = Omit<ComponentProps<"div">, "children" | "d
16
16
  sidebarTop?: ReactNode;
17
17
  sidebarFooter?: ReactNode;
18
18
  headerActions?: ReactNode;
19
+ headerMenuItems?: ReactNode;
19
20
  searchPlaceholder?: string | false;
21
+ searchLabel?: string;
22
+ clearSearchLabel?: string;
23
+ searchResultsLabel?: string;
24
+ searchStatusLabel?: (count: number, query: string) => string;
25
+ backLabel?: string;
26
+ moreActionsLabel?: string;
27
+ detailsLabel?: string;
20
28
  layout?: "viewport" | "contained";
21
29
  };
22
- export declare function FileExplorerBlock({ locations, activeLocationId, defaultActiveLocationId, selectedPath, defaultSelectedPath, searchValue, defaultSearchValue, onActiveLocationChange, onSelectedPathChange, onSearchValueChange, onOpenEntry, sidebarTop, sidebarFooter, headerActions, searchPlaceholder, layout, className, style, ...props }: FileExplorerBlockProps): import("react").JSX.Element;
30
+ export declare function FileExplorerBlock({ locations, activeLocationId, defaultActiveLocationId, selectedPath, defaultSelectedPath, searchValue, defaultSearchValue, onActiveLocationChange, onSelectedPathChange, onSearchValueChange, onOpenEntry, sidebarTop, sidebarFooter, headerActions, headerMenuItems, searchPlaceholder, searchLabel, clearSearchLabel, searchResultsLabel, searchStatusLabel, backLabel, moreActionsLabel, detailsLabel, layout, className, style, ...props }: FileExplorerBlockProps): import("react").JSX.Element;
23
31
  //#endregion
24
32
  export type { FileExplorerBreadcrumb, FileExplorerColumn, FileExplorerEntry, FileExplorerEntryDetail, FileExplorerLocation, FileExplorerResolution, FileExplorerSearchResult };