@devalok/shilp-sutra 0.56.0 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. package/MIGRATION.md +198 -0
  2. package/dist/_chunks/badge-group.js +75 -174
  3. package/dist/_chunks/badge-group.js.map +1 -1
  4. package/dist/_chunks/chat.js +270 -253
  5. package/dist/_chunks/chat.js.map +1 -1
  6. package/dist/_chunks/document-preview.js +1 -1
  7. package/dist/_chunks/document-preview.js.map +1 -1
  8. package/dist/_chunks/emoji-suggestion.js +1 -1
  9. package/dist/_chunks/emoji-suggestion.js.map +1 -1
  10. package/dist/_chunks/image-preview.js +71 -70
  11. package/dist/_chunks/image-preview.js.map +1 -1
  12. package/dist/_chunks/mention-suggestion.js +2 -2
  13. package/dist/_chunks/mention-suggestion.js.map +1 -1
  14. package/dist/_chunks/motion-preference.js +15 -0
  15. package/dist/_chunks/motion-preference.js.map +1 -0
  16. package/dist/_chunks/motion-provider.js +1 -1
  17. package/dist/_chunks/motion-provider.js.map +1 -1
  18. package/dist/_chunks/oauth-button.js +1 -1
  19. package/dist/_chunks/oauth-button.js.map +1 -1
  20. package/dist/_chunks/popover.js +50 -49
  21. package/dist/_chunks/popover.js.map +1 -1
  22. package/dist/_chunks/primitives-internal.js +29 -29
  23. package/dist/_chunks/primitives-internal.js.map +1 -1
  24. package/dist/_chunks/shared.js +48 -47
  25. package/dist/_chunks/shared.js.map +1 -1
  26. package/dist/_chunks/success.js +36 -36
  27. package/dist/_chunks/success.js.map +1 -1
  28. package/dist/_chunks/tree-view.js +1 -1
  29. package/dist/_chunks/tree-view.js.map +1 -1
  30. package/dist/_chunks/use-calendar.js +4 -4
  31. package/dist/_chunks/use-calendar.js.map +1 -1
  32. package/dist/ai/block-renderer.js +8 -8
  33. package/dist/ai/blocks/text.js +1 -1
  34. package/dist/ai/blocks/text.js.map +1 -1
  35. package/dist/ai/command-bar.js +67 -67
  36. package/dist/ai/command-bar.js.map +1 -1
  37. package/dist/ai/conversation.js +35 -35
  38. package/dist/ai/conversation.js.map +1 -1
  39. package/dist/ai/index.js +4 -4
  40. package/dist/composed/activity-feed.d.ts.map +1 -1
  41. package/dist/composed/activity-feed.js +109 -108
  42. package/dist/composed/activity-feed.js.map +1 -1
  43. package/dist/composed/avatar-group.d.ts +7 -2
  44. package/dist/composed/avatar-group.d.ts.map +1 -1
  45. package/dist/composed/avatar-group.js +3 -3
  46. package/dist/composed/avatar-group.js.map +1 -1
  47. package/dist/composed/command-palette.js +137 -137
  48. package/dist/composed/command-palette.js.map +1 -1
  49. package/dist/composed/content-card.js +2 -2
  50. package/dist/composed/content-card.js.map +1 -1
  51. package/dist/composed/date-picker/index.js +9 -9
  52. package/dist/composed/date-picker/index.js.map +1 -1
  53. package/dist/composed/diff.d.ts +23 -2
  54. package/dist/composed/diff.d.ts.map +1 -1
  55. package/dist/composed/diff.js +341 -260
  56. package/dist/composed/diff.js.map +1 -1
  57. package/dist/composed/emoji-picker.js +3 -3
  58. package/dist/composed/emoji-picker.js.map +1 -1
  59. package/dist/composed/empty-state.js +4 -4
  60. package/dist/composed/error-boundary.js +2 -2
  61. package/dist/composed/error-boundary.js.map +1 -1
  62. package/dist/composed/file-preview/image-preview.d.ts.map +1 -1
  63. package/dist/composed/file-preview/shared.d.ts.map +1 -1
  64. package/dist/composed/file-preview/video-preview.d.ts.map +1 -1
  65. package/dist/composed/file-preview.js +152 -151
  66. package/dist/composed/file-preview.js.map +1 -1
  67. package/dist/composed/filter-bar.d.ts.map +1 -1
  68. package/dist/composed/filter-bar.js +53 -52
  69. package/dist/composed/filter-bar.js.map +1 -1
  70. package/dist/composed/form-section.d.ts.map +1 -1
  71. package/dist/composed/form-section.js +38 -37
  72. package/dist/composed/form-section.js.map +1 -1
  73. package/dist/composed/inline-edit.js +1 -1
  74. package/dist/composed/inline-edit.js.map +1 -1
  75. package/dist/composed/loading-skeleton.js +3 -3
  76. package/dist/composed/loading-skeleton.js.map +1 -1
  77. package/dist/composed/master-detail.d.ts.map +1 -1
  78. package/dist/composed/master-detail.js +1 -1
  79. package/dist/composed/master-detail.js.map +1 -1
  80. package/dist/composed/member-picker.js +1 -1
  81. package/dist/composed/member-picker.js.map +1 -1
  82. package/dist/composed/multi-select-popover.d.ts.map +1 -1
  83. package/dist/composed/multi-select-popover.js +109 -108
  84. package/dist/composed/multi-select-popover.js.map +1 -1
  85. package/dist/composed/page-skeletons.js +4 -4
  86. package/dist/composed/page-skeletons.js.map +1 -1
  87. package/dist/composed/responsive-modal.js +1 -1
  88. package/dist/composed/responsive-modal.js.map +1 -1
  89. package/dist/composed/rich-chat-input/attachment-strip.d.ts.map +1 -1
  90. package/dist/composed/rich-chat-input/reply-banner.d.ts.map +1 -1
  91. package/dist/composed/rich-chat-input/schedule-send.d.ts.map +1 -1
  92. package/dist/composed/rich-chat-input.d.ts.map +1 -1
  93. package/dist/composed/rich-chat-input.js +473 -472
  94. package/dist/composed/rich-chat-input.js.map +1 -1
  95. package/dist/composed/rich-text-editor.js +6 -6
  96. package/dist/composed/rich-text-editor.js.map +1 -1
  97. package/dist/composed/schedule-view.js +5 -5
  98. package/dist/composed/schedule-view.js.map +1 -1
  99. package/dist/composed/status-badge.d.ts.map +1 -1
  100. package/dist/composed/status-badge.js +29 -28
  101. package/dist/composed/status-badge.js.map +1 -1
  102. package/dist/hooks/index.d.ts +1 -0
  103. package/dist/hooks/index.d.ts.map +1 -1
  104. package/dist/hooks/index.js +4 -3
  105. package/dist/hooks/use-container-size.d.ts +18 -0
  106. package/dist/hooks/use-container-size.d.ts.map +1 -0
  107. package/dist/hooks/use-container-size.js +28 -0
  108. package/dist/hooks/use-container-size.js.map +1 -0
  109. package/dist/motion/index.d.ts +1 -0
  110. package/dist/motion/index.d.ts.map +1 -1
  111. package/dist/motion/index.js +2 -15
  112. package/dist/motion/motion-preference.d.ts +36 -0
  113. package/dist/motion/motion-preference.d.ts.map +1 -0
  114. package/dist/motion/motion-provider.d.ts +2 -1
  115. package/dist/motion/motion-provider.d.ts.map +1 -1
  116. package/dist/motion/primitives-index.js +103 -102
  117. package/dist/motion/primitives-index.js.map +1 -1
  118. package/dist/motion/primitives.d.ts.map +1 -1
  119. package/dist/shell/app-shell.d.ts +101 -0
  120. package/dist/shell/app-shell.d.ts.map +1 -0
  121. package/dist/shell/app-shell.js +76 -0
  122. package/dist/shell/app-shell.js.map +1 -0
  123. package/dist/shell/bottom-navbar.js +21 -21
  124. package/dist/shell/bottom-navbar.js.map +1 -1
  125. package/dist/shell/index.d.ts +2 -1
  126. package/dist/shell/index.d.ts.map +1 -1
  127. package/dist/shell/index.js +6 -5
  128. package/dist/shell/notification-center.d.ts +17 -0
  129. package/dist/shell/notification-center.d.ts.map +1 -1
  130. package/dist/shell/notification-center.js +110 -105
  131. package/dist/shell/notification-center.js.map +1 -1
  132. package/dist/shell/notification-preferences.js +1 -1
  133. package/dist/shell/notification-preferences.js.map +1 -1
  134. package/dist/shell/top-bar.js +7 -7
  135. package/dist/shell/top-bar.js.map +1 -1
  136. package/dist/tokens/generate-scale.d.ts +49 -0
  137. package/dist/tokens/generate-scale.d.ts.map +1 -1
  138. package/dist/tokens/index.css +1 -0
  139. package/dist/tokens/palettes.css +292 -0
  140. package/dist/tokens/primitives.css +29 -26
  141. package/dist/tokens/semantic.css +170 -47
  142. package/dist/tokens/shilp-sutra.css +1 -0
  143. package/dist/tokens/utilities.css +10 -7
  144. package/dist/tokens/variants.css +1 -1
  145. package/dist/ui/accordion.d.ts.map +1 -1
  146. package/dist/ui/accordion.js +27 -26
  147. package/dist/ui/accordion.js.map +1 -1
  148. package/dist/ui/alert-dialog.d.ts.map +1 -1
  149. package/dist/ui/alert-dialog.js +60 -59
  150. package/dist/ui/alert-dialog.js.map +1 -1
  151. package/dist/ui/alert.d.ts.map +1 -1
  152. package/dist/ui/alert.js +55 -113
  153. package/dist/ui/alert.js.map +1 -1
  154. package/dist/ui/autocomplete.js +80 -80
  155. package/dist/ui/autocomplete.js.map +1 -1
  156. package/dist/ui/avatar.d.ts.map +1 -1
  157. package/dist/ui/avatar.js +71 -70
  158. package/dist/ui/avatar.js.map +1 -1
  159. package/dist/ui/badge-indicator.d.ts +4 -8
  160. package/dist/ui/badge-indicator.d.ts.map +1 -1
  161. package/dist/ui/badge-indicator.js +3 -8
  162. package/dist/ui/badge-indicator.js.map +1 -1
  163. package/dist/ui/badge.d.ts +55 -34
  164. package/dist/ui/badge.d.ts.map +1 -1
  165. package/dist/ui/banner.d.ts.map +1 -1
  166. package/dist/ui/banner.js +43 -41
  167. package/dist/ui/banner.js.map +1 -1
  168. package/dist/ui/button-group.d.ts.map +1 -1
  169. package/dist/ui/button-group.js +3 -23
  170. package/dist/ui/button-group.js.map +1 -1
  171. package/dist/ui/button.d.ts +10 -1
  172. package/dist/ui/button.d.ts.map +1 -1
  173. package/dist/ui/button.js +79 -212
  174. package/dist/ui/button.js.map +1 -1
  175. package/dist/ui/card.d.ts.map +1 -1
  176. package/dist/ui/card.js +78 -75
  177. package/dist/ui/card.js.map +1 -1
  178. package/dist/ui/charts/radar-chart.d.ts.map +1 -1
  179. package/dist/ui/charts/radar-chart.js +1 -1
  180. package/dist/ui/charts/radar-chart.js.map +1 -1
  181. package/dist/ui/chat/date-separator.d.ts +8 -1
  182. package/dist/ui/chat/date-separator.d.ts.map +1 -1
  183. package/dist/ui/chat/message-list.d.ts.map +1 -1
  184. package/dist/ui/chat/message.d.ts.map +1 -1
  185. package/dist/ui/chat/typing-indicator.d.ts.map +1 -1
  186. package/dist/ui/checkbox.js +1 -1
  187. package/dist/ui/checkbox.js.map +1 -1
  188. package/dist/ui/code.js +2 -2
  189. package/dist/ui/code.js.map +1 -1
  190. package/dist/ui/color-input.d.ts.map +1 -1
  191. package/dist/ui/color-input.js +151 -150
  192. package/dist/ui/color-input.js.map +1 -1
  193. package/dist/ui/combobox.d.ts +14 -0
  194. package/dist/ui/combobox.d.ts.map +1 -1
  195. package/dist/ui/combobox.js +156 -152
  196. package/dist/ui/combobox.js.map +1 -1
  197. package/dist/ui/context-menu.d.ts.map +1 -1
  198. package/dist/ui/context-menu.js +70 -69
  199. package/dist/ui/context-menu.js.map +1 -1
  200. package/dist/ui/data-table-body.d.ts +3 -1
  201. package/dist/ui/data-table-body.d.ts.map +1 -1
  202. package/dist/ui/data-table-body.js +93 -92
  203. package/dist/ui/data-table-body.js.map +1 -1
  204. package/dist/ui/data-table-bulk-actions.d.ts +7 -1
  205. package/dist/ui/data-table-bulk-actions.d.ts.map +1 -1
  206. package/dist/ui/data-table-bulk-actions.js +14 -8
  207. package/dist/ui/data-table-bulk-actions.js.map +1 -1
  208. package/dist/ui/data-table-card.d.ts.map +1 -1
  209. package/dist/ui/data-table-card.js +66 -47
  210. package/dist/ui/data-table-card.js.map +1 -1
  211. package/dist/ui/data-table-context.d.ts +4 -0
  212. package/dist/ui/data-table-context.d.ts.map +1 -1
  213. package/dist/ui/data-table-context.js +2 -2
  214. package/dist/ui/data-table-context.js.map +1 -1
  215. package/dist/ui/data-table-header.d.ts.map +1 -1
  216. package/dist/ui/data-table-header.js +50 -46
  217. package/dist/ui/data-table-header.js.map +1 -1
  218. package/dist/ui/data-table-pagination.js +3 -3
  219. package/dist/ui/data-table-pagination.js.map +1 -1
  220. package/dist/ui/data-table-toolbar.d.ts +11 -1
  221. package/dist/ui/data-table-toolbar.d.ts.map +1 -1
  222. package/dist/ui/data-table-toolbar.js +7 -7
  223. package/dist/ui/data-table-toolbar.js.map +1 -1
  224. package/dist/ui/data-table.d.ts +52 -5
  225. package/dist/ui/data-table.d.ts.map +1 -1
  226. package/dist/ui/data-table.js +181 -169
  227. package/dist/ui/data-table.js.map +1 -1
  228. package/dist/ui/dialog.d.ts.map +1 -1
  229. package/dist/ui/dialog.js +62 -61
  230. package/dist/ui/dialog.js.map +1 -1
  231. package/dist/ui/dot.d.ts.map +1 -1
  232. package/dist/ui/dot.js +10 -41
  233. package/dist/ui/dot.js.map +1 -1
  234. package/dist/ui/dropdown-menu.d.ts.map +1 -1
  235. package/dist/ui/dropdown-menu.js +79 -78
  236. package/dist/ui/dropdown-menu.js.map +1 -1
  237. package/dist/ui/file-upload.d.ts.map +1 -1
  238. package/dist/ui/file-upload.js +117 -116
  239. package/dist/ui/file-upload.js.map +1 -1
  240. package/dist/ui/form.d.ts.map +1 -1
  241. package/dist/ui/form.js +27 -26
  242. package/dist/ui/form.js.map +1 -1
  243. package/dist/ui/hover-card.d.ts.map +1 -1
  244. package/dist/ui/hover-card.js +26 -25
  245. package/dist/ui/hover-card.js.map +1 -1
  246. package/dist/ui/icon.js +7 -7
  247. package/dist/ui/index.d.ts +2 -2
  248. package/dist/ui/index.d.ts.map +1 -1
  249. package/dist/ui/index.js +3 -3
  250. package/dist/ui/index.js.map +1 -1
  251. package/dist/ui/input-otp.js +1 -1
  252. package/dist/ui/input-otp.js.map +1 -1
  253. package/dist/ui/input.js +8 -8
  254. package/dist/ui/input.js.map +1 -1
  255. package/dist/ui/menubar.d.ts.map +1 -1
  256. package/dist/ui/menubar.js +73 -72
  257. package/dist/ui/menubar.js.map +1 -1
  258. package/dist/ui/navigation-menu.d.ts.map +1 -1
  259. package/dist/ui/navigation-menu.js +80 -79
  260. package/dist/ui/navigation-menu.js.map +1 -1
  261. package/dist/ui/number-input.js +3 -3
  262. package/dist/ui/number-input.js.map +1 -1
  263. package/dist/ui/pagination.js +1 -1
  264. package/dist/ui/pagination.js.map +1 -1
  265. package/dist/ui/popover.d.ts.map +1 -1
  266. package/dist/ui/progress-ring.js +2 -2
  267. package/dist/ui/progress-ring.js.map +1 -1
  268. package/dist/ui/progress.d.ts.map +1 -1
  269. package/dist/ui/progress.js +82 -74
  270. package/dist/ui/progress.js.map +1 -1
  271. package/dist/ui/radio.d.ts.map +1 -1
  272. package/dist/ui/radio.js +32 -31
  273. package/dist/ui/radio.js.map +1 -1
  274. package/dist/ui/search-input.d.ts.map +1 -1
  275. package/dist/ui/search-input.js +28 -27
  276. package/dist/ui/search-input.js.map +1 -1
  277. package/dist/ui/select.d.ts.map +1 -1
  278. package/dist/ui/select.js +67 -66
  279. package/dist/ui/select.js.map +1 -1
  280. package/dist/ui/sheet.js +1 -1
  281. package/dist/ui/sheet.js.map +1 -1
  282. package/dist/ui/sidebar.d.ts.map +1 -1
  283. package/dist/ui/sidebar.js +14 -14
  284. package/dist/ui/sidebar.js.map +1 -1
  285. package/dist/ui/slider.d.ts +63 -9
  286. package/dist/ui/slider.d.ts.map +1 -1
  287. package/dist/ui/slider.js +75 -33
  288. package/dist/ui/slider.js.map +1 -1
  289. package/dist/ui/split-button.d.ts +8 -2
  290. package/dist/ui/split-button.d.ts.map +1 -1
  291. package/dist/ui/split-button.js +49 -95
  292. package/dist/ui/split-button.js.map +1 -1
  293. package/dist/ui/stat-card.d.ts.map +1 -1
  294. package/dist/ui/stat-card.js +89 -88
  295. package/dist/ui/stat-card.js.map +1 -1
  296. package/dist/ui/stat-flash.js +16 -16
  297. package/dist/ui/stepper.d.ts.map +1 -1
  298. package/dist/ui/stepper.js +63 -62
  299. package/dist/ui/stepper.js.map +1 -1
  300. package/dist/ui/surface.d.ts.map +1 -1
  301. package/dist/ui/surface.js +2 -2
  302. package/dist/ui/surface.js.map +1 -1
  303. package/dist/ui/switch.js +1 -1
  304. package/dist/ui/switch.js.map +1 -1
  305. package/dist/ui/table.js +3 -3
  306. package/dist/ui/table.js.map +1 -1
  307. package/dist/ui/tabs.d.ts.map +1 -1
  308. package/dist/ui/tabs.js +68 -67
  309. package/dist/ui/tabs.js.map +1 -1
  310. package/dist/ui/textarea.js +5 -5
  311. package/dist/ui/textarea.js.map +1 -1
  312. package/dist/ui/toast.d.ts.map +1 -1
  313. package/dist/ui/toast.js +196 -195
  314. package/dist/ui/toast.js.map +1 -1
  315. package/dist/ui/toggle.d.ts.map +1 -1
  316. package/dist/ui/toggle.js +26 -24
  317. package/dist/ui/toggle.js.map +1 -1
  318. package/dist/ui/tooltip.d.ts.map +1 -1
  319. package/dist/ui/tooltip.js +37 -36
  320. package/dist/ui/tooltip.js.map +1 -1
  321. package/dist/ui/tree-view/tree-item.d.ts.map +1 -1
  322. package/docs/components/composed/avatar-group.md +4 -4
  323. package/docs/components/composed/diff.md +10 -2
  324. package/docs/components/composed/schedule-view.md +1 -1
  325. package/docs/components/shell/app-shell.md +132 -0
  326. package/docs/components/ui/avatar.md +1 -1
  327. package/docs/components/ui/button.md +1 -1
  328. package/docs/components/ui/chat.md +7 -1
  329. package/docs/components/ui/color-swatch.md +1 -1
  330. package/docs/components/ui/data-table-toolbar.md +6 -2
  331. package/docs/components/ui/data-table.md +41 -7
  332. package/docs/components/ui/dot.md +1 -1
  333. package/docs/components/ui/progress.md +1 -0
  334. package/docs/components/ui/surface.md +3 -3
  335. package/docs/components/ui/table.md +2 -2
  336. package/docs/recipes/customize-brand.md +58 -0
  337. package/docs/recipes/install-astro.md +1 -0
  338. package/docs/recipes/install-next-app-router.md +1 -0
  339. package/docs/recipes/install-next-pages.md +22 -1
  340. package/docs/recipes/install-remix.md +1 -0
  341. package/docs/recipes/install-tanstack-start.md +1 -0
  342. package/docs/recipes/install-vite.md +2 -0
  343. package/docs/recipes/server-components.md +7 -4
  344. package/docs/recipes/troubleshoot.md +1 -0
  345. package/llms.txt +2 -1
  346. package/make-kit/Guidelines.md +2 -2
  347. package/make-kit/components/button.md +1 -1
  348. package/make-kit/components/card.md +6 -6
  349. package/make-kit/components/surface.md +4 -4
  350. package/make-kit/foundations/color.md +4 -4
  351. package/make-kit/foundations/dark-mode.md +1 -1
  352. package/make-kit/foundations/radius.md +1 -1
  353. package/make-kit/foundations/surfaces.md +9 -9
  354. package/mcp-manifest.json +358 -35
  355. package/package.json +8 -4
  356. package/skill/SKILL.md +12 -6
  357. package/skill/references/components.md +2 -1
  358. package/skill/references/customize-brand.md +58 -0
  359. package/skill/references/server-components.md +7 -4
  360. package/skill/references/setup-astro.md +1 -0
  361. package/skill/references/setup-next-app-router.md +1 -0
  362. package/skill/references/setup-next-pages.md +22 -1
  363. package/skill/references/setup-remix.md +1 -0
  364. package/skill/references/setup-tanstack-start.md +1 -0
  365. package/skill/references/setup-vite.md +2 -0
  366. package/skill/references/troubleshoot.md +1 -0
  367. package/dist/motion/check-motion-provider.d.ts +0 -2
  368. package/dist/motion/check-motion-provider.d.ts.map +0 -1
  369. package/dist/motion/index.js.map +0 -1
  370. package/dist/primitives/react-toast.d.ts +0 -120
  371. package/dist/ui/charts/_internal/scales.d.ts +0 -5
  372. package/dist/ui/charts/_internal/scales.d.ts.map +0 -1
  373. package/dist/ui/lib/slot.d.ts +0 -8
  374. package/dist/ui/lib/slot.d.ts.map +0 -1
@@ -28,8 +28,8 @@ var H = [
28
28
  "[&_p]:mb-ds-02b [&_p]:text-surface-fg-muted",
29
29
  "[&_ul]:ml-ds-05 [&_ul]:list-disc [&_ol]:ml-ds-05 [&_ol]:list-decimal",
30
30
  "[&_li]:text-surface-fg-muted",
31
- "[&_code]:rounded [&_code]:bg-surface-raised [&_code]:px-ds-02b [&_code]:py-ds-01 [&_code]:text-body-md [&_code]:text-accent-11",
32
- "[&_pre]:rounded-surface [&_pre]:bg-surface-raised [&_pre]:p-ds-04",
31
+ "[&_code]:rounded [&_code]:bg-surface-sunken [&_code]:px-ds-02b [&_code]:py-ds-01 [&_code]:text-body-md [&_code]:text-accent-11",
32
+ "[&_pre]:rounded-surface [&_pre]:bg-surface-sunken [&_pre]:p-ds-04",
33
33
  "[&_strong]:font-semibold [&_strong]:text-surface-fg",
34
34
  "[&_blockquote]:border-l-[3px] [&_blockquote]:border-accent-6 [&_blockquote]:pl-ds-04 [&_blockquote]:italic [&_blockquote]:text-surface-fg-subtle",
35
35
  "[&_mark]:rounded-xs [&_mark]:bg-warning-3 [&_mark]:px-[2px]",
@@ -47,7 +47,7 @@ function U({ onClick: t, isActive: n = !1, disabled: r = !1, title: i, children:
47
47
  title: i,
48
48
  "aria-label": i,
49
49
  "aria-pressed": n,
50
- className: e("inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control transition-colors duration-fast-01 ease-productive-standard", "hover:bg-surface-raised-hover", "disabled:pointer-events-none disabled:opacity-action-disabled", n ? "bg-surface-raised-hover text-accent-11" : "text-surface-fg-subtle"),
50
+ className: e("inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control transition-colors duration-fast-01 ease-productive-standard", "hover:bg-surface-panel-hover", "disabled:pointer-events-none disabled:opacity-action-disabled", n ? "bg-surface-panel-hover text-accent-11" : "text-surface-fg-subtle"),
51
51
  children: a
52
52
  });
53
53
  }
@@ -88,7 +88,7 @@ function W({ editor: e }) {
88
88
  t.key === "Escape" && (i(!1), o(""), e.commands.focus());
89
89
  },
90
90
  placeholder: "https://...",
91
- className: "h-ds-sm w-[240px] rounded-control-inner border border-surface-border-strong bg-surface-overlay px-ds-03 text-body-sm text-surface-fg focus:border-accent-7 focus:outline-hidden"
91
+ className: "h-ds-sm w-[240px] rounded-control-inner border border-surface-border-interactive bg-surface-panel-hover px-ds-03 text-body-sm text-surface-fg focus:border-accent-7 focus:outline-hidden"
92
92
  }), /* @__PURE__ */ u(n, {
93
93
  type: "submit",
94
94
  variant: "solid",
@@ -598,7 +598,7 @@ function Q() {
598
598
  onChange: (e) => r(e.target.value),
599
599
  spellCheck: !1,
600
600
  "aria-label": "Markdown source",
601
- className: "block min-h-[120px] w-full resize-y bg-surface-raised px-ds-04 py-ds-04 font-mono text-body-sm leading-ds-relaxed text-surface-fg focus:outline-hidden"
601
+ className: "block min-h-[120px] w-full resize-y bg-surface-panel px-ds-04 py-ds-04 font-mono text-body-sm leading-ds-relaxed text-surface-fg focus:outline-hidden"
602
602
  })
603
603
  }, "source") : /* @__PURE__ */ u(M.div, {
604
604
  initial: i,
@@ -649,7 +649,7 @@ var ce = c.forwardRef(function(t, n) {
649
649
  ref: n,
650
650
  ...t,
651
651
  children: /* @__PURE__ */ d("div", {
652
- className: e("overflow-hidden rounded-surface border border-surface-border-strong bg-surface-raised", "transition-colors ease-productive-standard focus-within:border-surface-border-strong"),
652
+ className: e("overflow-hidden rounded-surface border border-surface-border-strong bg-surface-panel", "transition-colors ease-productive-standard focus-within:border-surface-border-strong"),
653
653
  children: [/* @__PURE__ */ u(Z, { trailing: t.sourceToggle ? /* @__PURE__ */ u($, {}) : void 0 }), /* @__PURE__ */ u(Q, {})]
654
654
  })
655
655
  });
@@ -1 +1 @@
1
- {"version":3,"file":"rich-text-editor.js","names":[],"sources":["../../src/composed/rich-text-editor.tsx"],"sourcesContent":["'use client'\n\nimport {\n IconAlignCenter,\n IconAlignLeft,\n IconAlignRight,\n IconArrowBackUp,\n IconArrowForwardUp,\n IconBlockquote,\n IconBold,\n IconCode,\n IconEye,\n IconH2,\n IconH3,\n IconHighlight,\n IconItalic,\n IconLineDashed,\n IconLink,\n IconList,\n IconListCheck,\n IconListNumbers,\n IconMoodSmile,\n IconPaperclip,\n IconPhoto,\n IconStrikethrough,\n IconUnderline,\n} from '@tabler/icons-react'\nimport Highlight from '@tiptap/extension-highlight'\nimport Image from '@tiptap/extension-image'\nimport { ListKit } from '@tiptap/extension-list'\nimport Mention from '@tiptap/extension-mention'\nimport TextAlign from '@tiptap/extension-text-align'\nimport { Placeholder } from '@tiptap/extensions'\nimport { Markdown } from '@tiptap/markdown'\nimport { type Editor,EditorContent, useEditor, useEditorState } from '@tiptap/react'\nimport StarterKit from '@tiptap/starter-kit'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Button } from '../ui/button'\nimport { Icon } from '../ui/icon'\nimport { MENTION_TOKEN_CLASS } from '../ui/lib/mention'\nimport { cn } from '../ui/lib/utils'\nimport type { EmojiData, EmojiSet } from './emoji-picker'\nimport { EmojiNode } from './extensions/emoji-node'\nimport { createEmojiSuggestion } from './extensions/emoji-suggestion'\nimport { FileAttachment } from './extensions/file-attachment'\nimport { createSuggestionRenderer } from './extensions/mention-suggestion'\n\nconst PROSE_CLASSES = [\n 'prose prose-sm max-w-none',\n 'font-body text-body-md leading-relaxed text-surface-fg',\n '[&_h2]:text-heading-sm [&_h2]:mb-ds-03 [&_h2]:mt-ds-05 [&_h2]:text-surface-fg',\n '[&_h3]:text-body-lg [&_h3]:font-semibold [&_h3]:mb-ds-02b [&_h3]:mt-ds-04 [&_h3]:text-surface-fg',\n '[&_p]:mb-ds-02b [&_p]:text-surface-fg-muted',\n '[&_ul]:ml-ds-05 [&_ul]:list-disc [&_ol]:ml-ds-05 [&_ol]:list-decimal',\n '[&_li]:text-surface-fg-muted',\n '[&_code]:rounded [&_code]:bg-surface-raised [&_code]:px-ds-02b [&_code]:py-ds-01 [&_code]:text-body-md [&_code]:text-accent-11',\n '[&_pre]:rounded-surface [&_pre]:bg-surface-raised [&_pre]:p-ds-04',\n '[&_strong]:font-semibold [&_strong]:text-surface-fg',\n // slop-allow: side-stripe — blockquote left-rule is standard typography, not a card accent-rail\n '[&_blockquote]:border-l-[3px] [&_blockquote]:border-accent-6 [&_blockquote]:pl-ds-04 [&_blockquote]:italic [&_blockquote]:text-surface-fg-subtle',\n '[&_mark]:rounded-xs [&_mark]:bg-warning-3 [&_mark]:px-[2px]',\n '[&_ul[data-type=\"taskList\"]]:ml-0 [&_ul[data-type=\"taskList\"]]:list-none [&_li[data-type=\"taskItem\"]]:flex [&_li[data-type=\"taskItem\"]]:items-start [&_li[data-type=\"taskItem\"]]:gap-ds-02',\n '[&_hr]:my-ds-04 [&_hr]:border-surface-border-strong',\n '[&_a]:text-accent-11 [&_a]:underline [&_a]:decoration-accent-6 hover:[&_a]:decoration-accent-11',\n '[&_img]:max-w-full [&_img]:rounded-control [&_img]:my-ds-03',\n MENTION_TOKEN_CLASS,\n] as const\n\ninterface ToolbarButtonProps {\n onClick: () => void\n isActive?: boolean\n disabled?: boolean\n title: string\n children: React.ReactNode\n}\n\nfunction ToolbarButton({\n onClick,\n isActive = false,\n disabled = false,\n title,\n children,\n}: ToolbarButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n title={title}\n aria-label={title}\n aria-pressed={isActive}\n className={cn(\n 'inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control transition-colors duration-fast-01 ease-productive-standard',\n 'hover:bg-surface-raised-hover',\n 'disabled:pointer-events-none disabled:opacity-action-disabled',\n isActive\n ? 'bg-surface-raised-hover text-accent-11'\n : 'text-surface-fg-subtle',\n )}\n >\n {children}\n </button>\n )\n}\n\nfunction LinkButton({ editor }: { editor: Editor }) {\n const [showInput, setShowInput] = React.useState(false)\n const [url, setUrl] = React.useState('')\n const inputRef = React.useRef<HTMLInputElement>(null)\n const { isLink } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isLink: e.isActive('link') }),\n })\n\n const handleToggle = () => {\n if (isLink) {\n editor.chain().focus().unsetLink().run()\n return\n }\n const previousUrl = editor.getAttributes('link').href || ''\n setUrl(previousUrl)\n setShowInput(true)\n setTimeout(() => inputRef.current?.focus(), 0)\n }\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault()\n if (url.trim()) {\n editor.chain().focus().setLink({ href: url.trim() }).run()\n }\n setShowInput(false)\n setUrl('')\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n setShowInput(false)\n setUrl('')\n editor.commands.focus()\n }\n }\n\n return (\n <div className=\"relative\">\n <ToolbarButton onClick={handleToggle} isActive={isLink} title=\"Link\">\n <Icon icon={IconLink} size=\"sm\" />\n </ToolbarButton>\n {showInput && (\n <form\n onSubmit={handleSubmit}\n aria-label=\"Edit link URL\"\n className=\"absolute left-0 top-full z-popover mt-ds-01 flex items-center gap-ds-02 rounded-control bg-surface-overlay p-ds-02 shadow-raised-hover\"\n >\n <input\n ref={inputRef}\n type=\"url\"\n value={url}\n onChange={(e) => setUrl(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"https://...\"\n className=\"h-ds-sm w-[240px] rounded-control-inner border border-surface-border-strong bg-surface-overlay px-ds-03 text-body-sm text-surface-fg focus:border-accent-7 focus:outline-hidden\"\n />\n <Button type=\"submit\" variant=\"solid\" size=\"sm\">\n Apply\n </Button>\n </form>\n )}\n </div>\n )\n}\n\nfunction ToolbarDivider() {\n return <div className=\"mx-ds-02 h-ds-05 w-px bg-surface-border\" />\n}\n\nfunction Toolbar({ editor, toolbar, onImageClick, onFileClick, onEmojiClick, trailing, showControls = true }: {\n editor: Editor\n toolbar?: ToolbarItem[]\n onImageClick?: () => void\n onFileClick?: () => void\n onEmojiClick?: () => void\n /** Right-aligned content (e.g. a source-view toggle). */\n trailing?: React.ReactNode\n /** Hide the formatting controls, keeping only `trailing`. @default true */\n showControls?: boolean\n}) {\n // v3: useEditorState subscribes to specific state slices so the toolbar\n // re-renders only when active-state or can-undo/redo actually changes.\n const state = useEditorState({\n editor,\n selector: ({ editor: e }) => ({\n isBold: e.isActive('bold'),\n isItalic: e.isActive('italic'),\n isUnderline: e.isActive('underline'),\n isStrike: e.isActive('strike'),\n isHighlight: e.isActive('highlight'),\n isH2: e.isActive('heading', { level: 2 }),\n isH3: e.isActive('heading', { level: 3 }),\n isBlockquote: e.isActive('blockquote'),\n isBulletList: e.isActive('bulletList'),\n isOrderedList: e.isActive('orderedList'),\n isTaskList: e.isActive('taskList'),\n isCodeBlock: e.isActive('codeBlock'),\n isLink: e.isActive('link'),\n isAlignLeft: e.isActive({ textAlign: 'left' }),\n isAlignCenter: e.isActive({ textAlign: 'center' }),\n isAlignRight: e.isActive({ textAlign: 'right' }),\n canUndo: e.can().undo(),\n canRedo: e.can().redo(),\n }),\n })\n\n const show = (item: ToolbarItem) => !toolbar || toolbar.includes(item)\n\n // Each group is an array of ToolbarItem names that belong to it.\n // A divider renders between two adjacent groups only if both have at least one visible item.\n const hasInline = show('bold') || show('italic') || show('underline') || show('strike') || show('highlight')\n const hasBlock = show('h2') || show('h3') || show('blockquote')\n const hasList = show('bulletList') || show('orderedList') || show('taskList') || show('codeBlock')\n const hasMedia = show('link') || (!!onImageClick && show('image')) || (!!onFileClick && show('file')) || show('hr')\n const hasAlign = show('alignLeft') || show('alignCenter') || show('alignRight')\n const hasEmojiGroup = !!onEmojiClick && show('emoji')\n const hasHistory = show('undo') || show('redo')\n\n return (\n <div role=\"toolbar\" aria-label=\"Text formatting\" className=\"flex min-h-[2.75rem] flex-wrap items-center gap-ds-01 border-b border-surface-border-strong px-ds-04 py-ds-02b\">\n {showControls && (<>\n {/* Inline formatting */}\n {show('bold') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBold().run()} isActive={state.isBold} title=\"Bold\">\n <Icon icon={IconBold} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('italic') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleItalic().run()} isActive={state.isItalic} title=\"Italic\">\n <Icon icon={IconItalic} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('underline') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleUnderline().run()} isActive={state.isUnderline} title=\"Underline\">\n <Icon icon={IconUnderline} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('strike') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleStrike().run()} isActive={state.isStrike} title=\"Strikethrough\">\n <Icon icon={IconStrikethrough} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('highlight') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHighlight().run()} isActive={state.isHighlight} title=\"Highlight\">\n <Icon icon={IconHighlight} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n\n {hasInline && hasBlock && <ToolbarDivider />}\n\n {/* Block formatting */}\n {show('h2') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()} isActive={state.isH2} title=\"Heading 2\">\n <Icon icon={IconH2} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('h3') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()} isActive={state.isH3} title=\"Heading 3\">\n <Icon icon={IconH3} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('blockquote') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBlockquote().run()} isActive={state.isBlockquote} title=\"Blockquote\">\n <Icon icon={IconBlockquote} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n\n {hasBlock && hasList && <ToolbarDivider />}\n\n {/* Lists */}\n {show('bulletList') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBulletList().run()} isActive={state.isBulletList} title=\"Bullet list\">\n <Icon icon={IconList} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('orderedList') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleOrderedList().run()} isActive={state.isOrderedList} title=\"Ordered list\">\n <Icon icon={IconListNumbers} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('taskList') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleTaskList().run()} isActive={state.isTaskList} title=\"Task list\">\n <Icon icon={IconListCheck} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('codeBlock') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleCodeBlock().run()} isActive={state.isCodeBlock} title=\"Code block\">\n <Icon icon={IconCode} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n\n {hasList && hasMedia && <ToolbarDivider />}\n\n {/* Media & Links */}\n {show('link') && <LinkButton editor={editor} />}\n {onImageClick && show('image') && (\n <ToolbarButton onClick={onImageClick} title=\"Insert image\">\n <Icon icon={IconPhoto} size=\"sm\" />\n </ToolbarButton>\n )}\n {onFileClick && show('file') && (\n <ToolbarButton onClick={onFileClick} title=\"Attach file\">\n <Icon icon={IconPaperclip} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('hr') && (\n <ToolbarButton onClick={() => editor.chain().focus().setHorizontalRule().run()} title=\"Horizontal rule\">\n <Icon icon={IconLineDashed} size=\"sm\" />\n </ToolbarButton>\n )}\n\n {hasMedia && hasAlign && <ToolbarDivider />}\n\n {/* Alignment */}\n {show('alignLeft') && (\n <ToolbarButton onClick={() => editor.chain().focus().setTextAlign('left').run()} isActive={state.isAlignLeft} title=\"Align left\">\n <Icon icon={IconAlignLeft} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('alignCenter') && (\n <ToolbarButton onClick={() => editor.chain().focus().setTextAlign('center').run()} isActive={state.isAlignCenter} title=\"Align center\">\n <Icon icon={IconAlignCenter} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('alignRight') && (\n <ToolbarButton onClick={() => editor.chain().focus().setTextAlign('right').run()} isActive={state.isAlignRight} title=\"Align right\">\n <Icon icon={IconAlignRight} size=\"sm\" />\n </ToolbarButton>\n )}\n\n {hasAlign && (hasEmojiGroup || hasHistory) && <ToolbarDivider />}\n\n {/* Emoji */}\n {onEmojiClick && show('emoji') && (\n <ToolbarButton onClick={onEmojiClick} title=\"Emoji\">\n <Icon icon={IconMoodSmile} size=\"sm\" />\n </ToolbarButton>\n )}\n\n {/* History */}\n {show('undo') && (\n <ToolbarButton onClick={() => editor.chain().focus().undo().run()} disabled={!state.canUndo} title=\"Undo\">\n <Icon icon={IconArrowBackUp} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('redo') && (\n <ToolbarButton onClick={() => editor.chain().focus().redo().run()} disabled={!state.canRedo} title=\"Redo\">\n <Icon icon={IconArrowForwardUp} size=\"sm\" />\n </ToolbarButton>\n )}\n </>)}\n {trailing && <div className=\"ml-auto flex items-center pl-ds-02\">{trailing}</div>}\n </div>\n )\n}\n\nconst LazyPicker = React.lazy(() =>\n import('./emoji-picker').then((m) => ({ default: m.EmojiPicker })),\n)\n\nfunction EmojiPickerLazy({ onSelect }: { onSelect: (emoji: EmojiData) => void }) {\n const fallback = <div className=\"flex h-[435px] w-[352px] items-center justify-center rounded-surface bg-surface-overlay shadow-raised-hover\"><span className=\"text-body-sm text-surface-fg-subtle\">Loading…</span></div>\n\n return (\n <React.Suspense fallback={fallback}>\n <LazyPicker onSelect={onSelect} />\n </React.Suspense>\n )\n}\n\nexport type ToolbarItem =\n | 'bold' | 'italic' | 'underline' | 'strike' | 'highlight'\n | 'h2' | 'h3' | 'blockquote'\n | 'bulletList' | 'orderedList' | 'taskList' | 'codeBlock'\n | 'link' | 'image' | 'file' | 'hr'\n | 'alignLeft' | 'alignCenter' | 'alignRight'\n | 'emoji' | 'undo' | 'redo'\n\nexport interface MentionItem {\n id: string\n label: string\n avatar?: string\n}\n\n/**\n * A Tiptap-powered rich text editor with a configurable toolbar, @mentions,\n * emoji suggestions, file/image uploads, and task lists.\n *\n * Emits HTML by default, or Markdown when `format=\"markdown\"`. NOTE: the HTML\n * output is the editor's raw HTML and is NOT sanitized — do not render it as\n * untrusted content without sanitizing it first. Storing Markdown (and\n * rendering via MarkdownViewer) sidesteps that risk entirely.\n */\nexport interface RichTextEditorProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'onChange' | 'content'> {\n /** Content format read and emitted. `markdown` for Markdown in/out; `html` uses HTML. @default 'html' */\n format?: 'html' | 'markdown'\n /** Initial content, interpreted per `format`. Updates are NOT reactive — use `onChange` for controlled state. */\n content?: string\n placeholder?: string\n /** Called with the editor content (HTML, or Markdown when `format=\"markdown\"`) whenever it changes. */\n onChange?: (value: string) => void\n className?: string\n /** Set to false to render in read-only mode (e.g. for previewing). */\n editable?: boolean\n /** Called when an image is pasted/dropped. Return a URL. If not provided, images inline as base64. */\n onImageUpload?: (file: File) => Promise<string>\n /** Called when a non-image file is dropped/pasted. If not provided, non-image files are ignored. */\n onFileUpload?: (file: File) => Promise<{ url: string; name: string; size: number }>\n /** Whitelist of toolbar items to display. Omit to show all. */\n toolbar?: ToolbarItem[]\n /** Static list of mentionable items (shown when user types @). */\n mentions?: MentionItem[]\n /** Async mention search. Takes precedence over static `mentions` list. */\n onMentionSearch?: (query: string) => Promise<MentionItem[]>\n /** Called when a mention is selected from the suggestion dropdown. */\n onMentionSelect?: (item: MentionItem) => void\n /** Emoji art style. @default 'native' */\n emojiSet?: EmojiSet\n /** Show a source-view toggle (raw Markdown ⇄ visual) in the top-right of the default editor. @default false */\n sourceToggle?: boolean\n /** Controlled source-view state — drive it from an external button. */\n sourceMode?: boolean\n /** Uncontrolled initial source-view state. @default false */\n defaultSourceMode?: boolean\n /** Called when the source view toggles (raw Markdown ⇄ visual). */\n onSourceModeChange?: (source: boolean) => void\n}\n\n// --------------------------- compound slot context ------------------------\n\ninterface RTEContextValue {\n editor: Editor\n toolbar?: ToolbarItem[]\n editable: boolean\n onImageClick: () => void\n onFileClick?: () => void\n onEmojiClick: () => void\n /** Raw-Markdown source view active. */\n sourceMode: boolean\n setSourceMode: (source: boolean) => void\n toggleSource: () => void\n sourceText: string\n onSourceChange: (value: string) => void\n}\n\nconst RTEContext = React.createContext<RTEContextValue | null>(null)\n\n/** Access the editor + toolbar wiring inside a `<RichTextEditor.Provider>`. */\nfunction useRichTextEditor(): RTEContextValue {\n const ctx = React.useContext(RTEContext)\n if (!ctx) throw new Error('RichTextEditor.Toolbar / .Content must be used within <RichTextEditor.Provider>')\n return ctx\n}\n\nexport interface RichTextEditorProviderProps extends RichTextEditorProps {\n children?: React.ReactNode\n}\n\n/**\n * Owns the Tiptap editor + all upload/emoji/mention plumbing and provides it to\n * `RichTextEditor.Toolbar` / `RichTextEditor.Content`. Compose your own layout\n * (toolbar top/bottom/floating, or bring your own) around these slots, or use\n * `<RichTextEditor>` for the batteries-included default.\n */\nconst RichTextEditorProvider = React.forwardRef<HTMLDivElement, RichTextEditorProviderProps>(\n function RichTextEditorProvider({\n format = 'html',\n content = '',\n placeholder = 'Start writing...',\n onChange,\n className,\n editable = true,\n toolbar,\n onImageUpload,\n onFileUpload,\n mentions,\n onMentionSearch,\n onMentionSelect,\n sourceMode: sourceModeProp,\n defaultSourceMode = false,\n onSourceModeChange,\n // @deprecated no-op since the frimousse migration (native-only emoji). Kept\n // out of `...props` so it never leaks onto the DOM.\n emojiSet: _emojiSet = 'native',\n // Default-render-only flag; dropped here so it never leaks onto the DOM.\n sourceToggle: _sourceToggle,\n children,\n ...props\n}, ref) {\n const editorRef = React.useRef<ReturnType<typeof useEditor>>(null)\n const isInternalChangeRef = React.useRef(false)\n const reduceMotion = useReducedMotion()\n const [showEmojiPicker, setShowEmojiPicker] = React.useState(false)\n\n // Source view (raw Markdown), controllable.\n const [uncontrolledSource, setUncontrolledSource] = React.useState(defaultSourceMode)\n const sourceMode = sourceModeProp ?? uncontrolledSource\n const setSourceMode = React.useCallback(\n (v: boolean) => {\n if (sourceModeProp === undefined) setUncontrolledSource(v)\n onSourceModeChange?.(v)\n },\n [sourceModeProp, onSourceModeChange],\n )\n const [sourceText, setSourceText] = React.useState('')\n const emojiPickerRef = React.useRef<HTMLDivElement>(null)\n const imageInputRef = React.useRef<HTMLInputElement>(null)\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n\n const handleImageInsert = async (file: File) => {\n const ed = editorRef.current\n if (!ed) return\n if (onImageUpload) {\n const url = await onImageUpload(file)\n if (url && /^https?:\\/\\//i.test(url)) {\n ed.chain().focus().setImage({ src: url }).run()\n }\n } else {\n const reader = new FileReader()\n reader.onload = () => {\n ed.chain().focus().setImage({ src: reader.result as string }).run()\n }\n reader.readAsDataURL(file)\n }\n }\n\n const handleFileInsert = async (file: File) => {\n const ed = editorRef.current\n if (!ed || !onFileUpload) return\n const result = await onFileUpload(file)\n ed.chain().focus().insertContent({\n type: 'fileAttachment',\n attrs: { url: result.url, name: result.name, size: result.size },\n }).run()\n }\n\n const editor = useEditor({\n immediatelyRender: false, // SSR-safe — prevents hydration mismatch in Next.js\n extensions: [\n StarterKit.configure({\n heading: { levels: [2, 3] },\n // v3: Underline + Link are now included in StarterKit\n link: {\n openOnClick: false,\n protocols: ['http', 'https', 'mailto'],\n validate: (href: string) => /^(https?:\\/\\/|mailto:)/i.test(href),\n HTMLAttributes: {\n rel: 'noopener noreferrer',\n target: '_blank',\n },\n },\n }),\n Placeholder.configure({\n placeholder,\n emptyEditorClass:\n 'before:content-[attr(data-placeholder)] before:text-surface-fg-subtle before:float-left before:h-0 before:pointer-events-none',\n }),\n Highlight.configure({ multicolor: false }),\n ListKit.configure({\n bulletList: false, // Already in StarterKit\n orderedList: false, // Already in StarterKit\n listItem: false, // Already in StarterKit\n listKeymap: false, // Already in StarterKit\n taskList: {},\n taskItem: { nested: true },\n }),\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Image.configure({\n allowBase64: true,\n HTMLAttributes: {\n class: 'max-w-full rounded-control',\n },\n }),\n FileAttachment,\n ...(mentions || onMentionSearch ? [\n Mention.configure({\n HTMLAttributes: { class: 'mention' },\n suggestion: {\n items: async ({ query }: { query: string }) => {\n if (onMentionSearch) return await onMentionSearch(query)\n if (mentions) return mentions.filter(m => m.label.toLowerCase().includes(query.toLowerCase())).slice(0, 8)\n return []\n },\n render: createSuggestionRenderer(onMentionSelect),\n },\n }),\n ] : []),\n EmojiNode,\n createEmojiSuggestion(),\n Markdown,\n ],\n content,\n contentType: format === 'markdown' ? 'markdown' : undefined,\n editable,\n editorProps: {\n handleDrop: (_view, event, _slice, moved) => {\n if (moved || !event.dataTransfer?.files.length) return false\n const file = event.dataTransfer.files[0]\n if (!file) return false\n if (file.type.startsWith('image/')) {\n handleImageInsert(file)\n return true\n }\n if (onFileUpload) {\n handleFileInsert(file)\n return true\n }\n return false\n },\n handlePaste: (_view, event) => {\n const file = event.clipboardData?.files[0]\n if (!file) return false\n if (file.type.startsWith('image/')) {\n handleImageInsert(file)\n return true\n }\n if (onFileUpload) {\n handleFileInsert(file)\n return true\n }\n return false\n },\n attributes: {\n class: cn(\n ...PROSE_CLASSES,\n 'focus:outline-hidden',\n 'min-h-[120px] px-ds-04 py-ds-04',\n ),\n },\n },\n onUpdate: ({ editor: ed }) => {\n isInternalChangeRef.current = true\n onChange?.(format === 'markdown' ? ed.getMarkdown() : ed.getHTML())\n queueMicrotask(() => {\n isInternalChangeRef.current = false\n })\n },\n })\n\n React.useEffect(() => {\n editorRef.current = editor\n }, [editor])\n\n // Close emoji picker on click outside\n React.useEffect(() => {\n if (!showEmojiPicker) return\n const handleClickOutside = (e: MouseEvent) => {\n if (emojiPickerRef.current && !emojiPickerRef.current.contains(e.target as Node)) {\n setShowEmojiPicker(false)\n }\n }\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [showEmojiPicker])\n\n React.useEffect(() => {\n if (isInternalChangeRef.current) return\n if (!editor) return\n const current = format === 'markdown' ? editor.getMarkdown() : editor.getHTML()\n if (content !== current) {\n editor.commands.setContent(content, {\n emitUpdate: false,\n contentType: format === 'markdown' ? 'markdown' : undefined,\n })\n }\n }, [editor, content, format])\n\n // Entering source view: seed the textarea with the editor's current Markdown.\n React.useEffect(() => {\n if (sourceMode && editor) setSourceText(editor.getMarkdown())\n // Only re-seed on the source-mode transition, not on every keystroke.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [sourceMode])\n\n if (!editor) return null\n\n const onSourceChange = (v: string) => {\n setSourceText(v)\n // Push edits back into the doc so `onChange` fires in the configured format.\n editor.commands.setContent(v, { contentType: 'markdown' })\n }\n\n const ctx: RTEContextValue = {\n editor,\n toolbar,\n editable,\n onImageClick: () => imageInputRef.current?.click(),\n onFileClick: onFileUpload ? () => fileInputRef.current?.click() : undefined,\n onEmojiClick: () => setShowEmojiPicker((prev) => !prev),\n sourceMode,\n setSourceMode,\n toggleSource: () => setSourceMode(!sourceMode),\n sourceText,\n onSourceChange,\n }\n\n return (\n <RTEContext.Provider value={ctx}>\n <div ref={ref} {...props} className={cn('relative', className)}>\n {/* Emoji picker rendered outside the overflow-hidden box so it isn't clipped */}\n <AnimatePresence>\n {showEmojiPicker && (\n <motion.div\n key=\"emoji-picker\"\n ref={emojiPickerRef}\n initial={reduceMotion ? false : { opacity: 0, scale: 0.96, y: 4 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={reduceMotion ? { opacity: 0 } : { opacity: 0, scale: 0.96, y: 4 }}\n transition={{ duration: 0.14, ease: 'easeOut' }}\n className=\"absolute bottom-full right-0 z-popover mb-ds-02 origin-bottom-right\"\n onKeyDown={(e) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n setShowEmojiPicker(false)\n }\n }}\n >\n <EmojiPickerLazy\n onSelect={({ id, native }) => {\n editor.chain().focus().insertContent({\n type: 'emojiNode',\n attrs: { id, native },\n }).run()\n setShowEmojiPicker(false)\n }}\n />\n </motion.div>\n )}\n </AnimatePresence>\n <input\n ref={imageInputRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Upload image\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0]\n if (file) handleImageInsert(file)\n e.target.value = ''\n }}\n />\n {onFileUpload && (\n <input\n ref={fileInputRef}\n type=\"file\"\n aria-label=\"Upload file\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0]\n if (file) handleFileInsert(file)\n e.target.value = ''\n }}\n />\n )}\n {children}\n </div>\n </RTEContext.Provider>\n )\n},\n)\n\nRichTextEditorProvider.displayName = 'RichTextEditor.Provider'\n\n/**\n * The formatting toolbar. Reads the editor from `<RichTextEditor.Provider>`.\n * In source view the format controls hide but `trailing` (e.g. the source\n * toggle) stays, so the bar persists.\n */\nfunction RichTextEditorToolbarSlot({ trailing }: { trailing?: React.ReactNode }) {\n const { editor, toolbar, editable, sourceMode, onImageClick, onFileClick, onEmojiClick } = useRichTextEditor()\n if (!editable) return null\n const showControls = !sourceMode\n if (!showControls && !trailing) return null\n return (\n <Toolbar\n editor={editor}\n toolbar={toolbar}\n showControls={showControls}\n trailing={trailing}\n onImageClick={onImageClick}\n onFileClick={onFileClick}\n onEmojiClick={onEmojiClick}\n />\n )\n}\nRichTextEditorToolbarSlot.displayName = 'RichTextEditor.Toolbar'\n\n/** The content area — the visual editor, or a raw-Markdown textarea in source view. */\nfunction RichTextEditorContentSlot() {\n const { editor, sourceMode, sourceText, onSourceChange } = useRichTextEditor()\n const reduce = useReducedMotion()\n const enter = reduce ? { opacity: 0 } : { opacity: 0, y: 4 }\n return (\n <AnimatePresence mode=\"wait\" initial={false}>\n {sourceMode ? (\n <motion.div key=\"source\" initial={enter} animate={{ opacity: 1, y: 0 }} exit={enter} transition={{ duration: 0.14, ease: 'easeOut' }}>\n <textarea\n value={sourceText}\n onChange={(e) => onSourceChange(e.target.value)}\n spellCheck={false}\n aria-label=\"Markdown source\"\n className=\"block min-h-[120px] w-full resize-y bg-surface-raised px-ds-04 py-ds-04 font-mono text-body-sm leading-ds-relaxed text-surface-fg focus:outline-hidden\"\n />\n </motion.div>\n ) : (\n <motion.div key=\"visual\" initial={enter} animate={{ opacity: 1, y: 0 }} exit={enter} transition={{ duration: 0.14, ease: 'easeOut' }}>\n <EditorContent editor={editor} />\n </motion.div>\n )}\n </AnimatePresence>\n )\n}\nRichTextEditorContentSlot.displayName = 'RichTextEditor.Content'\n\n/**\n * A source-view toggle (raw Markdown ⇄ visual). Text + icon by default;\n * pass `iconOnly` for a compact button. Place it anywhere inside a Provider.\n */\nfunction RichTextEditorSourceToggleSlot({ className, iconOnly = false }: { className?: string; iconOnly?: boolean }) {\n const { sourceMode, toggleSource } = useRichTextEditor()\n const aria = sourceMode ? 'Switch to visual editor' : 'Switch to Markdown source'\n const icon = sourceMode ? IconEye : IconCode\n if (iconOnly) {\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-pressed={sourceMode}\n aria-label={aria}\n title={aria}\n className={className}\n onClick={toggleSource}\n >\n <Icon icon={icon} size=\"sm\" />\n </Button>\n )\n }\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-pressed={sourceMode}\n aria-label={aria}\n startIcon={icon}\n className={className}\n onClick={toggleSource}\n >\n {sourceMode ? 'Editor' : 'Markdown'}\n </Button>\n )\n}\nRichTextEditorSourceToggleSlot.displayName = 'RichTextEditor.SourceToggle'\n\n// Batteries-included default: Provider + bordered box + toolbar-over-content.\nconst RichTextEditorBase = React.forwardRef<HTMLDivElement, RichTextEditorProps>(\n function RichTextEditor(props, ref) {\n return (\n <RichTextEditorProvider ref={ref} {...props}>\n <div\n className={cn(\n 'overflow-hidden rounded-surface border border-surface-border-strong bg-surface-raised',\n 'transition-colors ease-productive-standard focus-within:border-surface-border-strong',\n )}\n >\n <RichTextEditorToolbarSlot\n trailing={props.sourceToggle ? <RichTextEditorSourceToggleSlot /> : undefined}\n />\n <RichTextEditorContentSlot />\n </div>\n </RichTextEditorProvider>\n )\n },\n)\nRichTextEditorBase.displayName = 'RichTextEditor'\n\nconst RichTextEditor = Object.assign(RichTextEditorBase, {\n Provider: RichTextEditorProvider,\n Toolbar: RichTextEditorToolbarSlot,\n Content: RichTextEditorContentSlot,\n SourceToggle: RichTextEditorSourceToggleSlot,\n})\n\nexport interface RichTextViewerProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'content'> {\n content: string\n /** Content format. `markdown` parses Markdown; `html` (default) parses HTML. @default 'html' */\n format?: 'html' | 'markdown'\n className?: string\n}\n\nconst RichTextViewer = React.forwardRef<HTMLDivElement, RichTextViewerProps>(\n function RichTextViewer({ content, format = 'html', className, ...props }, ref) {\n const editor = useEditor({\n immediatelyRender: false, // SSR-safe — prevents hydration mismatch in Next.js\n extensions: [\n StarterKit.configure({\n heading: { levels: [2, 3] },\n link: {\n openOnClick: true,\n protocols: ['http', 'https', 'mailto'],\n validate: (href: string) => /^(https?:\\/\\/|mailto:)/i.test(href),\n HTMLAttributes: {\n rel: 'noopener noreferrer',\n target: '_blank',\n },\n },\n }),\n Highlight.configure({ multicolor: false }),\n ListKit.configure({\n bulletList: false,\n orderedList: false,\n listItem: false,\n listKeymap: false,\n taskList: {},\n taskItem: { nested: true },\n }),\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Image.configure({\n allowBase64: true,\n HTMLAttributes: {\n class: 'max-w-full rounded-control',\n },\n }),\n FileAttachment,\n Mention.configure({\n HTMLAttributes: { class: 'mention' },\n }),\n Markdown,\n ],\n content,\n contentType: format === 'markdown' ? 'markdown' : undefined,\n editable: false,\n editorProps: {\n attributes: {\n class: cn(...PROSE_CLASSES),\n },\n },\n })\n\n if (!editor) return null\n\n return (\n <div ref={ref} {...props} className={className}>\n <EditorContent editor={editor} />\n </div>\n )\n},\n)\n\nRichTextViewer.displayName = 'RichTextViewer'\n\nexport {\n RichTextEditor,\n RichTextEditorProvider,\n RichTextEditorToolbarSlot as RichTextEditorToolbar,\n RichTextEditorContentSlot as RichTextEditorContent,\n RichTextEditorSourceToggleSlot as RichTextEditorSourceToggle,\n useRichTextEditor,\n RichTextViewer,\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rich-text-editor.js","names":[],"sources":["../../src/composed/rich-text-editor.tsx"],"sourcesContent":["'use client'\n\nimport {\n IconAlignCenter,\n IconAlignLeft,\n IconAlignRight,\n IconArrowBackUp,\n IconArrowForwardUp,\n IconBlockquote,\n IconBold,\n IconCode,\n IconEye,\n IconH2,\n IconH3,\n IconHighlight,\n IconItalic,\n IconLineDashed,\n IconLink,\n IconList,\n IconListCheck,\n IconListNumbers,\n IconMoodSmile,\n IconPaperclip,\n IconPhoto,\n IconStrikethrough,\n IconUnderline,\n} from '@tabler/icons-react'\nimport Highlight from '@tiptap/extension-highlight'\nimport Image from '@tiptap/extension-image'\nimport { ListKit } from '@tiptap/extension-list'\nimport Mention from '@tiptap/extension-mention'\nimport TextAlign from '@tiptap/extension-text-align'\nimport { Placeholder } from '@tiptap/extensions'\nimport { Markdown } from '@tiptap/markdown'\nimport { type Editor,EditorContent, useEditor, useEditorState } from '@tiptap/react'\nimport StarterKit from '@tiptap/starter-kit'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Button } from '../ui/button'\nimport { Icon } from '../ui/icon'\nimport { MENTION_TOKEN_CLASS } from '../ui/lib/mention'\nimport { cn } from '../ui/lib/utils'\nimport type { EmojiData, EmojiSet } from './emoji-picker'\nimport { EmojiNode } from './extensions/emoji-node'\nimport { createEmojiSuggestion } from './extensions/emoji-suggestion'\nimport { FileAttachment } from './extensions/file-attachment'\nimport { createSuggestionRenderer } from './extensions/mention-suggestion'\n\nconst PROSE_CLASSES = [\n 'prose prose-sm max-w-none',\n 'font-body text-body-md leading-relaxed text-surface-fg',\n '[&_h2]:text-heading-sm [&_h2]:mb-ds-03 [&_h2]:mt-ds-05 [&_h2]:text-surface-fg',\n '[&_h3]:text-body-lg [&_h3]:font-semibold [&_h3]:mb-ds-02b [&_h3]:mt-ds-04 [&_h3]:text-surface-fg',\n '[&_p]:mb-ds-02b [&_p]:text-surface-fg-muted',\n '[&_ul]:ml-ds-05 [&_ul]:list-disc [&_ol]:ml-ds-05 [&_ol]:list-decimal',\n '[&_li]:text-surface-fg-muted',\n '[&_code]:rounded [&_code]:bg-surface-sunken [&_code]:px-ds-02b [&_code]:py-ds-01 [&_code]:text-body-md [&_code]:text-accent-11',\n '[&_pre]:rounded-surface [&_pre]:bg-surface-sunken [&_pre]:p-ds-04',\n '[&_strong]:font-semibold [&_strong]:text-surface-fg',\n // slop-allow: side-stripe — blockquote left-rule is standard typography, not a card accent-rail\n '[&_blockquote]:border-l-[3px] [&_blockquote]:border-accent-6 [&_blockquote]:pl-ds-04 [&_blockquote]:italic [&_blockquote]:text-surface-fg-subtle',\n '[&_mark]:rounded-xs [&_mark]:bg-warning-3 [&_mark]:px-[2px]',\n '[&_ul[data-type=\"taskList\"]]:ml-0 [&_ul[data-type=\"taskList\"]]:list-none [&_li[data-type=\"taskItem\"]]:flex [&_li[data-type=\"taskItem\"]]:items-start [&_li[data-type=\"taskItem\"]]:gap-ds-02',\n '[&_hr]:my-ds-04 [&_hr]:border-surface-border-strong',\n '[&_a]:text-accent-11 [&_a]:underline [&_a]:decoration-accent-6 hover:[&_a]:decoration-accent-11',\n '[&_img]:max-w-full [&_img]:rounded-control [&_img]:my-ds-03',\n MENTION_TOKEN_CLASS,\n] as const\n\ninterface ToolbarButtonProps {\n onClick: () => void\n isActive?: boolean\n disabled?: boolean\n title: string\n children: React.ReactNode\n}\n\nfunction ToolbarButton({\n onClick,\n isActive = false,\n disabled = false,\n title,\n children,\n}: ToolbarButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n title={title}\n aria-label={title}\n aria-pressed={isActive}\n className={cn(\n 'inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control transition-colors duration-fast-01 ease-productive-standard',\n 'hover:bg-surface-panel-hover',\n 'disabled:pointer-events-none disabled:opacity-action-disabled',\n isActive\n ? 'bg-surface-panel-hover text-accent-11'\n : 'text-surface-fg-subtle',\n )}\n >\n {children}\n </button>\n )\n}\n\nfunction LinkButton({ editor }: { editor: Editor }) {\n const [showInput, setShowInput] = React.useState(false)\n const [url, setUrl] = React.useState('')\n const inputRef = React.useRef<HTMLInputElement>(null)\n const { isLink } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isLink: e.isActive('link') }),\n })\n\n const handleToggle = () => {\n if (isLink) {\n editor.chain().focus().unsetLink().run()\n return\n }\n const previousUrl = editor.getAttributes('link').href || ''\n setUrl(previousUrl)\n setShowInput(true)\n setTimeout(() => inputRef.current?.focus(), 0)\n }\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault()\n if (url.trim()) {\n editor.chain().focus().setLink({ href: url.trim() }).run()\n }\n setShowInput(false)\n setUrl('')\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n setShowInput(false)\n setUrl('')\n editor.commands.focus()\n }\n }\n\n return (\n <div className=\"relative\">\n <ToolbarButton onClick={handleToggle} isActive={isLink} title=\"Link\">\n <Icon icon={IconLink} size=\"sm\" />\n </ToolbarButton>\n {showInput && (\n <form\n onSubmit={handleSubmit}\n aria-label=\"Edit link URL\"\n className=\"absolute left-0 top-full z-popover mt-ds-01 flex items-center gap-ds-02 rounded-control bg-surface-overlay p-ds-02 shadow-raised-hover\"\n >\n <input\n ref={inputRef}\n type=\"url\"\n value={url}\n onChange={(e) => setUrl(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"https://...\"\n className=\"h-ds-sm w-[240px] rounded-control-inner border border-surface-border-interactive bg-surface-panel-hover px-ds-03 text-body-sm text-surface-fg focus:border-accent-7 focus:outline-hidden\"\n />\n <Button type=\"submit\" variant=\"solid\" size=\"sm\">\n Apply\n </Button>\n </form>\n )}\n </div>\n )\n}\n\nfunction ToolbarDivider() {\n return <div className=\"mx-ds-02 h-ds-05 w-px bg-surface-border\" />\n}\n\nfunction Toolbar({ editor, toolbar, onImageClick, onFileClick, onEmojiClick, trailing, showControls = true }: {\n editor: Editor\n toolbar?: ToolbarItem[]\n onImageClick?: () => void\n onFileClick?: () => void\n onEmojiClick?: () => void\n /** Right-aligned content (e.g. a source-view toggle). */\n trailing?: React.ReactNode\n /** Hide the formatting controls, keeping only `trailing`. @default true */\n showControls?: boolean\n}) {\n // v3: useEditorState subscribes to specific state slices so the toolbar\n // re-renders only when active-state or can-undo/redo actually changes.\n const state = useEditorState({\n editor,\n selector: ({ editor: e }) => ({\n isBold: e.isActive('bold'),\n isItalic: e.isActive('italic'),\n isUnderline: e.isActive('underline'),\n isStrike: e.isActive('strike'),\n isHighlight: e.isActive('highlight'),\n isH2: e.isActive('heading', { level: 2 }),\n isH3: e.isActive('heading', { level: 3 }),\n isBlockquote: e.isActive('blockquote'),\n isBulletList: e.isActive('bulletList'),\n isOrderedList: e.isActive('orderedList'),\n isTaskList: e.isActive('taskList'),\n isCodeBlock: e.isActive('codeBlock'),\n isLink: e.isActive('link'),\n isAlignLeft: e.isActive({ textAlign: 'left' }),\n isAlignCenter: e.isActive({ textAlign: 'center' }),\n isAlignRight: e.isActive({ textAlign: 'right' }),\n canUndo: e.can().undo(),\n canRedo: e.can().redo(),\n }),\n })\n\n const show = (item: ToolbarItem) => !toolbar || toolbar.includes(item)\n\n // Each group is an array of ToolbarItem names that belong to it.\n // A divider renders between two adjacent groups only if both have at least one visible item.\n const hasInline = show('bold') || show('italic') || show('underline') || show('strike') || show('highlight')\n const hasBlock = show('h2') || show('h3') || show('blockquote')\n const hasList = show('bulletList') || show('orderedList') || show('taskList') || show('codeBlock')\n const hasMedia = show('link') || (!!onImageClick && show('image')) || (!!onFileClick && show('file')) || show('hr')\n const hasAlign = show('alignLeft') || show('alignCenter') || show('alignRight')\n const hasEmojiGroup = !!onEmojiClick && show('emoji')\n const hasHistory = show('undo') || show('redo')\n\n return (\n <div role=\"toolbar\" aria-label=\"Text formatting\" className=\"flex min-h-[2.75rem] flex-wrap items-center gap-ds-01 border-b border-surface-border-strong px-ds-04 py-ds-02b\">\n {showControls && (<>\n {/* Inline formatting */}\n {show('bold') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBold().run()} isActive={state.isBold} title=\"Bold\">\n <Icon icon={IconBold} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('italic') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleItalic().run()} isActive={state.isItalic} title=\"Italic\">\n <Icon icon={IconItalic} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('underline') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleUnderline().run()} isActive={state.isUnderline} title=\"Underline\">\n <Icon icon={IconUnderline} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('strike') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleStrike().run()} isActive={state.isStrike} title=\"Strikethrough\">\n <Icon icon={IconStrikethrough} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('highlight') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHighlight().run()} isActive={state.isHighlight} title=\"Highlight\">\n <Icon icon={IconHighlight} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n\n {hasInline && hasBlock && <ToolbarDivider />}\n\n {/* Block formatting */}\n {show('h2') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()} isActive={state.isH2} title=\"Heading 2\">\n <Icon icon={IconH2} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('h3') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()} isActive={state.isH3} title=\"Heading 3\">\n <Icon icon={IconH3} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('blockquote') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBlockquote().run()} isActive={state.isBlockquote} title=\"Blockquote\">\n <Icon icon={IconBlockquote} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n\n {hasBlock && hasList && <ToolbarDivider />}\n\n {/* Lists */}\n {show('bulletList') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBulletList().run()} isActive={state.isBulletList} title=\"Bullet list\">\n <Icon icon={IconList} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('orderedList') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleOrderedList().run()} isActive={state.isOrderedList} title=\"Ordered list\">\n <Icon icon={IconListNumbers} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('taskList') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleTaskList().run()} isActive={state.isTaskList} title=\"Task list\">\n <Icon icon={IconListCheck} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('codeBlock') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleCodeBlock().run()} isActive={state.isCodeBlock} title=\"Code block\">\n <Icon icon={IconCode} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n\n {hasList && hasMedia && <ToolbarDivider />}\n\n {/* Media & Links */}\n {show('link') && <LinkButton editor={editor} />}\n {onImageClick && show('image') && (\n <ToolbarButton onClick={onImageClick} title=\"Insert image\">\n <Icon icon={IconPhoto} size=\"sm\" />\n </ToolbarButton>\n )}\n {onFileClick && show('file') && (\n <ToolbarButton onClick={onFileClick} title=\"Attach file\">\n <Icon icon={IconPaperclip} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('hr') && (\n <ToolbarButton onClick={() => editor.chain().focus().setHorizontalRule().run()} title=\"Horizontal rule\">\n <Icon icon={IconLineDashed} size=\"sm\" />\n </ToolbarButton>\n )}\n\n {hasMedia && hasAlign && <ToolbarDivider />}\n\n {/* Alignment */}\n {show('alignLeft') && (\n <ToolbarButton onClick={() => editor.chain().focus().setTextAlign('left').run()} isActive={state.isAlignLeft} title=\"Align left\">\n <Icon icon={IconAlignLeft} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('alignCenter') && (\n <ToolbarButton onClick={() => editor.chain().focus().setTextAlign('center').run()} isActive={state.isAlignCenter} title=\"Align center\">\n <Icon icon={IconAlignCenter} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('alignRight') && (\n <ToolbarButton onClick={() => editor.chain().focus().setTextAlign('right').run()} isActive={state.isAlignRight} title=\"Align right\">\n <Icon icon={IconAlignRight} size=\"sm\" />\n </ToolbarButton>\n )}\n\n {hasAlign && (hasEmojiGroup || hasHistory) && <ToolbarDivider />}\n\n {/* Emoji */}\n {onEmojiClick && show('emoji') && (\n <ToolbarButton onClick={onEmojiClick} title=\"Emoji\">\n <Icon icon={IconMoodSmile} size=\"sm\" />\n </ToolbarButton>\n )}\n\n {/* History */}\n {show('undo') && (\n <ToolbarButton onClick={() => editor.chain().focus().undo().run()} disabled={!state.canUndo} title=\"Undo\">\n <Icon icon={IconArrowBackUp} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('redo') && (\n <ToolbarButton onClick={() => editor.chain().focus().redo().run()} disabled={!state.canRedo} title=\"Redo\">\n <Icon icon={IconArrowForwardUp} size=\"sm\" />\n </ToolbarButton>\n )}\n </>)}\n {trailing && <div className=\"ml-auto flex items-center pl-ds-02\">{trailing}</div>}\n </div>\n )\n}\n\nconst LazyPicker = React.lazy(() =>\n import('./emoji-picker').then((m) => ({ default: m.EmojiPicker })),\n)\n\nfunction EmojiPickerLazy({ onSelect }: { onSelect: (emoji: EmojiData) => void }) {\n const fallback = <div className=\"flex h-[435px] w-[352px] items-center justify-center rounded-surface bg-surface-overlay shadow-raised-hover\"><span className=\"text-body-sm text-surface-fg-subtle\">Loading…</span></div>\n\n return (\n <React.Suspense fallback={fallback}>\n <LazyPicker onSelect={onSelect} />\n </React.Suspense>\n )\n}\n\nexport type ToolbarItem =\n | 'bold' | 'italic' | 'underline' | 'strike' | 'highlight'\n | 'h2' | 'h3' | 'blockquote'\n | 'bulletList' | 'orderedList' | 'taskList' | 'codeBlock'\n | 'link' | 'image' | 'file' | 'hr'\n | 'alignLeft' | 'alignCenter' | 'alignRight'\n | 'emoji' | 'undo' | 'redo'\n\nexport interface MentionItem {\n id: string\n label: string\n avatar?: string\n}\n\n/**\n * A Tiptap-powered rich text editor with a configurable toolbar, @mentions,\n * emoji suggestions, file/image uploads, and task lists.\n *\n * Emits HTML by default, or Markdown when `format=\"markdown\"`. NOTE: the HTML\n * output is the editor's raw HTML and is NOT sanitized — do not render it as\n * untrusted content without sanitizing it first. Storing Markdown (and\n * rendering via MarkdownViewer) sidesteps that risk entirely.\n */\nexport interface RichTextEditorProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'onChange' | 'content'> {\n /** Content format read and emitted. `markdown` for Markdown in/out; `html` uses HTML. @default 'html' */\n format?: 'html' | 'markdown'\n /** Initial content, interpreted per `format`. Updates are NOT reactive — use `onChange` for controlled state. */\n content?: string\n placeholder?: string\n /** Called with the editor content (HTML, or Markdown when `format=\"markdown\"`) whenever it changes. */\n onChange?: (value: string) => void\n className?: string\n /** Set to false to render in read-only mode (e.g. for previewing). */\n editable?: boolean\n /** Called when an image is pasted/dropped. Return a URL. If not provided, images inline as base64. */\n onImageUpload?: (file: File) => Promise<string>\n /** Called when a non-image file is dropped/pasted. If not provided, non-image files are ignored. */\n onFileUpload?: (file: File) => Promise<{ url: string; name: string; size: number }>\n /** Whitelist of toolbar items to display. Omit to show all. */\n toolbar?: ToolbarItem[]\n /** Static list of mentionable items (shown when user types @). */\n mentions?: MentionItem[]\n /** Async mention search. Takes precedence over static `mentions` list. */\n onMentionSearch?: (query: string) => Promise<MentionItem[]>\n /** Called when a mention is selected from the suggestion dropdown. */\n onMentionSelect?: (item: MentionItem) => void\n /** Emoji art style. @default 'native' */\n emojiSet?: EmojiSet\n /** Show a source-view toggle (raw Markdown ⇄ visual) in the top-right of the default editor. @default false */\n sourceToggle?: boolean\n /** Controlled source-view state — drive it from an external button. */\n sourceMode?: boolean\n /** Uncontrolled initial source-view state. @default false */\n defaultSourceMode?: boolean\n /** Called when the source view toggles (raw Markdown ⇄ visual). */\n onSourceModeChange?: (source: boolean) => void\n}\n\n// --------------------------- compound slot context ------------------------\n\ninterface RTEContextValue {\n editor: Editor\n toolbar?: ToolbarItem[]\n editable: boolean\n onImageClick: () => void\n onFileClick?: () => void\n onEmojiClick: () => void\n /** Raw-Markdown source view active. */\n sourceMode: boolean\n setSourceMode: (source: boolean) => void\n toggleSource: () => void\n sourceText: string\n onSourceChange: (value: string) => void\n}\n\nconst RTEContext = React.createContext<RTEContextValue | null>(null)\n\n/** Access the editor + toolbar wiring inside a `<RichTextEditor.Provider>`. */\nfunction useRichTextEditor(): RTEContextValue {\n const ctx = React.useContext(RTEContext)\n if (!ctx) throw new Error('RichTextEditor.Toolbar / .Content must be used within <RichTextEditor.Provider>')\n return ctx\n}\n\nexport interface RichTextEditorProviderProps extends RichTextEditorProps {\n children?: React.ReactNode\n}\n\n/**\n * Owns the Tiptap editor + all upload/emoji/mention plumbing and provides it to\n * `RichTextEditor.Toolbar` / `RichTextEditor.Content`. Compose your own layout\n * (toolbar top/bottom/floating, or bring your own) around these slots, or use\n * `<RichTextEditor>` for the batteries-included default.\n */\nconst RichTextEditorProvider = React.forwardRef<HTMLDivElement, RichTextEditorProviderProps>(\n function RichTextEditorProvider({\n format = 'html',\n content = '',\n placeholder = 'Start writing...',\n onChange,\n className,\n editable = true,\n toolbar,\n onImageUpload,\n onFileUpload,\n mentions,\n onMentionSearch,\n onMentionSelect,\n sourceMode: sourceModeProp,\n defaultSourceMode = false,\n onSourceModeChange,\n // @deprecated no-op since the frimousse migration (native-only emoji). Kept\n // out of `...props` so it never leaks onto the DOM.\n emojiSet: _emojiSet = 'native',\n // Default-render-only flag; dropped here so it never leaks onto the DOM.\n sourceToggle: _sourceToggle,\n children,\n ...props\n}, ref) {\n const editorRef = React.useRef<ReturnType<typeof useEditor>>(null)\n const isInternalChangeRef = React.useRef(false)\n const reduceMotion = useReducedMotion()\n const [showEmojiPicker, setShowEmojiPicker] = React.useState(false)\n\n // Source view (raw Markdown), controllable.\n const [uncontrolledSource, setUncontrolledSource] = React.useState(defaultSourceMode)\n const sourceMode = sourceModeProp ?? uncontrolledSource\n const setSourceMode = React.useCallback(\n (v: boolean) => {\n if (sourceModeProp === undefined) setUncontrolledSource(v)\n onSourceModeChange?.(v)\n },\n [sourceModeProp, onSourceModeChange],\n )\n const [sourceText, setSourceText] = React.useState('')\n const emojiPickerRef = React.useRef<HTMLDivElement>(null)\n const imageInputRef = React.useRef<HTMLInputElement>(null)\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n\n const handleImageInsert = async (file: File) => {\n const ed = editorRef.current\n if (!ed) return\n if (onImageUpload) {\n const url = await onImageUpload(file)\n if (url && /^https?:\\/\\//i.test(url)) {\n ed.chain().focus().setImage({ src: url }).run()\n }\n } else {\n const reader = new FileReader()\n reader.onload = () => {\n ed.chain().focus().setImage({ src: reader.result as string }).run()\n }\n reader.readAsDataURL(file)\n }\n }\n\n const handleFileInsert = async (file: File) => {\n const ed = editorRef.current\n if (!ed || !onFileUpload) return\n const result = await onFileUpload(file)\n ed.chain().focus().insertContent({\n type: 'fileAttachment',\n attrs: { url: result.url, name: result.name, size: result.size },\n }).run()\n }\n\n const editor = useEditor({\n immediatelyRender: false, // SSR-safe — prevents hydration mismatch in Next.js\n extensions: [\n StarterKit.configure({\n heading: { levels: [2, 3] },\n // v3: Underline + Link are now included in StarterKit\n link: {\n openOnClick: false,\n protocols: ['http', 'https', 'mailto'],\n validate: (href: string) => /^(https?:\\/\\/|mailto:)/i.test(href),\n HTMLAttributes: {\n rel: 'noopener noreferrer',\n target: '_blank',\n },\n },\n }),\n Placeholder.configure({\n placeholder,\n emptyEditorClass:\n 'before:content-[attr(data-placeholder)] before:text-surface-fg-subtle before:float-left before:h-0 before:pointer-events-none',\n }),\n Highlight.configure({ multicolor: false }),\n ListKit.configure({\n bulletList: false, // Already in StarterKit\n orderedList: false, // Already in StarterKit\n listItem: false, // Already in StarterKit\n listKeymap: false, // Already in StarterKit\n taskList: {},\n taskItem: { nested: true },\n }),\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Image.configure({\n allowBase64: true,\n HTMLAttributes: {\n class: 'max-w-full rounded-control',\n },\n }),\n FileAttachment,\n ...(mentions || onMentionSearch ? [\n Mention.configure({\n HTMLAttributes: { class: 'mention' },\n suggestion: {\n items: async ({ query }: { query: string }) => {\n if (onMentionSearch) return await onMentionSearch(query)\n if (mentions) return mentions.filter(m => m.label.toLowerCase().includes(query.toLowerCase())).slice(0, 8)\n return []\n },\n render: createSuggestionRenderer(onMentionSelect),\n },\n }),\n ] : []),\n EmojiNode,\n createEmojiSuggestion(),\n Markdown,\n ],\n content,\n contentType: format === 'markdown' ? 'markdown' : undefined,\n editable,\n editorProps: {\n handleDrop: (_view, event, _slice, moved) => {\n if (moved || !event.dataTransfer?.files.length) return false\n const file = event.dataTransfer.files[0]\n if (!file) return false\n if (file.type.startsWith('image/')) {\n handleImageInsert(file)\n return true\n }\n if (onFileUpload) {\n handleFileInsert(file)\n return true\n }\n return false\n },\n handlePaste: (_view, event) => {\n const file = event.clipboardData?.files[0]\n if (!file) return false\n if (file.type.startsWith('image/')) {\n handleImageInsert(file)\n return true\n }\n if (onFileUpload) {\n handleFileInsert(file)\n return true\n }\n return false\n },\n attributes: {\n class: cn(\n ...PROSE_CLASSES,\n 'focus:outline-hidden',\n 'min-h-[120px] px-ds-04 py-ds-04',\n ),\n },\n },\n onUpdate: ({ editor: ed }) => {\n isInternalChangeRef.current = true\n onChange?.(format === 'markdown' ? ed.getMarkdown() : ed.getHTML())\n queueMicrotask(() => {\n isInternalChangeRef.current = false\n })\n },\n })\n\n React.useEffect(() => {\n editorRef.current = editor\n }, [editor])\n\n // Close emoji picker on click outside\n React.useEffect(() => {\n if (!showEmojiPicker) return\n const handleClickOutside = (e: MouseEvent) => {\n if (emojiPickerRef.current && !emojiPickerRef.current.contains(e.target as Node)) {\n setShowEmojiPicker(false)\n }\n }\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [showEmojiPicker])\n\n React.useEffect(() => {\n if (isInternalChangeRef.current) return\n if (!editor) return\n const current = format === 'markdown' ? editor.getMarkdown() : editor.getHTML()\n if (content !== current) {\n editor.commands.setContent(content, {\n emitUpdate: false,\n contentType: format === 'markdown' ? 'markdown' : undefined,\n })\n }\n }, [editor, content, format])\n\n // Entering source view: seed the textarea with the editor's current Markdown.\n React.useEffect(() => {\n if (sourceMode && editor) setSourceText(editor.getMarkdown())\n // Only re-seed on the source-mode transition, not on every keystroke.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [sourceMode])\n\n if (!editor) return null\n\n const onSourceChange = (v: string) => {\n setSourceText(v)\n // Push edits back into the doc so `onChange` fires in the configured format.\n editor.commands.setContent(v, { contentType: 'markdown' })\n }\n\n const ctx: RTEContextValue = {\n editor,\n toolbar,\n editable,\n onImageClick: () => imageInputRef.current?.click(),\n onFileClick: onFileUpload ? () => fileInputRef.current?.click() : undefined,\n onEmojiClick: () => setShowEmojiPicker((prev) => !prev),\n sourceMode,\n setSourceMode,\n toggleSource: () => setSourceMode(!sourceMode),\n sourceText,\n onSourceChange,\n }\n\n return (\n <RTEContext.Provider value={ctx}>\n <div ref={ref} {...props} className={cn('relative', className)}>\n {/* Emoji picker rendered outside the overflow-hidden box so it isn't clipped */}\n <AnimatePresence>\n {showEmojiPicker && (\n <motion.div\n key=\"emoji-picker\"\n ref={emojiPickerRef}\n initial={reduceMotion ? false : { opacity: 0, scale: 0.96, y: 4 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={reduceMotion ? { opacity: 0 } : { opacity: 0, scale: 0.96, y: 4 }}\n transition={{ duration: 0.14, ease: 'easeOut' }}\n className=\"absolute bottom-full right-0 z-popover mb-ds-02 origin-bottom-right\"\n onKeyDown={(e) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n setShowEmojiPicker(false)\n }\n }}\n >\n <EmojiPickerLazy\n onSelect={({ id, native }) => {\n editor.chain().focus().insertContent({\n type: 'emojiNode',\n attrs: { id, native },\n }).run()\n setShowEmojiPicker(false)\n }}\n />\n </motion.div>\n )}\n </AnimatePresence>\n <input\n ref={imageInputRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Upload image\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0]\n if (file) handleImageInsert(file)\n e.target.value = ''\n }}\n />\n {onFileUpload && (\n <input\n ref={fileInputRef}\n type=\"file\"\n aria-label=\"Upload file\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0]\n if (file) handleFileInsert(file)\n e.target.value = ''\n }}\n />\n )}\n {children}\n </div>\n </RTEContext.Provider>\n )\n},\n)\n\nRichTextEditorProvider.displayName = 'RichTextEditor.Provider'\n\n/**\n * The formatting toolbar. Reads the editor from `<RichTextEditor.Provider>`.\n * In source view the format controls hide but `trailing` (e.g. the source\n * toggle) stays, so the bar persists.\n */\nfunction RichTextEditorToolbarSlot({ trailing }: { trailing?: React.ReactNode }) {\n const { editor, toolbar, editable, sourceMode, onImageClick, onFileClick, onEmojiClick } = useRichTextEditor()\n if (!editable) return null\n const showControls = !sourceMode\n if (!showControls && !trailing) return null\n return (\n <Toolbar\n editor={editor}\n toolbar={toolbar}\n showControls={showControls}\n trailing={trailing}\n onImageClick={onImageClick}\n onFileClick={onFileClick}\n onEmojiClick={onEmojiClick}\n />\n )\n}\nRichTextEditorToolbarSlot.displayName = 'RichTextEditor.Toolbar'\n\n/** The content area — the visual editor, or a raw-Markdown textarea in source view. */\nfunction RichTextEditorContentSlot() {\n const { editor, sourceMode, sourceText, onSourceChange } = useRichTextEditor()\n const reduce = useReducedMotion()\n const enter = reduce ? { opacity: 0 } : { opacity: 0, y: 4 }\n return (\n <AnimatePresence mode=\"wait\" initial={false}>\n {sourceMode ? (\n <motion.div key=\"source\" initial={enter} animate={{ opacity: 1, y: 0 }} exit={enter} transition={{ duration: 0.14, ease: 'easeOut' }}>\n <textarea\n value={sourceText}\n onChange={(e) => onSourceChange(e.target.value)}\n spellCheck={false}\n aria-label=\"Markdown source\"\n className=\"block min-h-[120px] w-full resize-y bg-surface-panel px-ds-04 py-ds-04 font-mono text-body-sm leading-ds-relaxed text-surface-fg focus:outline-hidden\"\n />\n </motion.div>\n ) : (\n <motion.div key=\"visual\" initial={enter} animate={{ opacity: 1, y: 0 }} exit={enter} transition={{ duration: 0.14, ease: 'easeOut' }}>\n <EditorContent editor={editor} />\n </motion.div>\n )}\n </AnimatePresence>\n )\n}\nRichTextEditorContentSlot.displayName = 'RichTextEditor.Content'\n\n/**\n * A source-view toggle (raw Markdown ⇄ visual). Text + icon by default;\n * pass `iconOnly` for a compact button. Place it anywhere inside a Provider.\n */\nfunction RichTextEditorSourceToggleSlot({ className, iconOnly = false }: { className?: string; iconOnly?: boolean }) {\n const { sourceMode, toggleSource } = useRichTextEditor()\n const aria = sourceMode ? 'Switch to visual editor' : 'Switch to Markdown source'\n const icon = sourceMode ? IconEye : IconCode\n if (iconOnly) {\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-pressed={sourceMode}\n aria-label={aria}\n title={aria}\n className={className}\n onClick={toggleSource}\n >\n <Icon icon={icon} size=\"sm\" />\n </Button>\n )\n }\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-pressed={sourceMode}\n aria-label={aria}\n startIcon={icon}\n className={className}\n onClick={toggleSource}\n >\n {sourceMode ? 'Editor' : 'Markdown'}\n </Button>\n )\n}\nRichTextEditorSourceToggleSlot.displayName = 'RichTextEditor.SourceToggle'\n\n// Batteries-included default: Provider + bordered box + toolbar-over-content.\nconst RichTextEditorBase = React.forwardRef<HTMLDivElement, RichTextEditorProps>(\n function RichTextEditor(props, ref) {\n return (\n <RichTextEditorProvider ref={ref} {...props}>\n <div\n className={cn(\n 'overflow-hidden rounded-surface border border-surface-border-strong bg-surface-panel',\n 'transition-colors ease-productive-standard focus-within:border-surface-border-strong',\n )}\n >\n <RichTextEditorToolbarSlot\n trailing={props.sourceToggle ? <RichTextEditorSourceToggleSlot /> : undefined}\n />\n <RichTextEditorContentSlot />\n </div>\n </RichTextEditorProvider>\n )\n },\n)\nRichTextEditorBase.displayName = 'RichTextEditor'\n\nconst RichTextEditor = Object.assign(RichTextEditorBase, {\n Provider: RichTextEditorProvider,\n Toolbar: RichTextEditorToolbarSlot,\n Content: RichTextEditorContentSlot,\n SourceToggle: RichTextEditorSourceToggleSlot,\n})\n\nexport interface RichTextViewerProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'content'> {\n content: string\n /** Content format. `markdown` parses Markdown; `html` (default) parses HTML. @default 'html' */\n format?: 'html' | 'markdown'\n className?: string\n}\n\nconst RichTextViewer = React.forwardRef<HTMLDivElement, RichTextViewerProps>(\n function RichTextViewer({ content, format = 'html', className, ...props }, ref) {\n const editor = useEditor({\n immediatelyRender: false, // SSR-safe — prevents hydration mismatch in Next.js\n extensions: [\n StarterKit.configure({\n heading: { levels: [2, 3] },\n link: {\n openOnClick: true,\n protocols: ['http', 'https', 'mailto'],\n validate: (href: string) => /^(https?:\\/\\/|mailto:)/i.test(href),\n HTMLAttributes: {\n rel: 'noopener noreferrer',\n target: '_blank',\n },\n },\n }),\n Highlight.configure({ multicolor: false }),\n ListKit.configure({\n bulletList: false,\n orderedList: false,\n listItem: false,\n listKeymap: false,\n taskList: {},\n taskItem: { nested: true },\n }),\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Image.configure({\n allowBase64: true,\n HTMLAttributes: {\n class: 'max-w-full rounded-control',\n },\n }),\n FileAttachment,\n Mention.configure({\n HTMLAttributes: { class: 'mention' },\n }),\n Markdown,\n ],\n content,\n contentType: format === 'markdown' ? 'markdown' : undefined,\n editable: false,\n editorProps: {\n attributes: {\n class: cn(...PROSE_CLASSES),\n },\n },\n })\n\n if (!editor) return null\n\n return (\n <div ref={ref} {...props} className={className}>\n <EditorContent editor={editor} />\n </div>\n )\n},\n)\n\nRichTextViewer.displayName = 'RichTextViewer'\n\nexport {\n RichTextEditor,\n RichTextEditorProvider,\n RichTextEditorToolbarSlot as RichTextEditorToolbar,\n RichTextEditorContentSlot as RichTextEditorContent,\n RichTextEditorSourceToggleSlot as RichTextEditorSourceToggle,\n useRichTextEditor,\n RichTextViewer,\n}\n"],"mappings":"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"}
@@ -11,7 +11,7 @@ var p = {
11
11
  warning: "bg-warning-3 text-warning-11",
12
12
  error: "bg-error-3 text-error-11",
13
13
  info: "bg-info-3 text-info-11",
14
- neutral: "bg-surface-raised text-surface-fg-muted"
14
+ neutral: "bg-surface-panel-hover text-surface-fg-muted"
15
15
  }, m = {
16
16
  accent: "bg-accent-9",
17
17
  success: "bg-success-9",
@@ -89,7 +89,7 @@ function v({ dayIndex: a, date: o, events: f, startHour: h, endHour: _, slotDura
89
89
  return /* @__PURE__ */ i("div", {
90
90
  className: "flex min-w-ds-11 flex-1 flex-col",
91
91
  children: [D && /* @__PURE__ */ r("div", {
92
- className: e("border-b border-surface-border-strong py-ds-02 text-center text-body-sm font-semibold", N ? "bg-accent-2 text-accent-11" : "bg-surface-raised text-surface-fg"),
92
+ className: e("border-b border-surface-border-strong py-ds-02 text-center text-body-sm font-semibold", N ? "bg-accent-4 text-accent-11" : "bg-surface-panel text-surface-fg"),
93
93
  children: s(o, "EEE d")
94
94
  }), /* @__PURE__ */ i("div", {
95
95
  className: "relative flex-1",
@@ -99,7 +99,7 @@ function v({ dayIndex: a, date: o, events: f, startHour: h, endHour: _, slotDura
99
99
  "data-day": a,
100
100
  "data-slot": n,
101
101
  tabIndex: a === b.day && n === b.slot ? 0 : -1,
102
- className: e("block w-full min-h-ds-06 border-b transition-colors ease-productive-standard duration-fast-02", "hover:bg-surface-raised-hover", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-accent-9", n % 2 == 0 ? "border-surface-border-strong" : "border-surface-border-subtle"),
102
+ className: e("block w-full min-h-ds-06 border-b transition-colors ease-productive-standard duration-fast-02", "hover:bg-surface-panel-hover", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-accent-9", n % 2 == 0 ? "border-surface-border-strong" : "border-surface-border-subtle"),
103
103
  style: { height: `${100 / j}%` },
104
104
  onClick: () => E?.(t.start, t.end),
105
105
  onKeyDown: S,
@@ -114,7 +114,7 @@ function v({ dayIndex: a, date: o, events: f, startHour: h, endHour: _, slotDura
114
114
  return /* @__PURE__ */ r("button", {
115
115
  type: "button",
116
116
  "aria-pressed": d || void 0,
117
- className: e("absolute overflow-hidden rounded-control-inner px-ds-02 py-ds-01", "cursor-pointer text-start text-body-xs font-medium", "transition-[box-shadow] ease-productive-standard duration-fast-02 hover:shadow-raised", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9", "motion-safe:active:scale-[0.98]", d && "ring-2 ring-accent-9", p[l]),
117
+ className: e("absolute overflow-hidden rounded-control-inner px-ds-02 py-ds-01", "cursor-pointer text-start text-body-xs font-medium", "transition-colors ease-productive-standard duration-fast-02 hover:bg-surface-panel-hover", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9", "motion-safe:active:scale-[0.98]", d && "ring-2 ring-accent-9", p[l]),
118
118
  style: {
119
119
  top: `${n}%`,
120
120
  height: `${a}%`,
@@ -209,7 +209,7 @@ var y = n.forwardRef(({ view: t, date: o, events: c, onEventClick: l, onSlotClic
209
209
  ref: j,
210
210
  role: "region",
211
211
  "aria-label": t === "day" ? `Schedule for ${s(o, "EEEE, MMMM d, yyyy")}` : `Week schedule starting ${s(E[0], "MMMM d, yyyy")}`,
212
- className: "flex overflow-hidden rounded-surface border border-surface-border-strong bg-surface-raised",
212
+ className: "flex overflow-hidden rounded-surface border border-surface-border-strong bg-surface-panel",
213
213
  style: { height: typeof S == "number" ? `${S}px` : S },
214
214
  children: [/* @__PURE__ */ r(_, {
215
215
  startHour: p,
@@ -1 +1 @@
1
- {"version":3,"file":"schedule-view.js","names":[],"sources":["../../src/composed/schedule-view.tsx"],"sourcesContent":["'use client'\n\nimport {\n addDays,\n differenceInMinutes,\n format,\n getHours,\n getMinutes,\n isSameDay,\n isToday,\n startOfWeek,\n} from 'date-fns'\nimport * as React from 'react'\n\nimport { Dot } from '../ui/dot'\nimport { cn } from '../ui/lib/utils'\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface ScheduleEvent {\n id: string\n title: string\n start: Date\n end: Date\n color?: 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral'\n}\n\n/**\n * A day/week calendar schedule grid. Renders time-slotted events with\n * proportional height, color coding, overlapping-event columns, a live\n * current-time indicator, and keyboard-navigable slots (when `onSlotClick` is\n * set). Presentational — drive `events`/`date`/`view` from the parent.\n */\nexport interface ScheduleViewProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Display mode: single-day column or full-week (7 columns). */\n view: 'day' | 'week'\n /** Current day (day view) or any date within the target week (week view). */\n date: Date\n /** Events to display on the calendar grid. */\n events: ScheduleEvent[]\n /** Called when an event block is clicked. */\n onEventClick?: (event: ScheduleEvent) => void\n /**\n * Called when an empty time slot is clicked. When omitted, slots render as\n * non-interactive grid lines (no keyboard/AT tab stops).\n */\n onSlotClick?: (start: Date, end: Date) => void\n /** First visible hour (default 8). */\n startHour?: number\n /** Last visible hour -- exclusive (default 18). */\n endHour?: number\n /** Slot duration in minutes (default 30). */\n slotDuration?: number\n /** Currently-selected event id — rendered with a ring. */\n selectedEventId?: string\n /** Custom event content renderer. Receives the event; return the block body. */\n renderEvent?: (event: ScheduleEvent) => React.ReactNode\n /** Optional toolbar/header rendered above the grid. */\n header?: React.ReactNode\n /** Content shown when there are no events in view. */\n emptyState?: React.ReactNode\n /** Grid body height (CSS length or px number). @default 480 */\n height?: number | string\n}\n\n/* ------------------------------------------------------------------ */\n/* Color map */\n/* ------------------------------------------------------------------ */\n\nconst eventColorMap: Record<NonNullable<ScheduleEvent['color']>, string> = {\n accent: 'bg-accent-2 text-accent-11',\n success: 'bg-success-3 text-success-11',\n warning: 'bg-warning-3 text-warning-11',\n error: 'bg-error-3 text-error-11',\n info: 'bg-info-3 text-info-11',\n neutral: 'bg-surface-raised text-surface-fg-muted',\n}\n\nconst eventDotMap: Record<NonNullable<ScheduleEvent['color']>, string> = {\n accent: 'bg-accent-9',\n success: 'bg-success-9',\n warning: 'bg-warning-9',\n error: 'bg-error-9',\n info: 'bg-info-9',\n neutral: 'bg-surface-fg-subtle',\n}\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction formatHourLabel(hour: number): string {\n if (hour === 0) return '12 AM'\n if (hour < 12) return `${hour} AM`\n if (hour === 12) return '12 PM'\n return `${hour - 12} PM`\n}\n\ninterface PositionedEvent {\n event: ScheduleEvent\n top: number\n height: number\n col: number\n cols: number\n}\n\n/**\n * Position a day's events, partitioning concurrent events into side-by-side\n * columns so overlaps stay legible (greedy interval colouring per overlap\n * cluster).\n */\nfunction layoutDayEvents(\n events: ScheduleEvent[],\n startHour: number,\n endHour: number,\n): PositionedEvent[] {\n const totalMinutes = (endHour - startHour) * 60\n const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime())\n\n const result: PositionedEvent[] = []\n let cluster: PositionedEvent[] = []\n let clusterEnd = -Infinity\n\n const flush = () => {\n const cols = cluster.reduce((m, e) => Math.max(m, e.col + 1), 0)\n for (const e of cluster) e.cols = cols\n result.push(...cluster)\n cluster = []\n clusterEnd = -Infinity\n }\n\n for (const event of sorted) {\n const startM = (getHours(event.start) - startHour) * 60 + getMinutes(event.start)\n const durationM = Math.max(differenceInMinutes(event.end, event.start), 1)\n const startMs = event.start.getTime()\n\n // New cluster when this event starts after everything so far has ended.\n if (startMs >= clusterEnd && cluster.length > 0) flush()\n\n // First free column within the cluster.\n const taken = new Set(cluster.filter((c) => c.event.end.getTime() > startMs).map((c) => c.col))\n let col = 0\n while (taken.has(col)) col++\n\n cluster.push({\n event,\n top: (startM / totalMinutes) * 100,\n height: (durationM / totalMinutes) * 100,\n col,\n cols: 1,\n })\n clusterEnd = Math.max(clusterEnd, event.end.getTime())\n }\n if (cluster.length > 0) flush()\n\n return result\n}\n\n/* ------------------------------------------------------------------ */\n/* Time column */\n/* ------------------------------------------------------------------ */\n\nfunction TimeColumn({ startHour, endHour }: { startHour: number; endHour: number }) {\n const hours: number[] = []\n for (let h = startHour; h < endHour; h++) hours.push(h)\n const slotHeight = 100 / (endHour - startHour)\n\n return (\n <div className=\"relative w-ds-11 shrink-0 border-e border-surface-border-strong\" aria-hidden=\"true\">\n {hours.map((hour) => (\n <div\n key={hour}\n className=\"pe-ds-02 text-end text-caption text-surface-fg-muted\"\n style={{ height: `${slotHeight}%` }}\n >\n {formatHourLabel(hour)}\n </div>\n ))}\n </div>\n )\n}\n\n/* ------------------------------------------------------------------ */\n/* Day column */\n/* ------------------------------------------------------------------ */\n\ninterface DayColumnProps {\n dayIndex: number\n date: Date\n events: ScheduleEvent[]\n startHour: number\n endHour: number\n slotDuration: number\n now: Date\n active: { day: number; slot: number }\n interactive: boolean\n onSlotKeyDown?: (e: React.KeyboardEvent<HTMLButtonElement>) => void\n selectedEventId?: string\n renderEvent?: (event: ScheduleEvent) => React.ReactNode\n onEventClick?: (event: ScheduleEvent) => void\n onSlotClick?: (start: Date, end: Date) => void\n showHeader?: boolean\n nowLineRef?: React.Ref<HTMLDivElement>\n}\n\nfunction DayColumn({\n dayIndex,\n date,\n events,\n startHour,\n endHour,\n slotDuration,\n now,\n active,\n interactive,\n onSlotKeyDown,\n selectedEventId,\n renderEvent,\n onEventClick,\n onSlotClick,\n showHeader,\n nowLineRef,\n}: DayColumnProps) {\n const dayEvents = React.useMemo(\n () => layoutDayEvents(events.filter((e) => isSameDay(e.start, date)), startHour, endHour),\n [events, date, startHour, endHour],\n )\n const totalMinutes = (endHour - startHour) * 60\n const slotCount = totalMinutes / slotDuration\n\n const slots = React.useMemo(() => {\n const out: { start: Date; end: Date }[] = []\n for (let i = 0; i < slotCount; i++) {\n const slotStart = new Date(date)\n slotStart.setHours(startHour, i * slotDuration, 0, 0)\n const slotEnd = new Date(slotStart)\n slotEnd.setMinutes(slotEnd.getMinutes() + slotDuration)\n out.push({ start: slotStart, end: slotEnd })\n }\n return out\n }, [date, startHour, slotDuration, slotCount])\n\n const todayInView = isToday(date)\n let nowIndicatorTop: number | null = null\n if (todayInView) {\n const nowHour = getHours(now)\n if (nowHour >= startHour && nowHour < endHour) {\n const nowMinutes = (nowHour - startHour) * 60 + getMinutes(now)\n nowIndicatorTop = (nowMinutes / totalMinutes) * 100\n }\n }\n\n return (\n <div className=\"flex min-w-ds-11 flex-1 flex-col\">\n {showHeader && (\n <div\n className={cn(\n 'border-b border-surface-border-strong py-ds-02 text-center text-body-sm font-semibold',\n todayInView ? 'bg-accent-2 text-accent-11' : 'bg-surface-raised text-surface-fg',\n )}\n >\n {format(date, 'EEE d')}\n </div>\n )}\n <div className=\"relative flex-1\">\n {/* Slot lines — interactive buttons only when onSlotClick is set,\n otherwise inert grid lines (no tab stops, hidden from AT). */}\n {slots.map((slot, i) =>\n interactive ? (\n <button\n key={i}\n type=\"button\"\n data-day={dayIndex}\n data-slot={i}\n tabIndex={dayIndex === active.day && i === active.slot ? 0 : -1}\n className={cn(\n 'block w-full min-h-ds-06 border-b transition-colors ease-productive-standard duration-fast-02',\n 'hover:bg-surface-raised-hover',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-accent-9',\n i % 2 === 0 ? 'border-surface-border-strong' : 'border-surface-border-subtle',\n )}\n style={{ height: `${100 / slotCount}%` }}\n onClick={() => onSlotClick?.(slot.start, slot.end)}\n onKeyDown={onSlotKeyDown}\n aria-label={`${format(slot.start, 'EEE h:mm a')} to ${format(slot.end, 'h:mm a')}`}\n />\n ) : (\n <div\n key={i}\n aria-hidden=\"true\"\n className={cn(\n 'w-full border-b',\n i % 2 === 0 ? 'border-surface-border-strong' : 'border-surface-border-subtle',\n )}\n style={{ height: `${100 / slotCount}%` }}\n />\n ),\n )}\n\n {/* Events — column-partitioned so overlaps sit side by side */}\n {dayEvents.map(({ event, top, height, col, cols }) => {\n const eventColor = event.color ?? 'accent'\n const colWidth = 100 / cols\n const selected = event.id === selectedEventId\n return (\n <button\n key={event.id}\n type=\"button\"\n aria-pressed={selected || undefined}\n className={cn(\n 'absolute overflow-hidden rounded-control-inner px-ds-02 py-ds-01',\n 'cursor-pointer text-start text-body-xs font-medium',\n 'transition-[box-shadow] ease-productive-standard duration-fast-02 hover:shadow-raised',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9',\n 'motion-safe:active:scale-[0.98]',\n selected && 'ring-2 ring-accent-9',\n eventColorMap[eventColor],\n )}\n style={{\n top: `${top}%`,\n height: `${height}%`,\n insetInlineStart: `calc(${col * colWidth}% + 2px)`,\n width: `calc(${colWidth}% - 4px)`,\n }}\n onClick={(e) => {\n e.stopPropagation()\n onEventClick?.(event)\n }}\n aria-label={`${event.title}, ${format(event.start, 'h:mm a')} to ${format(event.end, 'h:mm a')}`}\n >\n {renderEvent ? (\n renderEvent(event)\n ) : (\n <span className=\"flex items-start gap-ds-02\">\n <span\n className={cn('mt-0.5 h-ds-03 w-ds-03 shrink-0 rounded-pill', eventDotMap[eventColor])}\n aria-hidden=\"true\"\n />\n <span className=\"line-clamp-2\">{event.title}</span>\n </span>\n )}\n </button>\n )\n })}\n\n {/* Live current-time indicator */}\n {nowIndicatorTop != null && (\n <div\n ref={nowLineRef}\n className=\"pointer-events-none absolute inset-x-0 z-raised h-ds-01 bg-error-9\"\n style={{ top: `${nowIndicatorTop}%` }}\n aria-hidden=\"true\"\n >\n <Dot color=\"error\" size=\"lg\" pulse className=\"absolute -translate-x-1/2 -translate-y-1/2\" />\n </div>\n )}\n </div>\n </div>\n )\n}\n\n/* ------------------------------------------------------------------ */\n/* ScheduleView */\n/* ------------------------------------------------------------------ */\n\nconst ScheduleView = React.forwardRef<HTMLDivElement, ScheduleViewProps>(\n (\n {\n view,\n date,\n events,\n onEventClick,\n onSlotClick,\n startHour = 8,\n endHour = 18,\n slotDuration = 30,\n selectedEventId,\n renderEvent,\n header,\n emptyState,\n height = 480,\n className,\n ...props\n },\n ref,\n ) => {\n const days = React.useMemo<Date[]>(() => {\n if (view === 'day') return [date]\n const weekStart = startOfWeek(date, { weekStartsOn: 1 })\n return Array.from({ length: 7 }, (_, i) => addDays(weekStart, i))\n }, [view, date])\n\n const interactive = !!onSlotClick\n const slotCount = ((endHour - startHour) * 60) / slotDuration\n\n // Live now-line: re-render each minute so the indicator actually ticks.\n const [now, setNow] = React.useState(() => new Date())\n React.useEffect(() => {\n const id = setInterval(() => setNow(new Date()), 60_000)\n return () => clearInterval(id)\n }, [])\n\n // Roving-tabindex slot navigation (only meaningful when interactive).\n const gridRef = React.useRef<HTMLDivElement>(null)\n const nowLineRef = React.useRef<HTMLDivElement>(null)\n const [active, setActive] = React.useState<{ day: number; slot: number }>({ day: 0, slot: 0 })\n\n // Scroll the now-line into view on mount.\n React.useEffect(() => {\n nowLineRef.current?.scrollIntoView({ block: 'center' })\n }, [])\n\n const handleSlotKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {\n if (!interactive) return\n const target = e.target as HTMLElement\n const dayAttr = target.getAttribute('data-day')\n const slotAttr = target.getAttribute('data-slot')\n if (dayAttr == null || slotAttr == null) return\n const day = Number(dayAttr)\n const slot = Number(slotAttr)\n const rtl = getComputedStyle(gridRef.current ?? target).direction === 'rtl'\n let nextDay = day\n let nextSlot = slot\n switch (e.key) {\n case 'ArrowDown': nextSlot = Math.min(slot + 1, slotCount - 1); break\n case 'ArrowUp': nextSlot = Math.max(slot - 1, 0); break\n case 'ArrowRight': nextDay = rtl ? Math.max(day - 1, 0) : Math.min(day + 1, days.length - 1); break\n case 'ArrowLeft': nextDay = rtl ? Math.min(day + 1, days.length - 1) : Math.max(day - 1, 0); break\n case 'Home': nextSlot = 0; break\n case 'End': nextSlot = slotCount - 1; break\n default: return\n }\n e.preventDefault()\n setActive({ day: nextDay, slot: nextSlot })\n // Focus the target cell now — focus() works regardless of the tabIndex\n // the re-render is about to move onto it.\n gridRef.current\n ?.querySelector<HTMLButtonElement>(`[data-day=\"${nextDay}\"][data-slot=\"${nextSlot}\"]`)\n ?.focus()\n }\n\n const isEmpty = events.length === 0\n\n return (\n <div ref={ref} className={cn('flex flex-col', className)} {...props}>\n {header}\n <div\n ref={gridRef}\n role=\"region\"\n aria-label={\n view === 'day'\n ? `Schedule for ${format(date, 'EEEE, MMMM d, yyyy')}`\n : `Week schedule starting ${format(days[0], 'MMMM d, yyyy')}`\n }\n className=\"flex overflow-hidden rounded-surface border border-surface-border-strong bg-surface-raised\"\n style={{ height: typeof height === 'number' ? `${height}px` : height }}\n >\n <TimeColumn startHour={startHour} endHour={endHour} />\n <div className=\"relative flex flex-1 divide-x divide-surface-border overflow-x-auto overflow-y-auto\">\n {days.map((day, i) => (\n <DayColumn\n key={day.toISOString()}\n dayIndex={i}\n date={day}\n events={events}\n startHour={startHour}\n endHour={endHour}\n slotDuration={slotDuration}\n now={now}\n active={active}\n interactive={interactive}\n onSlotKeyDown={handleSlotKeyDown}\n selectedEventId={selectedEventId}\n renderEvent={renderEvent}\n onEventClick={onEventClick}\n onSlotClick={onSlotClick}\n showHeader={view === 'week'}\n nowLineRef={i === 0 || isSameDay(day, now) ? nowLineRef : undefined}\n />\n ))}\n {isEmpty && (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center p-ds-05 text-center text-body-sm text-surface-fg-muted\">\n {emptyState ?? 'No events scheduled.'}\n </div>\n )}\n </div>\n </div>\n </div>\n )\n },\n)\nScheduleView.displayName = 'ScheduleView'\n\nexport { ScheduleView }\n"],"mappings":"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"}
1
+ {"version":3,"file":"schedule-view.js","names":[],"sources":["../../src/composed/schedule-view.tsx"],"sourcesContent":["'use client'\n\nimport {\n addDays,\n differenceInMinutes,\n format,\n getHours,\n getMinutes,\n isSameDay,\n isToday,\n startOfWeek,\n} from 'date-fns'\nimport * as React from 'react'\n\nimport { Dot } from '../ui/dot'\nimport { cn } from '../ui/lib/utils'\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface ScheduleEvent {\n id: string\n title: string\n start: Date\n end: Date\n color?: 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral'\n}\n\n/**\n * A day/week calendar schedule grid. Renders time-slotted events with\n * proportional height, color coding, overlapping-event columns, a live\n * current-time indicator, and keyboard-navigable slots (when `onSlotClick` is\n * set). Presentational — drive `events`/`date`/`view` from the parent.\n */\nexport interface ScheduleViewProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Display mode: single-day column or full-week (7 columns). */\n view: 'day' | 'week'\n /** Current day (day view) or any date within the target week (week view). */\n date: Date\n /** Events to display on the calendar grid. */\n events: ScheduleEvent[]\n /** Called when an event block is clicked. */\n onEventClick?: (event: ScheduleEvent) => void\n /**\n * Called when an empty time slot is clicked. When omitted, slots render as\n * non-interactive grid lines (no keyboard/AT tab stops).\n */\n onSlotClick?: (start: Date, end: Date) => void\n /** First visible hour (default 8). */\n startHour?: number\n /** Last visible hour -- exclusive (default 18). */\n endHour?: number\n /** Slot duration in minutes (default 30). */\n slotDuration?: number\n /** Currently-selected event id — rendered with a ring. */\n selectedEventId?: string\n /** Custom event content renderer. Receives the event; return the block body. */\n renderEvent?: (event: ScheduleEvent) => React.ReactNode\n /** Optional toolbar/header rendered above the grid. */\n header?: React.ReactNode\n /** Content shown when there are no events in view. */\n emptyState?: React.ReactNode\n /** Grid body height (CSS length or px number). @default 480 */\n height?: number | string\n}\n\n/* ------------------------------------------------------------------ */\n/* Color map */\n/* ------------------------------------------------------------------ */\n\nconst eventColorMap: Record<NonNullable<ScheduleEvent['color']>, string> = {\n accent: 'bg-accent-2 text-accent-11',\n success: 'bg-success-3 text-success-11',\n warning: 'bg-warning-3 text-warning-11',\n error: 'bg-error-3 text-error-11',\n info: 'bg-info-3 text-info-11',\n neutral: 'bg-surface-panel-hover text-surface-fg-muted',\n}\n\nconst eventDotMap: Record<NonNullable<ScheduleEvent['color']>, string> = {\n accent: 'bg-accent-9',\n success: 'bg-success-9',\n warning: 'bg-warning-9',\n error: 'bg-error-9',\n info: 'bg-info-9',\n neutral: 'bg-surface-fg-subtle',\n}\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction formatHourLabel(hour: number): string {\n if (hour === 0) return '12 AM'\n if (hour < 12) return `${hour} AM`\n if (hour === 12) return '12 PM'\n return `${hour - 12} PM`\n}\n\ninterface PositionedEvent {\n event: ScheduleEvent\n top: number\n height: number\n col: number\n cols: number\n}\n\n/**\n * Position a day's events, partitioning concurrent events into side-by-side\n * columns so overlaps stay legible (greedy interval colouring per overlap\n * cluster).\n */\nfunction layoutDayEvents(\n events: ScheduleEvent[],\n startHour: number,\n endHour: number,\n): PositionedEvent[] {\n const totalMinutes = (endHour - startHour) * 60\n const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime())\n\n const result: PositionedEvent[] = []\n let cluster: PositionedEvent[] = []\n let clusterEnd = -Infinity\n\n const flush = () => {\n const cols = cluster.reduce((m, e) => Math.max(m, e.col + 1), 0)\n for (const e of cluster) e.cols = cols\n result.push(...cluster)\n cluster = []\n clusterEnd = -Infinity\n }\n\n for (const event of sorted) {\n const startM = (getHours(event.start) - startHour) * 60 + getMinutes(event.start)\n const durationM = Math.max(differenceInMinutes(event.end, event.start), 1)\n const startMs = event.start.getTime()\n\n // New cluster when this event starts after everything so far has ended.\n if (startMs >= clusterEnd && cluster.length > 0) flush()\n\n // First free column within the cluster.\n const taken = new Set(cluster.filter((c) => c.event.end.getTime() > startMs).map((c) => c.col))\n let col = 0\n while (taken.has(col)) col++\n\n cluster.push({\n event,\n top: (startM / totalMinutes) * 100,\n height: (durationM / totalMinutes) * 100,\n col,\n cols: 1,\n })\n clusterEnd = Math.max(clusterEnd, event.end.getTime())\n }\n if (cluster.length > 0) flush()\n\n return result\n}\n\n/* ------------------------------------------------------------------ */\n/* Time column */\n/* ------------------------------------------------------------------ */\n\nfunction TimeColumn({ startHour, endHour }: { startHour: number; endHour: number }) {\n const hours: number[] = []\n for (let h = startHour; h < endHour; h++) hours.push(h)\n const slotHeight = 100 / (endHour - startHour)\n\n return (\n <div className=\"relative w-ds-11 shrink-0 border-e border-surface-border-strong\" aria-hidden=\"true\">\n {hours.map((hour) => (\n <div\n key={hour}\n className=\"pe-ds-02 text-end text-caption text-surface-fg-muted\"\n style={{ height: `${slotHeight}%` }}\n >\n {formatHourLabel(hour)}\n </div>\n ))}\n </div>\n )\n}\n\n/* ------------------------------------------------------------------ */\n/* Day column */\n/* ------------------------------------------------------------------ */\n\ninterface DayColumnProps {\n dayIndex: number\n date: Date\n events: ScheduleEvent[]\n startHour: number\n endHour: number\n slotDuration: number\n now: Date\n active: { day: number; slot: number }\n interactive: boolean\n onSlotKeyDown?: (e: React.KeyboardEvent<HTMLButtonElement>) => void\n selectedEventId?: string\n renderEvent?: (event: ScheduleEvent) => React.ReactNode\n onEventClick?: (event: ScheduleEvent) => void\n onSlotClick?: (start: Date, end: Date) => void\n showHeader?: boolean\n nowLineRef?: React.Ref<HTMLDivElement>\n}\n\nfunction DayColumn({\n dayIndex,\n date,\n events,\n startHour,\n endHour,\n slotDuration,\n now,\n active,\n interactive,\n onSlotKeyDown,\n selectedEventId,\n renderEvent,\n onEventClick,\n onSlotClick,\n showHeader,\n nowLineRef,\n}: DayColumnProps) {\n const dayEvents = React.useMemo(\n () => layoutDayEvents(events.filter((e) => isSameDay(e.start, date)), startHour, endHour),\n [events, date, startHour, endHour],\n )\n const totalMinutes = (endHour - startHour) * 60\n const slotCount = totalMinutes / slotDuration\n\n const slots = React.useMemo(() => {\n const out: { start: Date; end: Date }[] = []\n for (let i = 0; i < slotCount; i++) {\n const slotStart = new Date(date)\n slotStart.setHours(startHour, i * slotDuration, 0, 0)\n const slotEnd = new Date(slotStart)\n slotEnd.setMinutes(slotEnd.getMinutes() + slotDuration)\n out.push({ start: slotStart, end: slotEnd })\n }\n return out\n }, [date, startHour, slotDuration, slotCount])\n\n const todayInView = isToday(date)\n let nowIndicatorTop: number | null = null\n if (todayInView) {\n const nowHour = getHours(now)\n if (nowHour >= startHour && nowHour < endHour) {\n const nowMinutes = (nowHour - startHour) * 60 + getMinutes(now)\n nowIndicatorTop = (nowMinutes / totalMinutes) * 100\n }\n }\n\n return (\n <div className=\"flex min-w-ds-11 flex-1 flex-col\">\n {showHeader && (\n <div\n className={cn(\n 'border-b border-surface-border-strong py-ds-02 text-center text-body-sm font-semibold',\n todayInView ? 'bg-accent-4 text-accent-11' : 'bg-surface-panel text-surface-fg',\n )}\n >\n {format(date, 'EEE d')}\n </div>\n )}\n <div className=\"relative flex-1\">\n {/* Slot lines — interactive buttons only when onSlotClick is set,\n otherwise inert grid lines (no tab stops, hidden from AT). */}\n {slots.map((slot, i) =>\n interactive ? (\n <button\n key={i}\n type=\"button\"\n data-day={dayIndex}\n data-slot={i}\n tabIndex={dayIndex === active.day && i === active.slot ? 0 : -1}\n className={cn(\n 'block w-full min-h-ds-06 border-b transition-colors ease-productive-standard duration-fast-02',\n 'hover:bg-surface-panel-hover',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-accent-9',\n i % 2 === 0 ? 'border-surface-border-strong' : 'border-surface-border-subtle',\n )}\n style={{ height: `${100 / slotCount}%` }}\n onClick={() => onSlotClick?.(slot.start, slot.end)}\n onKeyDown={onSlotKeyDown}\n aria-label={`${format(slot.start, 'EEE h:mm a')} to ${format(slot.end, 'h:mm a')}`}\n />\n ) : (\n <div\n key={i}\n aria-hidden=\"true\"\n className={cn(\n 'w-full border-b',\n i % 2 === 0 ? 'border-surface-border-strong' : 'border-surface-border-subtle',\n )}\n style={{ height: `${100 / slotCount}%` }}\n />\n ),\n )}\n\n {/* Events — column-partitioned so overlaps sit side by side */}\n {dayEvents.map(({ event, top, height, col, cols }) => {\n const eventColor = event.color ?? 'accent'\n const colWidth = 100 / cols\n const selected = event.id === selectedEventId\n return (\n <button\n key={event.id}\n type=\"button\"\n aria-pressed={selected || undefined}\n className={cn(\n 'absolute overflow-hidden rounded-control-inner px-ds-02 py-ds-01',\n 'cursor-pointer text-start text-body-xs font-medium',\n 'transition-colors ease-productive-standard duration-fast-02 hover:bg-surface-panel-hover',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9',\n 'motion-safe:active:scale-[0.98]',\n selected && 'ring-2 ring-accent-9',\n eventColorMap[eventColor],\n )}\n style={{\n top: `${top}%`,\n height: `${height}%`,\n insetInlineStart: `calc(${col * colWidth}% + 2px)`,\n width: `calc(${colWidth}% - 4px)`,\n }}\n onClick={(e) => {\n e.stopPropagation()\n onEventClick?.(event)\n }}\n aria-label={`${event.title}, ${format(event.start, 'h:mm a')} to ${format(event.end, 'h:mm a')}`}\n >\n {renderEvent ? (\n renderEvent(event)\n ) : (\n <span className=\"flex items-start gap-ds-02\">\n <span\n className={cn('mt-0.5 h-ds-03 w-ds-03 shrink-0 rounded-pill', eventDotMap[eventColor])}\n aria-hidden=\"true\"\n />\n <span className=\"line-clamp-2\">{event.title}</span>\n </span>\n )}\n </button>\n )\n })}\n\n {/* Live current-time indicator */}\n {nowIndicatorTop != null && (\n <div\n ref={nowLineRef}\n className=\"pointer-events-none absolute inset-x-0 z-raised h-ds-01 bg-error-9\"\n style={{ top: `${nowIndicatorTop}%` }}\n aria-hidden=\"true\"\n >\n <Dot color=\"error\" size=\"lg\" pulse className=\"absolute -translate-x-1/2 -translate-y-1/2\" />\n </div>\n )}\n </div>\n </div>\n )\n}\n\n/* ------------------------------------------------------------------ */\n/* ScheduleView */\n/* ------------------------------------------------------------------ */\n\nconst ScheduleView = React.forwardRef<HTMLDivElement, ScheduleViewProps>(\n (\n {\n view,\n date,\n events,\n onEventClick,\n onSlotClick,\n startHour = 8,\n endHour = 18,\n slotDuration = 30,\n selectedEventId,\n renderEvent,\n header,\n emptyState,\n height = 480,\n className,\n ...props\n },\n ref,\n ) => {\n const days = React.useMemo<Date[]>(() => {\n if (view === 'day') return [date]\n const weekStart = startOfWeek(date, { weekStartsOn: 1 })\n return Array.from({ length: 7 }, (_, i) => addDays(weekStart, i))\n }, [view, date])\n\n const interactive = !!onSlotClick\n const slotCount = ((endHour - startHour) * 60) / slotDuration\n\n // Live now-line: re-render each minute so the indicator actually ticks.\n const [now, setNow] = React.useState(() => new Date())\n React.useEffect(() => {\n const id = setInterval(() => setNow(new Date()), 60_000)\n return () => clearInterval(id)\n }, [])\n\n // Roving-tabindex slot navigation (only meaningful when interactive).\n const gridRef = React.useRef<HTMLDivElement>(null)\n const nowLineRef = React.useRef<HTMLDivElement>(null)\n const [active, setActive] = React.useState<{ day: number; slot: number }>({ day: 0, slot: 0 })\n\n // Scroll the now-line into view on mount.\n React.useEffect(() => {\n nowLineRef.current?.scrollIntoView({ block: 'center' })\n }, [])\n\n const handleSlotKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {\n if (!interactive) return\n const target = e.target as HTMLElement\n const dayAttr = target.getAttribute('data-day')\n const slotAttr = target.getAttribute('data-slot')\n if (dayAttr == null || slotAttr == null) return\n const day = Number(dayAttr)\n const slot = Number(slotAttr)\n const rtl = getComputedStyle(gridRef.current ?? target).direction === 'rtl'\n let nextDay = day\n let nextSlot = slot\n switch (e.key) {\n case 'ArrowDown': nextSlot = Math.min(slot + 1, slotCount - 1); break\n case 'ArrowUp': nextSlot = Math.max(slot - 1, 0); break\n case 'ArrowRight': nextDay = rtl ? Math.max(day - 1, 0) : Math.min(day + 1, days.length - 1); break\n case 'ArrowLeft': nextDay = rtl ? Math.min(day + 1, days.length - 1) : Math.max(day - 1, 0); break\n case 'Home': nextSlot = 0; break\n case 'End': nextSlot = slotCount - 1; break\n default: return\n }\n e.preventDefault()\n setActive({ day: nextDay, slot: nextSlot })\n // Focus the target cell now — focus() works regardless of the tabIndex\n // the re-render is about to move onto it.\n gridRef.current\n ?.querySelector<HTMLButtonElement>(`[data-day=\"${nextDay}\"][data-slot=\"${nextSlot}\"]`)\n ?.focus()\n }\n\n const isEmpty = events.length === 0\n\n return (\n <div ref={ref} className={cn('flex flex-col', className)} {...props}>\n {header}\n <div\n ref={gridRef}\n role=\"region\"\n aria-label={\n view === 'day'\n ? `Schedule for ${format(date, 'EEEE, MMMM d, yyyy')}`\n : `Week schedule starting ${format(days[0], 'MMMM d, yyyy')}`\n }\n className=\"flex overflow-hidden rounded-surface border border-surface-border-strong bg-surface-panel\"\n style={{ height: typeof height === 'number' ? `${height}px` : height }}\n >\n <TimeColumn startHour={startHour} endHour={endHour} />\n <div className=\"relative flex flex-1 divide-x divide-surface-border overflow-x-auto overflow-y-auto\">\n {days.map((day, i) => (\n <DayColumn\n key={day.toISOString()}\n dayIndex={i}\n date={day}\n events={events}\n startHour={startHour}\n endHour={endHour}\n slotDuration={slotDuration}\n now={now}\n active={active}\n interactive={interactive}\n onSlotKeyDown={handleSlotKeyDown}\n selectedEventId={selectedEventId}\n renderEvent={renderEvent}\n onEventClick={onEventClick}\n onSlotClick={onSlotClick}\n showHeader={view === 'week'}\n nowLineRef={i === 0 || isSameDay(day, now) ? nowLineRef : undefined}\n />\n ))}\n {isEmpty && (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center p-ds-05 text-center text-body-sm text-surface-fg-muted\">\n {emptyState ?? 'No events scheduled.'}\n </div>\n )}\n </div>\n </div>\n </div>\n )\n },\n)\nScheduleView.displayName = 'ScheduleView'\n\nexport { ScheduleView }\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"status-badge.d.ts","sourceRoot":"","sources":["../../src/composed/status-badge.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAGrD;;;;GAIG;AACH,KAAK,SAAS,GACV,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,GAC5D,SAAS,GAAG,aAAa,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAA;AAkBhE,KAAK,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;AAEvE,UAAU,oBAAqB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IACtG,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;AAED,UAAU,qBAAsB,SAAQ,oBAAoB;IAC1D,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd;AAED,UAAU,oBAAqB,SAAQ,oBAAoB;IACzD,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,KAAK,EAAE,WAAW,CAAA;CACnB;AAED,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,GAAG,oBAAoB,CAAA;AAO3E,QAAA,MAAM,WAAW,sFAsChB,CAAA;AAGD,OAAO,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"status-badge.d.ts","sourceRoot":"","sources":["../../src/composed/status-badge.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAGrD;;;;GAIG;AACH,KAAK,SAAS,GACV,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,GAC5D,SAAS,GAAG,aAAa,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAA;AAkBhE,KAAK,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;AAEvE,UAAU,oBAAqB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IACtG,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;AAED,UAAU,qBAAsB,SAAQ,oBAAoB;IAC1D,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd;AAED,UAAU,oBAAqB,SAAQ,oBAAoB;IACzD,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,KAAK,EAAE,WAAW,CAAA;CACnB;AAED,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,GAAG,oBAAoB,CAAA;AAO3E,QAAA,MAAM,WAAW,sFAwChB,CAAA;AAGD,OAAO,EAAE,WAAW,EAAE,CAAA"}
@@ -1,13 +1,14 @@
1
1
  "use client";
2
2
  import { motionProps as e } from "../ui/lib/motion.js";
3
- import { Dot as t } from "../ui/dot.js";
4
- import { BadgeCompound as n } from "../_chunks/badge-group.js";
5
- import * as r from "react";
6
- import { jsx as i } from "react/jsx-runtime";
7
- import { IconChevronDown as a } from "@tabler/icons-react";
8
- import { AnimatePresence as o, motion as s } from "framer-motion";
3
+ import { MotionPreference as t } from "../_chunks/motion-preference.js";
4
+ import { Dot as n } from "../ui/dot.js";
5
+ import { BadgeCompound as r } from "../_chunks/badge-group.js";
6
+ import * as i from "react";
7
+ import { jsx as a } from "react/jsx-runtime";
8
+ import { IconChevronDown as o } from "@tabler/icons-react";
9
+ import { AnimatePresence as s, motion as c } from "framer-motion";
9
10
  //#region src/composed/status-badge.tsx
10
- var c = {
11
+ var l = {
11
12
  active: "success",
12
13
  approved: "success",
13
14
  completed: "success",
@@ -18,14 +19,14 @@ var c = {
18
19
  review: "info",
19
20
  cancelled: "neutral",
20
21
  draft: "neutral"
21
- }, l = {
22
+ }, u = {
22
23
  duration: .3,
23
24
  ease: "easeOut"
24
- }, u = (e) => e.charAt(0).toUpperCase() + e.slice(1), d = r.forwardRef(({ status: r, color: d, size: f = "md", label: p, hideDot: m = !1, onClick: h, icon: g, className: _, ...v }, y) => {
25
- let b = d ?? r ?? "pending", x = d ?? c[r ?? "pending"], S = p ?? u(d ?? r ?? "pending").replace("-", " "), C = g ?? (h == null ? void 0 : a);
26
- return /* @__PURE__ */ i(o, {
25
+ }, d = (e) => e.charAt(0).toUpperCase() + e.slice(1), f = i.forwardRef(({ status: i, color: f, size: p = "md", label: m, hideDot: h = !1, onClick: g, icon: _, className: v, ...y }, b) => {
26
+ let x = f ?? i ?? "pending", S = f ?? l[i ?? "pending"], C = m ?? d(f ?? i ?? "pending").replace("-", " "), w = _ ?? (g == null ? void 0 : o);
27
+ return /* @__PURE__ */ a(t, { children: /* @__PURE__ */ a(s, {
27
28
  mode: "wait",
28
- children: /* @__PURE__ */ i(s.span, {
29
+ children: /* @__PURE__ */ a(c.span, {
29
30
  initial: {
30
31
  opacity: .6,
31
32
  scale: .95
@@ -38,26 +39,26 @@ var c = {
38
39
  opacity: .6,
39
40
  scale: .95
40
41
  },
41
- transition: l,
42
+ transition: u,
42
43
  className: "inline-flex",
43
- ...e(v),
44
- children: /* @__PURE__ */ i(n, {
45
- ref: y,
44
+ ...e(y),
45
+ children: /* @__PURE__ */ a(r, {
46
+ ref: b,
46
47
  variant: "soft",
47
- color: x,
48
- size: f,
49
- onClick: h,
50
- startIcon: m ? void 0 : /* @__PURE__ */ i(t, {
51
- color: x,
48
+ color: S,
49
+ size: p,
50
+ onClick: g,
51
+ startIcon: h ? void 0 : /* @__PURE__ */ a(n, {
52
+ color: S,
52
53
  size: "sm"
53
54
  }),
54
- endIcon: C,
55
- className: _,
56
- children: S
55
+ endIcon: w,
56
+ className: v,
57
+ children: C
57
58
  })
58
- }, b)
59
- });
59
+ }, x)
60
+ }) });
60
61
  });
61
- d.displayName = "StatusBadge";
62
+ f.displayName = "StatusBadge";
62
63
  //#endregion
63
- export { d as StatusBadge };
64
+ export { f as StatusBadge };