@giddaa-housing/ui 0.1.0 → 1.1.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 (315) hide show
  1. package/README.md +18 -6
  2. package/css/base.css +37 -0
  3. package/css/components.css +135 -0
  4. package/css/generated/shared.css +1 -0
  5. package/css/giddaa.css +402 -0
  6. package/css/preset.css +77 -0
  7. package/css/styles.css +2 -0
  8. package/css/theme.css +255 -0
  9. package/dist/accordion.d.ts +9 -10
  10. package/dist/accordion.js +41 -117
  11. package/dist/activity-timeline.d.ts +29 -0
  12. package/dist/activity-timeline.js +97 -0
  13. package/dist/alert.d.ts +8 -9
  14. package/dist/alert.js +53 -141
  15. package/dist/auth-layout.d.ts +23 -0
  16. package/dist/auth-layout.js +153 -0
  17. package/dist/avatar.d.ts +6 -6
  18. package/dist/avatar.js +40 -142
  19. package/dist/badge.d.ts +12 -13
  20. package/dist/badge.js +66 -114
  21. package/dist/bar-chart.d.ts +136 -114
  22. package/dist/bar-chart.js +244 -297
  23. package/dist/breadcrumb.d.ts +5 -5
  24. package/dist/breadcrumb.js +56 -148
  25. package/dist/bullet-chart.d.ts +33 -33
  26. package/dist/bullet-chart.js +123 -183
  27. package/dist/button-BZIeyUw6.d.ts +17 -0
  28. package/dist/button-group.d.ts +13 -16
  29. package/dist/button-group.js +38 -163
  30. package/dist/button.d.ts +2 -19
  31. package/dist/button.js +90 -142
  32. package/dist/calendar.d.ts +6 -6
  33. package/dist/calendar.js +134 -288
  34. package/dist/card.d.ts +14 -16
  35. package/dist/card.js +58 -174
  36. package/dist/carousel.d.ts +34 -35
  37. package/dist/carousel.js +319 -378
  38. package/dist/chart.d.ts +58 -59
  39. package/dist/chart.js +350 -466
  40. package/dist/checkbox.d.ts +10 -12
  41. package/dist/checkbox.js +84 -84
  42. package/dist/cn-BI_4DMBf.js +23 -0
  43. package/dist/collapsible.d.ts +7 -8
  44. package/dist/collapsible.js +23 -77
  45. package/dist/combobox.d.ts +10 -10
  46. package/dist/combobox.js +220 -696
  47. package/dist/cta.d.ts +64 -0
  48. package/dist/cta.js +192 -0
  49. package/dist/currency-selector.d.ts +41 -0
  50. package/dist/currency-selector.js +114 -0
  51. package/dist/data-table.d.ts +164 -0
  52. package/dist/data-table.js +673 -0
  53. package/dist/date-picker.d.ts +27 -20
  54. package/dist/date-picker.js +122 -520
  55. package/dist/details-card.d.ts +19 -0
  56. package/dist/details-card.js +118 -0
  57. package/dist/dialog.d.ts +13 -14
  58. package/dist/dialog.js +117 -320
  59. package/dist/dropdown-menu.d.ts +14 -14
  60. package/dist/dropdown-menu.js +170 -365
  61. package/dist/dropzone.d.ts +55 -55
  62. package/dist/dropzone.js +328 -467
  63. package/dist/editorial-card.d.ts +27 -0
  64. package/dist/editorial-card.js +144 -0
  65. package/dist/empty-state.d.ts +8 -9
  66. package/dist/empty-state.js +48 -135
  67. package/dist/field.d.ts +23 -25
  68. package/dist/field.js +111 -327
  69. package/dist/filter.d.ts +118 -0
  70. package/dist/filter.js +775 -0
  71. package/dist/footer.d.ts +40 -0
  72. package/dist/footer.js +227 -0
  73. package/dist/funnel-chart.d.ts +38 -41
  74. package/dist/funnel-chart.js +168 -563
  75. package/dist/gallery-indicator.d.ts +17 -0
  76. package/dist/gallery-indicator.js +75 -0
  77. package/dist/heatmap-chart.d.ts +95 -0
  78. package/dist/heatmap-chart.js +197 -0
  79. package/dist/infotip.d.ts +10 -0
  80. package/dist/infotip.js +40 -0
  81. package/dist/input-CfoEJ8A6.d.ts +12 -0
  82. package/dist/input-group.d.ts +16 -19
  83. package/dist/input-group.js +92 -372
  84. package/dist/input-size-context-C-SFx9sx.d.ts +10 -0
  85. package/dist/input-size-context.d.ts +2 -11
  86. package/dist/input-size-context.js +14 -20
  87. package/dist/input.d.ts +2 -13
  88. package/dist/input.js +23 -79
  89. package/dist/item.d.ts +7 -8
  90. package/dist/item.js +22 -89
  91. package/dist/kpi-card.d.ts +18 -20
  92. package/dist/kpi-card.js +84 -232
  93. package/dist/label.d.ts +6 -6
  94. package/dist/label.js +39 -66
  95. package/dist/line-chart.d.ts +88 -89
  96. package/dist/line-chart.js +143 -262
  97. package/dist/logo.d.ts +4 -4
  98. package/dist/logo.js +87 -141
  99. package/dist/map-indicator.d.ts +13 -0
  100. package/dist/map-indicator.js +83 -0
  101. package/dist/match.d.ts +15 -0
  102. package/dist/match.js +68 -0
  103. package/dist/media-gallery-hero.d.ts +58 -0
  104. package/dist/media-gallery-hero.js +201 -0
  105. package/dist/media-player.d.ts +60 -0
  106. package/dist/media-player.js +919 -0
  107. package/dist/multi-step-form.d.ts +56 -0
  108. package/dist/multi-step-form.js +342 -0
  109. package/dist/number-input.d.ts +34 -34
  110. package/dist/number-input.js +62 -413
  111. package/dist/page-header.d.ts +10 -11
  112. package/dist/page-header.js +34 -107
  113. package/dist/pagination.d.ts +17 -20
  114. package/dist/pagination.js +132 -341
  115. package/dist/password-input.d.ts +5 -12
  116. package/dist/password-input.js +32 -354
  117. package/dist/phone-input.d.ts +19 -19
  118. package/dist/phone-input.js +232 -561
  119. package/dist/photo-gallery.d.ts +20 -20
  120. package/dist/photo-gallery.js +314 -746
  121. package/dist/picker-lzgmsNfG.js +32 -0
  122. package/dist/pie-chart.d.ts +60 -60
  123. package/dist/pie-chart.js +141 -184
  124. package/dist/popover.d.ts +9 -9
  125. package/dist/popover.js +60 -156
  126. package/dist/price-tag.d.ts +34 -0
  127. package/dist/price-tag.js +118 -0
  128. package/dist/progress.d.ts +18 -16
  129. package/dist/progress.js +156 -300
  130. package/dist/property-listing-card.d.ts +29 -0
  131. package/dist/property-listing-card.js +117 -0
  132. package/dist/radar-chart.d.ts +108 -0
  133. package/dist/radar-chart.js +172 -0
  134. package/dist/radio-group.d.ts +11 -13
  135. package/dist/radio-group.js +47 -96
  136. package/dist/review-block.d.ts +18 -0
  137. package/dist/review-block.js +154 -0
  138. package/dist/rich-text-editor.d.ts +30 -14
  139. package/dist/rich-text-editor.js +594 -979
  140. package/dist/scatter-chart.d.ts +140 -0
  141. package/dist/scatter-chart.js +248 -0
  142. package/dist/search-input.d.ts +8 -15
  143. package/dist/search-input.js +58 -408
  144. package/dist/select.d.ts +8 -8
  145. package/dist/select.js +131 -291
  146. package/dist/separator.d.ts +8 -9
  147. package/dist/separator.js +31 -70
  148. package/dist/sheet.d.ts +11 -11
  149. package/dist/sheet.js +84 -262
  150. package/dist/sidebar.d.ts +32 -37
  151. package/dist/sidebar.js +380 -1055
  152. package/dist/size-context-D4mYvcg8.d.ts +10 -0
  153. package/dist/size-context.d.ts +2 -11
  154. package/dist/size-context.js +14 -18
  155. package/dist/skeleton.d.ts +4 -5
  156. package/dist/skeleton.js +9 -45
  157. package/dist/slider.d.ts +27 -0
  158. package/dist/slider.js +81 -0
  159. package/dist/sparkline.d.ts +43 -46
  160. package/dist/sparkline.js +223 -561
  161. package/dist/stepper.d.ts +23 -24
  162. package/dist/stepper.js +149 -276
  163. package/dist/styles.css +9995 -2
  164. package/dist/switch.d.ts +10 -12
  165. package/dist/switch.js +49 -106
  166. package/dist/table-card.d.ts +35 -0
  167. package/dist/table-card.js +125 -0
  168. package/dist/table.d.ts +18 -14
  169. package/dist/table.js +114 -182
  170. package/dist/tabs.d.ts +23 -15
  171. package/dist/tabs.js +62 -149
  172. package/dist/tag.d.ts +22 -23
  173. package/dist/tag.js +104 -156
  174. package/dist/testimonial-block.d.ts +33 -0
  175. package/dist/testimonial-block.js +208 -0
  176. package/dist/textarea-IS_D8pXf.d.ts +11 -0
  177. package/dist/textarea.d.ts +2 -12
  178. package/dist/textarea.js +20 -74
  179. package/dist/time-picker.d.ts +11 -11
  180. package/dist/time-picker.js +247 -464
  181. package/dist/toast.d.ts +16 -18
  182. package/dist/toast.js +154 -310
  183. package/dist/tooltip.d.ts +9 -10
  184. package/dist/tooltip.js +33 -91
  185. package/dist/tree-map.d.ts +54 -57
  186. package/dist/tree-map.js +231 -646
  187. package/dist/use-uncontrolled-CLfM1XbB.js +21 -0
  188. package/dist/waterfall-chart.d.ts +126 -0
  189. package/dist/waterfall-chart.js +480 -0
  190. package/package.json +123 -34
  191. package/dist/accordion.js.map +0 -1
  192. package/dist/alert.js.map +0 -1
  193. package/dist/avatar.js.map +0 -1
  194. package/dist/badge.js.map +0 -1
  195. package/dist/bar-chart.js.map +0 -1
  196. package/dist/base.css +0 -32
  197. package/dist/breadcrumb.js.map +0 -1
  198. package/dist/bullet-chart.js.map +0 -1
  199. package/dist/button-group.js.map +0 -1
  200. package/dist/button.js.map +0 -1
  201. package/dist/calendar.js.map +0 -1
  202. package/dist/card.js.map +0 -1
  203. package/dist/carousel.js.map +0 -1
  204. package/dist/chart.js.map +0 -1
  205. package/dist/checkbox.js.map +0 -1
  206. package/dist/collapsible.js.map +0 -1
  207. package/dist/combobox.js.map +0 -1
  208. package/dist/date-picker.js.map +0 -1
  209. package/dist/dialog.js.map +0 -1
  210. package/dist/dropdown-menu.js.map +0 -1
  211. package/dist/dropzone.js.map +0 -1
  212. package/dist/empty-state.js.map +0 -1
  213. package/dist/field.js.map +0 -1
  214. package/dist/files/red-hat-display-latin-300-italic.woff +0 -0
  215. package/dist/files/red-hat-display-latin-300-italic.woff2 +0 -0
  216. package/dist/files/red-hat-display-latin-300-normal.woff +0 -0
  217. package/dist/files/red-hat-display-latin-300-normal.woff2 +0 -0
  218. package/dist/files/red-hat-display-latin-400-italic.woff +0 -0
  219. package/dist/files/red-hat-display-latin-400-italic.woff2 +0 -0
  220. package/dist/files/red-hat-display-latin-400-normal.woff +0 -0
  221. package/dist/files/red-hat-display-latin-400-normal.woff2 +0 -0
  222. package/dist/files/red-hat-display-latin-500-italic.woff +0 -0
  223. package/dist/files/red-hat-display-latin-500-italic.woff2 +0 -0
  224. package/dist/files/red-hat-display-latin-500-normal.woff +0 -0
  225. package/dist/files/red-hat-display-latin-500-normal.woff2 +0 -0
  226. package/dist/files/red-hat-display-latin-600-italic.woff +0 -0
  227. package/dist/files/red-hat-display-latin-600-italic.woff2 +0 -0
  228. package/dist/files/red-hat-display-latin-600-normal.woff +0 -0
  229. package/dist/files/red-hat-display-latin-600-normal.woff2 +0 -0
  230. package/dist/files/red-hat-display-latin-700-italic.woff +0 -0
  231. package/dist/files/red-hat-display-latin-700-italic.woff2 +0 -0
  232. package/dist/files/red-hat-display-latin-700-normal.woff +0 -0
  233. package/dist/files/red-hat-display-latin-700-normal.woff2 +0 -0
  234. package/dist/files/red-hat-display-latin-800-italic.woff +0 -0
  235. package/dist/files/red-hat-display-latin-800-italic.woff2 +0 -0
  236. package/dist/files/red-hat-display-latin-800-normal.woff +0 -0
  237. package/dist/files/red-hat-display-latin-800-normal.woff2 +0 -0
  238. package/dist/files/red-hat-display-latin-900-italic.woff +0 -0
  239. package/dist/files/red-hat-display-latin-900-italic.woff2 +0 -0
  240. package/dist/files/red-hat-display-latin-900-normal.woff +0 -0
  241. package/dist/files/red-hat-display-latin-900-normal.woff2 +0 -0
  242. package/dist/files/red-hat-display-latin-ext-300-italic.woff +0 -0
  243. package/dist/files/red-hat-display-latin-ext-300-italic.woff2 +0 -0
  244. package/dist/files/red-hat-display-latin-ext-300-normal.woff +0 -0
  245. package/dist/files/red-hat-display-latin-ext-300-normal.woff2 +0 -0
  246. package/dist/files/red-hat-display-latin-ext-400-italic.woff +0 -0
  247. package/dist/files/red-hat-display-latin-ext-400-italic.woff2 +0 -0
  248. package/dist/files/red-hat-display-latin-ext-400-normal.woff +0 -0
  249. package/dist/files/red-hat-display-latin-ext-400-normal.woff2 +0 -0
  250. package/dist/files/red-hat-display-latin-ext-500-italic.woff +0 -0
  251. package/dist/files/red-hat-display-latin-ext-500-italic.woff2 +0 -0
  252. package/dist/files/red-hat-display-latin-ext-500-normal.woff +0 -0
  253. package/dist/files/red-hat-display-latin-ext-500-normal.woff2 +0 -0
  254. package/dist/files/red-hat-display-latin-ext-600-italic.woff +0 -0
  255. package/dist/files/red-hat-display-latin-ext-600-italic.woff2 +0 -0
  256. package/dist/files/red-hat-display-latin-ext-600-normal.woff +0 -0
  257. package/dist/files/red-hat-display-latin-ext-600-normal.woff2 +0 -0
  258. package/dist/files/red-hat-display-latin-ext-700-italic.woff +0 -0
  259. package/dist/files/red-hat-display-latin-ext-700-italic.woff2 +0 -0
  260. package/dist/files/red-hat-display-latin-ext-700-normal.woff +0 -0
  261. package/dist/files/red-hat-display-latin-ext-700-normal.woff2 +0 -0
  262. package/dist/files/red-hat-display-latin-ext-800-italic.woff +0 -0
  263. package/dist/files/red-hat-display-latin-ext-800-italic.woff2 +0 -0
  264. package/dist/files/red-hat-display-latin-ext-800-normal.woff +0 -0
  265. package/dist/files/red-hat-display-latin-ext-800-normal.woff2 +0 -0
  266. package/dist/files/red-hat-display-latin-ext-900-italic.woff +0 -0
  267. package/dist/files/red-hat-display-latin-ext-900-italic.woff2 +0 -0
  268. package/dist/files/red-hat-display-latin-ext-900-normal.woff +0 -0
  269. package/dist/files/red-hat-display-latin-ext-900-normal.woff2 +0 -0
  270. package/dist/funnel-chart.js.map +0 -1
  271. package/dist/index.d.ts +0 -87
  272. package/dist/index.js +0 -10448
  273. package/dist/index.js.map +0 -1
  274. package/dist/input-group.js.map +0 -1
  275. package/dist/input-size-context.js.map +0 -1
  276. package/dist/input.js.map +0 -1
  277. package/dist/item.js.map +0 -1
  278. package/dist/kpi-card.js.map +0 -1
  279. package/dist/label.js.map +0 -1
  280. package/dist/line-chart.js.map +0 -1
  281. package/dist/logo.js.map +0 -1
  282. package/dist/number-input.js.map +0 -1
  283. package/dist/page-header.js.map +0 -1
  284. package/dist/pagination.js.map +0 -1
  285. package/dist/password-input.js.map +0 -1
  286. package/dist/phone-input.js.map +0 -1
  287. package/dist/photo-gallery.js.map +0 -1
  288. package/dist/pie-chart.js.map +0 -1
  289. package/dist/popover.js.map +0 -1
  290. package/dist/progress.js.map +0 -1
  291. package/dist/radio-group.js.map +0 -1
  292. package/dist/red-hat-display.css +0 -2
  293. package/dist/rich-text-editor.js.map +0 -1
  294. package/dist/search-input.js.map +0 -1
  295. package/dist/select.js.map +0 -1
  296. package/dist/separator.js.map +0 -1
  297. package/dist/sheet.js.map +0 -1
  298. package/dist/sidebar.js.map +0 -1
  299. package/dist/size-context.js.map +0 -1
  300. package/dist/skeleton.js.map +0 -1
  301. package/dist/sparkline.js.map +0 -1
  302. package/dist/stepper.js.map +0 -1
  303. package/dist/switch.js.map +0 -1
  304. package/dist/tab-list.d.ts +0 -38
  305. package/dist/tab-list.js +0 -394
  306. package/dist/tab-list.js.map +0 -1
  307. package/dist/table.js.map +0 -1
  308. package/dist/tabs.js.map +0 -1
  309. package/dist/tag.js.map +0 -1
  310. package/dist/textarea.js.map +0 -1
  311. package/dist/theme/giddaa.css +0 -2
  312. package/dist/time-picker.js.map +0 -1
  313. package/dist/toast.js.map +0 -1
  314. package/dist/tooltip.js.map +0 -1
  315. package/dist/tree-map.js.map +0 -1
@@ -1,4 +1,13 @@
1
- // src/components/ui/rich-text-editor.tsx
1
+ "use client";
2
+ import { t as cn } from "./cn-BI_4DMBf.js";
3
+ import { useComponentSize } from "./size-context.js";
4
+ import { Button } from "./button.js";
5
+ import { Input } from "./input.js";
6
+ import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
7
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from "./dropdown-menu.js";
8
+ import { AlignCenter, AlignJustify, AlignLeft, AlignRight, Baseline, Bold, ChevronDown, Code2, ImageIcon, Italic, Link2, List, ListOrdered, Quote, Redo2, Underline, Undo2 } from "lucide-react";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ import * as React from "react";
2
11
  import { Color } from "@tiptap/extension-color";
3
12
  import { Image } from "@tiptap/extension-image";
4
13
  import { Placeholder } from "@tiptap/extension-placeholder";
@@ -6,995 +15,601 @@ import { TextAlign } from "@tiptap/extension-text-align";
6
15
  import { TextStyle } from "@tiptap/extension-text-style";
7
16
  import { EditorContent, useEditor, useEditorState } from "@tiptap/react";
8
17
  import { StarterKit } from "@tiptap/starter-kit";
9
- import {
10
- AlignCenter,
11
- AlignJustify,
12
- AlignLeft,
13
- AlignRight,
14
- Baseline,
15
- Bold,
16
- ChevronDown,
17
- Code2,
18
- ImageIcon,
19
- Italic,
20
- Link2,
21
- List,
22
- ListOrdered,
23
- Quote,
24
- Redo2,
25
- Underline,
26
- Undo2
27
- } from "lucide-react";
28
- import * as React from "react";
29
-
30
- // src/lib/cn.ts
31
- import { clsx } from "clsx";
32
- import { extendTailwindMerge } from "tailwind-merge";
33
- var twMerge = extendTailwindMerge({
34
- extend: {
35
- classGroups: {
36
- "font-size": [
37
- {
38
- text: [
39
- "gdt-display",
40
- "gdt-h1",
41
- "gdt-h2",
42
- "gdt-h3",
43
- "gdt-h4",
44
- "gdt-h5",
45
- "gdt-xl",
46
- "gdt-lg",
47
- "gdt-md",
48
- "gdt-sm",
49
- "gdt-xs",
50
- "gdt-subtext",
51
- "gdt-capitalized"
52
- ]
53
- }
54
- ]
55
- }
56
- }
57
- });
58
- function cn(...inputs) {
59
- return twMerge(clsx(inputs));
60
- }
61
-
62
- // src/components/ui/button.tsx
63
- import { Button as ButtonPrimitive } from "@base-ui/react/button";
64
- import { cva } from "class-variance-authority";
65
- import { Loader } from "lucide-react";
66
-
67
- // src/components/ui/size-context.tsx
68
- import { createContext, useContext } from "react";
69
- import { Fragment, jsx } from "react/jsx-runtime";
70
- var SizeContext = createContext(void 0);
71
- function SizeProvider({
72
- children,
73
- size
74
- }) {
75
- if (!size) {
76
- return /* @__PURE__ */ jsx(Fragment, { children });
77
- }
78
- return /* @__PURE__ */ jsx(SizeContext.Provider, { value: size, children });
79
- }
80
- function useComponentSize(size, fallback = "md") {
81
- const inheritedSize = useContext(SizeContext);
82
- return size ?? inheritedSize ?? fallback;
83
- }
84
-
85
- // src/components/ui/button.tsx
86
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
87
- var buttonVariants = cva(
88
- "group/button inline-flex shrink-0 items-center justify-center rounded-full bg-clip-padding whitespace-nowrap font-bold transition-[background-color,color,border-color,box-shadow,transform] outline-none select-none focus-visible:border-line-focus focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-invalid:border-line-danger aria-invalid:ring-3 aria-invalid:ring-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
89
- {
90
- variants: {
91
- variant: {
92
- primary: "bg-action-primary text-fg-on-brand hover:bg-action-primary-hover active:bg-action-primary-pressed",
93
- "primary-outline": "border-2 border-action-primary bg-transparent text-fg-brand hover:bg-surface-brand-subtle active:bg-surface-brand-subtle data-focused:bg-surface-brand-subtle data-pressed:bg-surface-brand-subtle",
94
- secondary: "bg-surface-brand-subtle text-fg-brand hover:bg-action-primary-hover hover:text-fg-on-brand active:bg-action-primary-pressed active:text-fg-on-brand data-focused:bg-action-primary-hover data-pressed:bg-action-primary-pressed data-focused:text-fg-on-brand data-pressed:text-fg-on-brand",
95
- "secondary-outline": "border-2 border-action-secondary bg-transparent text-fg-brand hover:bg-surface-brand-subtle active:bg-surface-brand-subtle data-focused:bg-surface-brand-subtle data-pressed:bg-surface-brand-subtle",
96
- tertiary: "bg-action-tertiary text-fg-primary hover:bg-action-tertiary-hover active:bg-action-tertiary-pressed data-focused:bg-action-tertiary-hover data-pressed:bg-action-tertiary-pressed",
97
- "tertiary-outline": "border border-line-strong bg-transparent text-fg-primary hover:bg-surface active:bg-surface-raised data-focused:bg-surface data-pressed:bg-surface-raised",
98
- ghost: "bg-transparent text-fg-primary hover:bg-surface active:bg-surface-raised data-focused:bg-surface data-pressed:bg-surface-raised",
99
- danger: "bg-action-danger text-fg-on-brand hover:bg-action-danger-hover active:bg-action-danger-pressed data-focused:bg-action-danger-hover data-pressed:bg-action-danger-pressed",
100
- "glass-overlay": "bg-surface-glass-overlay-button text-fg-on-brand",
101
- "link-brand": "border-transparent bg-transparent px-0 text-fg-brand hover:underline active:underline active:opacity-70",
102
- "link-neutral": "border-transparent bg-transparent px-0 text-fg-secondary hover:underline active:underline active:opacity-70"
103
- },
104
- size: {
105
- sm: "h-8 gap-2 px-3.5 text-gdt-xs has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3 [&_svg:not([class*='size-'])]:size-3.5",
106
- md: "h-10 gap-2 px-4.5 text-gdt-sm has-data-[icon=inline-end]:pr-4 has-data-[icon=inline-start]:pl-4",
107
- lg: "h-12.5 gap-2.5 px-5.5 text-gdt-md has-data-[icon=inline-end]:pr-5 has-data-[icon=inline-start]:pl-5 [&_svg:not([class*='size-'])]:size-4.5",
108
- xl: "h-14 gap-3 px-6.5 text-gdt-lg has-data-[icon=inline-end]:pr-6 has-data-[icon=inline-start]:pl-6 [&_svg:not([class*='size-'])]:size-5",
109
- icon: "size-10",
110
- "icon-xs": "size-6 text-gdt-xs [&_svg:not([class*='size-'])]:size-3",
111
- "icon-sm": "size-8 text-gdt-sm [&_svg:not([class*='size-'])]:size-3.5",
112
- "icon-lg": "size-12.5 text-gdt-md [&_svg:not([class*='size-'])]:size-4.5",
113
- "icon-xl": "size-14 text-gdt-lg [&_svg:not([class*='size-'])]:size-5"
114
- }
115
- },
116
- defaultVariants: {
117
- variant: "primary",
118
- size: "md"
119
- }
120
- }
121
- );
122
- function Button({
123
- className,
124
- variant = "primary",
125
- size,
126
- isLoading = false,
127
- children,
128
- disabled = false,
129
- ...props
130
- }) {
131
- const inheritedSize = useComponentSize();
132
- const resolvedSize = size ?? inheritedSize;
133
- const _disabled = disabled || isLoading;
134
- return /* @__PURE__ */ jsxs(
135
- ButtonPrimitive,
136
- {
137
- "data-slot": "button",
138
- className: cn(buttonVariants({ variant, size: resolvedSize, className })),
139
- disabled: _disabled,
140
- ...props,
141
- children: [
142
- isLoading && /* @__PURE__ */ jsx2(Loader, { className: "size-4 animate-spin" }),
143
- " ",
144
- children
145
- ]
146
- }
147
- );
148
- }
149
-
150
- // src/components/ui/dropdown-menu.tsx
151
- import { Menu as MenuPrimitive } from "@base-ui/react/menu";
152
- import { cva as cva2 } from "class-variance-authority";
153
- import { CheckIcon, ChevronRightIcon } from "lucide-react";
154
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
155
- function DropdownMenu({
156
- children,
157
- size,
158
- ...props
159
- }) {
160
- return /* @__PURE__ */ jsx3(SizeProvider, { size, children: /* @__PURE__ */ jsx3(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props, children }) });
161
- }
162
- function DropdownMenuTrigger({ ...props }) {
163
- return /* @__PURE__ */ jsx3(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
164
- }
165
- var dropdownMenuContentVariants = cva2(
166
- "relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto border border-line-subtle bg-canvas text-fg-primary shadow-(--elevation-e1-shadow) duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95",
167
- {
168
- variants: {
169
- size: {
170
- sm: "rounded-lg p-1",
171
- md: "rounded-xl p-1.5",
172
- lg: "rounded-[18px] p-2"
173
- }
174
- },
175
- defaultVariants: {
176
- size: "md"
177
- }
178
- }
179
- );
180
- var dropdownMenuItemVariants = cva2(
181
- "group/dropdown-menu-item relative flex w-full cursor-pointer items-center font-normal text-fg-primary outline-none transition-colors select-none focus:bg-surface focus:text-fg-primary data-highlighted:bg-surface data-highlighted:text-fg-primary data-[variant=destructive]:text-fg-danger data-[variant=destructive]:focus:bg-surface-danger-subtle data-[variant=destructive]:focus:text-fg-danger data-[variant=destructive]:data-highlighted:bg-surface-danger-subtle data-[variant=destructive]:data-highlighted:text-fg-danger data-disabled:pointer-events-none data-disabled:text-fg-caption-placeholder data-disabled:opacity-100 [&_svg]:pointer-events-none [&_svg]:shrink-0 data-[variant=destructive]:[&_svg]:text-fg-danger",
182
- {
183
- variants: {
184
- size: {
185
- sm: "gap-1.5 rounded-md px-3 py-1.5 text-gdt-xs [&_svg:not([class*='size-'])]:size-3.5",
186
- md: "gap-2 rounded-md px-4 py-2 text-gdt-sm [&_svg:not([class*='size-'])]:size-4",
187
- lg: "gap-2.5 rounded-md px-4 py-2.5 text-gdt-md [&_svg:not([class*='size-'])]:size-4.5"
188
- }
189
- },
190
- defaultVariants: {
191
- size: "md"
192
- }
193
- }
194
- );
195
- var dropdownMenuLabelVariants = cva2(
196
- "font-medium text-fg-secondary data-inset:pl-8",
197
- {
198
- variants: {
199
- size: {
200
- sm: "px-3 py-1 text-gdt-xs",
201
- md: "px-3 py-1 text-gdt-xs",
202
- lg: "px-4 py-1.5 text-gdt-sm"
203
- }
204
- },
205
- defaultVariants: {
206
- size: "md"
207
- }
208
- }
209
- );
210
- function DropdownMenuContent({
211
- align = "start",
212
- alignOffset = 0,
213
- side = "bottom",
214
- sideOffset = 6,
215
- className,
216
- ...props
217
- }) {
218
- const resolvedSize = useComponentSize();
219
- return /* @__PURE__ */ jsx3(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx3(
220
- MenuPrimitive.Positioner,
221
- {
222
- className: "isolate z-50 outline-none",
223
- align,
224
- alignOffset,
225
- side,
226
- sideOffset,
227
- children: /* @__PURE__ */ jsx3(
228
- MenuPrimitive.Popup,
229
- {
230
- "data-slot": "dropdown-menu-content",
231
- "data-size": resolvedSize,
232
- className: cn(
233
- dropdownMenuContentVariants({ size: resolvedSize }),
234
- className
235
- ),
236
- ...props
237
- }
238
- )
239
- }
240
- ) });
241
- }
242
- function DropdownMenuRadioGroup({ ...props }) {
243
- return /* @__PURE__ */ jsx3(
244
- MenuPrimitive.RadioGroup,
245
- {
246
- "data-slot": "dropdown-menu-radio-group",
247
- ...props
248
- }
249
- );
250
- }
251
- function DropdownMenuRadioItem({
252
- className,
253
- children,
254
- inset,
255
- ...props
256
- }) {
257
- const resolvedSize = useComponentSize();
258
- return /* @__PURE__ */ jsxs2(
259
- MenuPrimitive.RadioItem,
260
- {
261
- "data-slot": "dropdown-menu-radio-item",
262
- "data-inset": inset,
263
- "data-size": resolvedSize,
264
- className: cn(
265
- dropdownMenuItemVariants({ size: resolvedSize }),
266
- "pr-10 data-inset:pl-8",
267
- className
268
- ),
269
- ...props,
270
- children: [
271
- /* @__PURE__ */ jsx3(
272
- "span",
273
- {
274
- className: "pointer-events-none absolute right-3 flex items-center justify-center text-fg-brand",
275
- "data-slot": "dropdown-menu-radio-item-indicator",
276
- children: /* @__PURE__ */ jsx3(MenuPrimitive.RadioItemIndicator, { children: /* @__PURE__ */ jsx3(CheckIcon, {}) })
277
- }
278
- ),
279
- children
280
- ]
281
- }
282
- );
283
- }
284
-
285
- // src/components/ui/input.tsx
286
- import { Input as InputPrimitive } from "@base-ui/react/input";
287
- import { cva as cva3 } from "class-variance-authority";
288
-
289
- // src/components/ui/input-size-context.tsx
290
- import { createContext as createContext2, useContext as useContext2 } from "react";
291
- import { Fragment as Fragment2, jsx as jsx4 } from "react/jsx-runtime";
292
- var InputSizeContext = createContext2(
293
- void 0
294
- );
295
- function useInputComponentSize(size, fallback = "md") {
296
- const inheritedSize = useContext2(InputSizeContext);
297
- return size ?? inheritedSize ?? fallback;
298
- }
299
-
300
- // src/components/ui/input.tsx
301
- import { jsx as jsx5 } from "react/jsx-runtime";
302
- var inputVariants = cva3(
303
- "flex w-full min-w-0 rounded-full border border-line bg-canvas text-fg-primary transition-[background-color,border-color,box-shadow,color] outline-none file:inline-flex file:border-0 file:bg-transparent file:font-normal file:text-fg-primary placeholder:text-fg-muted hover:border-line-strong focus-visible:border-line-focus focus-visible:inset-ring-1 inset-ring-line-focus disabled:pointer-events-none disabled:cursor-not-allowed disabled:border-line-subtle disabled:bg-surface disabled:text-fg-muted disabled:placeholder:text-fg-muted aria-invalid:border-line-danger aria-invalid:text-fg-danger aria-invalid:placeholder:text-fg-danger aria-invalid:shadow-none",
304
- {
305
- variants: {
306
- size: {
307
- sm: "h-8 px-3 text-gdt-xs font-normal file:text-gdt-xs",
308
- md: "h-10 px-3.5 text-gdt-sm font-normal file:text-gdt-sm",
309
- lg: "h-12 px-4 text-gdt-md font-normal file:text-gdt-md",
310
- xl: "h-14 px-4.5 text-gdt-lg font-normal file:text-gdt-lg"
311
- }
312
- },
313
- defaultVariants: {
314
- size: "md"
315
- }
316
- }
317
- );
318
- function Input({ className, size, type, ...props }) {
319
- const resolvedSize = useInputComponentSize(size);
320
- return /* @__PURE__ */ jsx5(
321
- InputPrimitive,
322
- {
323
- type,
324
- "data-slot": "input",
325
- "data-size": resolvedSize,
326
- className: cn(inputVariants({ size: resolvedSize }), className),
327
- ...props
328
- }
329
- );
330
- }
331
-
332
- // src/components/ui/popover.tsx
333
- import { Popover as PopoverPrimitive } from "@base-ui/react/popover";
334
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
335
- function Popover({ ...props }) {
336
- return /* @__PURE__ */ jsx6(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
337
- }
338
- function PopoverTrigger({ ...props }) {
339
- return /* @__PURE__ */ jsx6(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
340
- }
341
- function PopoverContent({
342
- className,
343
- align = "center",
344
- alignOffset = 0,
345
- side = "bottom",
346
- sideOffset = 6,
347
- showArrow = true,
348
- size = "md",
349
- children,
350
- ...props
351
- }) {
352
- return /* @__PURE__ */ jsx6(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx6(
353
- PopoverPrimitive.Positioner,
354
- {
355
- align,
356
- alignOffset,
357
- side,
358
- sideOffset,
359
- className: "isolate z-50",
360
- children: /* @__PURE__ */ jsxs3(
361
- PopoverPrimitive.Popup,
362
- {
363
- "data-slot": "popover-content",
364
- className: cn(
365
- "z-50 relative flex w-72 max-w-[calc(100vw-2rem)] origin-(--transform-origin) flex-col rounded-lg border-0 bg-surface-overlay py-4 text-gdt-sm text-fg-primary shadow-2 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 has-[&_[data-slot=popover-footer]]:pb-0",
366
- className
367
- ),
368
- ...props,
369
- children: [
370
- /* @__PURE__ */ jsx6(SizeProvider, { size, children }),
371
- showArrow ? /* @__PURE__ */ jsx6(PopoverPrimitive.Arrow, { className: "relative block w-3 h-1.5 overflow-clip data-[side=bottom]:top-[-6px] data-[side=left]:right-[-9px] data-[side=left]:rotate-90 data-[side=right]:left-[-9px] data-[side=right]:-rotate-90 data-[side=top]:bottom-[-6px] data-[side=top]:rotate-180 before:content-[''] before:absolute before:bottom-0 before:left-1/2 before:w-[calc(6px*sqrt(2))] before:h-[calc(6px*sqrt(2))] before:bg-surface-overlay before:border before:border-line before:[transform:translate(-50%,50%)_rotate(45deg)]" }) : null
372
- ]
373
- }
374
- )
375
- }
376
- ) });
377
- }
378
-
379
- // src/components/ui/rich-text-editor.tsx
380
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
381
- var SIZES = {
382
- sm: {
383
- width: "max-w-[420px]",
384
- content: "min-h-[140px]",
385
- contentPad: "px-4 py-3",
386
- text: "text-gdt-xs",
387
- icon: "[&_svg:not([class*='size-'])]:size-3.5",
388
- button: "h-7 min-w-7 px-1",
389
- toolbarPad: "px-2 py-1.5",
390
- toolbarGap: "gap-0.5",
391
- divider: "h-4"
392
- },
393
- md: {
394
- width: "max-w-[520px]",
395
- content: "min-h-[172px]",
396
- contentPad: "px-5 py-4",
397
- text: "text-gdt-sm",
398
- icon: "[&_svg:not([class*='size-'])]:size-4",
399
- button: "h-8 min-w-8 px-1.5",
400
- toolbarPad: "px-2.5 py-2",
401
- toolbarGap: "gap-0.5",
402
- divider: "h-5"
403
- },
404
- lg: {
405
- width: "max-w-[600px]",
406
- content: "min-h-[206px]",
407
- contentPad: "px-6 py-5",
408
- text: "text-gdt-md",
409
- icon: "[&_svg:not([class*='size-'])]:size-[18px]",
410
- button: "h-9 min-w-9 px-2",
411
- toolbarPad: "px-3 py-2.5",
412
- toolbarGap: "gap-1",
413
- divider: "h-6"
414
- }
18
+ //#region src/rich-text-editor.tsx
19
+ const SIZES = {
20
+ sm: {
21
+ content: "min-h-[140px]",
22
+ contentPad: "px-4 py-3",
23
+ text: "text-gdt-xs",
24
+ icon: "[&_svg:not([class*='size-'])]:size-3.5",
25
+ button: "h-7 min-w-7 px-1",
26
+ toolbarPad: "px-2 py-1.5",
27
+ toolbarGap: "gap-0.5",
28
+ divider: "h-4"
29
+ },
30
+ md: {
31
+ content: "min-h-[172px]",
32
+ contentPad: "px-5 py-4",
33
+ text: "text-gdt-sm",
34
+ icon: "[&_svg:not([class*='size-'])]:size-4",
35
+ button: "h-8 min-w-8 px-1.5",
36
+ toolbarPad: "px-2.5 py-2",
37
+ toolbarGap: "gap-0.5",
38
+ divider: "h-5"
39
+ },
40
+ lg: {
41
+ content: "min-h-[206px]",
42
+ contentPad: "px-6 py-5",
43
+ text: "text-gdt-md",
44
+ icon: "[&_svg:not([class*='size-'])]:size-[18px]",
45
+ button: "h-9 min-w-9 px-2",
46
+ toolbarPad: "px-3 py-2.5",
47
+ toolbarGap: "gap-1",
48
+ divider: "h-6"
49
+ }
415
50
  };
416
- var TEXT_COLORS = [
417
- { label: "Default", value: "" },
418
- { label: "Forest", value: "#2f5a2c" },
419
- { label: "Brass", value: "#b8861a" },
420
- { label: "Clay", value: "#b2542b" },
421
- { label: "Moss", value: "#4e4d29" },
422
- { label: "Stone", value: "#5c5648" },
423
- { label: "Ink", value: "#1f1c18" }
51
+ const TEXT_COLORS = [
52
+ {
53
+ label: "Default",
54
+ value: "",
55
+ swatch: ""
56
+ },
57
+ {
58
+ label: "Forest",
59
+ value: "#2f5a2c",
60
+ swatch: "var(--color-forest-500)"
61
+ },
62
+ {
63
+ label: "Brass",
64
+ value: "#b8861a",
65
+ swatch: "var(--color-brass-400)"
66
+ },
67
+ {
68
+ label: "Clay",
69
+ value: "#b2542b",
70
+ swatch: "var(--color-clay-500)"
71
+ },
72
+ {
73
+ label: "Moss",
74
+ value: "#4e4d29",
75
+ swatch: "var(--color-moss-500)"
76
+ },
77
+ {
78
+ label: "Stone",
79
+ value: "#5c5648",
80
+ swatch: "var(--color-stone-600)"
81
+ },
82
+ {
83
+ label: "Ink",
84
+ value: "#1f1c18",
85
+ swatch: "var(--color-stone-900)"
86
+ }
424
87
  ];
425
- var BLOCK_OPTIONS = [
426
- { value: "paragraph", label: "Normal" },
427
- { value: "h1", label: "Heading 1" },
428
- { value: "h2", label: "Heading 2" },
429
- { value: "h3", label: "Heading 3" }
88
+ const BLOCK_OPTIONS = [
89
+ {
90
+ value: "paragraph",
91
+ label: "Normal"
92
+ },
93
+ {
94
+ value: "h1",
95
+ label: "Heading 1"
96
+ },
97
+ {
98
+ value: "h2",
99
+ label: "Heading 2"
100
+ },
101
+ {
102
+ value: "h3",
103
+ label: "Heading 3"
104
+ }
430
105
  ];
431
106
  function toolbarControlClass(tokens, active) {
432
- return cn(
433
- "inline-flex shrink-0 cursor-pointer items-center justify-center rounded-md font-medium text-fg-secondary outline-none transition-colors select-none",
434
- "hover:bg-action-tertiary-hover hover:text-fg-primary",
435
- "focus-visible:ring-2 focus-visible:ring-line-focus",
436
- "disabled:pointer-events-none disabled:opacity-40 data-disabled:pointer-events-none data-disabled:opacity-40",
437
- tokens.button,
438
- tokens.icon,
439
- tokens.text,
440
- active && "bg-action-primary text-fg-on-brand hover:bg-action-primary-hover hover:text-fg-on-brand"
441
- );
107
+ return cn("inline-flex shrink-0 cursor-pointer items-center justify-center rounded-md font-medium text-fg-secondary outline-none transition-colors select-none", "hover:bg-action-tertiary-hover hover:text-fg-primary", "focus-visible:ring-2 focus-visible:ring-line-focus", "disabled:pointer-events-none disabled:opacity-40 data-disabled:pointer-events-none data-disabled:opacity-40", tokens.button, tokens.icon, tokens.text, active && "bg-action-primary text-fg-on-brand hover:bg-action-primary-hover hover:text-fg-on-brand");
442
108
  }
443
- function ToolbarButton({
444
- tokens,
445
- label,
446
- active,
447
- disabled,
448
- onClick,
449
- children
450
- }) {
451
- return /* @__PURE__ */ jsx7(
452
- "button",
453
- {
454
- type: "button",
455
- "aria-label": label,
456
- title: label,
457
- "aria-pressed": active,
458
- disabled,
459
- onMouseDown: (event) => event.preventDefault(),
460
- onClick,
461
- className: toolbarControlClass(tokens, active),
462
- children
463
- }
464
- );
109
+ function ToolbarButton({ tokens, label, active, disabled, onClick, children }) {
110
+ return /* @__PURE__ */ jsx("button", {
111
+ type: "button",
112
+ "aria-label": label,
113
+ title: label,
114
+ "aria-pressed": active,
115
+ disabled,
116
+ onMouseDown: (event) => event.preventDefault(),
117
+ onClick,
118
+ className: toolbarControlClass(tokens, active),
119
+ children
120
+ });
465
121
  }
466
122
  function ToolbarDivider({ tokens }) {
467
- return /* @__PURE__ */ jsx7(
468
- "span",
469
- {
470
- "aria-hidden": "true",
471
- className: cn("mx-1 w-px shrink-0 self-center bg-line", tokens.divider)
472
- }
473
- );
123
+ return /* @__PURE__ */ jsx("span", {
124
+ "aria-hidden": "true",
125
+ className: cn("mx-1 w-px shrink-0 self-center bg-line", tokens.divider)
126
+ });
474
127
  }
475
- function BlockControl({
476
- tokens,
477
- value,
478
- disabled,
479
- onChange
480
- }) {
481
- const current = BLOCK_OPTIONS.find((option) => option.value === value);
482
- return /* @__PURE__ */ jsxs4(DropdownMenu, { children: [
483
- /* @__PURE__ */ jsxs4(
484
- DropdownMenuTrigger,
485
- {
486
- disabled,
487
- onMouseDown: (event) => event.preventDefault(),
488
- className: cn(
489
- toolbarControlClass(tokens),
490
- "w-auto justify-between gap-1 px-2"
491
- ),
492
- children: [
493
- /* @__PURE__ */ jsx7("span", { className: "whitespace-nowrap", children: current?.label ?? "Normal" }),
494
- /* @__PURE__ */ jsx7(ChevronDown, { className: "size-3.5 opacity-70" })
495
- ]
496
- }
497
- ),
498
- /* @__PURE__ */ jsx7(DropdownMenuContent, { className: "min-w-40", children: /* @__PURE__ */ jsx7(
499
- DropdownMenuRadioGroup,
500
- {
501
- value,
502
- onValueChange: (next) => onChange(next),
503
- children: BLOCK_OPTIONS.map((option) => /* @__PURE__ */ jsx7(DropdownMenuRadioItem, { value: option.value, children: option.label }, option.value))
504
- }
505
- ) })
506
- ] });
128
+ function BlockControl({ tokens, value, disabled, onChange }) {
129
+ const current = BLOCK_OPTIONS.find((option) => option.value === value);
130
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(DropdownMenuTrigger, {
131
+ disabled,
132
+ className: cn(toolbarControlClass(tokens), "w-auto justify-between gap-1 px-2"),
133
+ children: [/* @__PURE__ */ jsx("span", {
134
+ className: "whitespace-nowrap",
135
+ children: current?.label ?? "Normal"
136
+ }), /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5 opacity-70" })]
137
+ }), /* @__PURE__ */ jsx(DropdownMenuContent, {
138
+ className: "min-w-40",
139
+ children: /* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
140
+ value,
141
+ onValueChange: (next) => onChange(next),
142
+ children: BLOCK_OPTIONS.map((option) => /* @__PURE__ */ jsx(DropdownMenuRadioItem, {
143
+ value: option.value,
144
+ closeOnClick: true,
145
+ children: option.label
146
+ }, option.value))
147
+ })
148
+ })] });
507
149
  }
508
- function ColorControl({
509
- tokens,
510
- value,
511
- disabled,
512
- onChange
513
- }) {
514
- const [open, setOpen] = React.useState(false);
515
- const active = value !== "";
516
- return /* @__PURE__ */ jsxs4(Popover, { open, onOpenChange: setOpen, children: [
517
- /* @__PURE__ */ jsx7(
518
- PopoverTrigger,
519
- {
520
- disabled,
521
- "aria-label": "Text colour",
522
- title: "Text colour",
523
- onMouseDown: (event) => event.preventDefault(),
524
- className: toolbarControlClass(tokens, false),
525
- children: /* @__PURE__ */ jsxs4("span", { className: "relative inline-flex flex-col items-center", children: [
526
- /* @__PURE__ */ jsx7(Baseline, { className: active ? "text-fg-brand" : void 0 }),
527
- /* @__PURE__ */ jsx7(
528
- "span",
529
- {
530
- "aria-hidden": "true",
531
- className: "mt-px h-0.5 w-3 rounded-full",
532
- style: { backgroundColor: active ? value : "currentColor" }
533
- }
534
- )
535
- ] })
536
- }
537
- ),
538
- /* @__PURE__ */ jsx7(
539
- PopoverContent,
540
- {
541
- showArrow: false,
542
- align: "start",
543
- sideOffset: 8,
544
- className: "w-auto py-3",
545
- children: /* @__PURE__ */ jsx7("div", { className: "grid grid-cols-4 gap-2 px-4", children: TEXT_COLORS.map((color) => {
546
- const isSelected = color.value === value;
547
- return /* @__PURE__ */ jsx7(
548
- "button",
549
- {
550
- type: "button",
551
- title: color.label,
552
- "aria-label": color.label,
553
- "aria-pressed": isSelected,
554
- onClick: () => {
555
- onChange(color.value);
556
- setOpen(false);
557
- },
558
- className: cn(
559
- "flex size-7 items-center justify-center rounded-full border transition-[box-shadow,border-color] outline-none",
560
- "hover:border-line-strong focus-visible:ring-2 focus-visible:ring-line-focus",
561
- isSelected ? "border-line-focus ring-2 ring-line-focus/40" : "border-line"
562
- ),
563
- children: /* @__PURE__ */ jsx7(
564
- "span",
565
- {
566
- className: cn(
567
- "flex size-5 items-center justify-center rounded-full text-gdt-xs font-bold",
568
- color.value === "" && "text-fg-secondary"
569
- ),
570
- style: color.value ? { backgroundColor: color.value, color: "#fff" } : void 0,
571
- children: "A"
572
- }
573
- )
574
- },
575
- color.label
576
- );
577
- }) })
578
- }
579
- )
580
- ] });
150
+ function ColorControl({ tokens, value, disabled, onChange }) {
151
+ const [open, setOpen] = React.useState(false);
152
+ const active = value !== "";
153
+ return /* @__PURE__ */ jsxs(Popover, {
154
+ open,
155
+ onOpenChange: setOpen,
156
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
157
+ disabled,
158
+ "aria-label": "Text colour",
159
+ title: "Text colour",
160
+ onMouseDown: (event) => event.preventDefault(),
161
+ className: toolbarControlClass(tokens, false),
162
+ children: /* @__PURE__ */ jsxs("span", {
163
+ className: "relative inline-flex flex-col items-center",
164
+ children: [/* @__PURE__ */ jsx(Baseline, { className: active ? "text-fg-brand" : void 0 }), /* @__PURE__ */ jsx("span", {
165
+ "aria-hidden": "true",
166
+ className: "mt-px h-0.5 w-3 rounded-full",
167
+ style: { backgroundColor: active ? value : "currentColor" }
168
+ })]
169
+ })
170
+ }), /* @__PURE__ */ jsx(PopoverContent, {
171
+ showArrow: false,
172
+ align: "start",
173
+ sideOffset: 8,
174
+ className: "w-auto py-3",
175
+ children: /* @__PURE__ */ jsx("div", {
176
+ className: "grid grid-cols-4 gap-2 px-4",
177
+ children: TEXT_COLORS.map((color) => {
178
+ const isSelected = color.value === value;
179
+ return /* @__PURE__ */ jsx("button", {
180
+ type: "button",
181
+ title: color.label,
182
+ "aria-label": color.label,
183
+ "aria-pressed": isSelected,
184
+ onClick: () => {
185
+ onChange(color.value);
186
+ setOpen(false);
187
+ },
188
+ className: cn("flex size-7 items-center justify-center rounded-full border transition-[box-shadow,border-color] outline-none", "hover:border-line-strong focus-visible:ring-2 focus-visible:ring-line-focus", isSelected ? "border-line-focus ring-2 ring-line-focus/40" : "border-line"),
189
+ children: /* @__PURE__ */ jsx("span", {
190
+ className: cn("flex size-5 items-center justify-center rounded-full text-gdt-xs font-bold", color.value === "" && "text-fg-secondary"),
191
+ style: color.value ? {
192
+ backgroundColor: color.swatch,
193
+ color: "var(--color-stone-0, #fff)"
194
+ } : void 0,
195
+ children: "A"
196
+ })
197
+ }, color.label);
198
+ })
199
+ })
200
+ })]
201
+ });
581
202
  }
582
- function LinkControl({
583
- tokens,
584
- active,
585
- currentHref,
586
- disabled,
587
- onApply,
588
- onRemove
589
- }) {
590
- const [open, setOpen] = React.useState(false);
591
- const [href, setHref] = React.useState("");
592
- function handleOpenChange(next) {
593
- if (next) setHref(currentHref);
594
- setOpen(next);
595
- }
596
- function handleSubmit(event) {
597
- event.preventDefault();
598
- const trimmed = href.trim();
599
- if (trimmed) onApply(trimmed);
600
- else onRemove();
601
- setOpen(false);
602
- }
603
- return /* @__PURE__ */ jsxs4(Popover, { open, onOpenChange: handleOpenChange, children: [
604
- /* @__PURE__ */ jsx7(
605
- PopoverTrigger,
606
- {
607
- disabled,
608
- "aria-label": "Insert link",
609
- title: "Insert link",
610
- "aria-pressed": active,
611
- onMouseDown: (event) => event.preventDefault(),
612
- className: toolbarControlClass(tokens, active),
613
- children: /* @__PURE__ */ jsx7(Link2, {})
614
- }
615
- ),
616
- /* @__PURE__ */ jsx7(PopoverContent, { showArrow: false, align: "start", sideOffset: 8, children: /* @__PURE__ */ jsxs4("form", { className: "flex flex-col gap-3 px-4", onSubmit: handleSubmit, children: [
617
- /* @__PURE__ */ jsx7(
618
- Input,
619
- {
620
- autoFocus: true,
621
- size: "sm",
622
- type: "url",
623
- placeholder: "https://example.com",
624
- value: href,
625
- onChange: (event) => setHref(event.target.value)
626
- }
627
- ),
628
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between gap-2", children: [
629
- /* @__PURE__ */ jsx7(
630
- Button,
631
- {
632
- type: "button",
633
- variant: "tertiary-outline",
634
- size: "sm",
635
- disabled: !active,
636
- onClick: () => {
637
- onRemove();
638
- setOpen(false);
639
- },
640
- children: "Remove"
641
- }
642
- ),
643
- /* @__PURE__ */ jsx7(Button, { type: "submit", size: "sm", children: "Apply" })
644
- ] })
645
- ] }) })
646
- ] });
203
+ function LinkControl({ tokens, active, currentHref, disabled, onApply, onRemove }) {
204
+ const [open, setOpen] = React.useState(false);
205
+ const [href, setHref] = React.useState("");
206
+ function handleOpenChange(next) {
207
+ if (next) setHref(currentHref);
208
+ setOpen(next);
209
+ }
210
+ function handleSubmit(event) {
211
+ event.preventDefault();
212
+ const trimmed = href.trim();
213
+ if (trimmed) onApply(trimmed);
214
+ else onRemove();
215
+ setOpen(false);
216
+ }
217
+ return /* @__PURE__ */ jsxs(Popover, {
218
+ open,
219
+ onOpenChange: handleOpenChange,
220
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
221
+ disabled,
222
+ "aria-label": "Insert link",
223
+ title: "Insert link",
224
+ "aria-pressed": active,
225
+ onMouseDown: (event) => event.preventDefault(),
226
+ className: toolbarControlClass(tokens, active),
227
+ children: /* @__PURE__ */ jsx(Link2, {})
228
+ }), /* @__PURE__ */ jsx(PopoverContent, {
229
+ showArrow: false,
230
+ align: "start",
231
+ sideOffset: 8,
232
+ children: /* @__PURE__ */ jsxs("form", {
233
+ className: "flex flex-col gap-3 px-4",
234
+ onSubmit: handleSubmit,
235
+ children: [/* @__PURE__ */ jsx(Input, {
236
+ autoFocus: true,
237
+ size: "sm",
238
+ type: "url",
239
+ placeholder: "https://example.com",
240
+ value: href,
241
+ onChange: (event) => setHref(event.target.value)
242
+ }), /* @__PURE__ */ jsxs("div", {
243
+ className: "flex items-center justify-between gap-2",
244
+ children: [/* @__PURE__ */ jsx(Button, {
245
+ type: "button",
246
+ variant: "tertiary-outline",
247
+ size: "sm",
248
+ disabled: !active,
249
+ onClick: () => {
250
+ onRemove();
251
+ setOpen(false);
252
+ },
253
+ children: "Remove"
254
+ }), /* @__PURE__ */ jsx(Button, {
255
+ type: "submit",
256
+ size: "sm",
257
+ children: "Apply"
258
+ })]
259
+ })]
260
+ })
261
+ })]
262
+ });
647
263
  }
648
- var ALIGN_OPTIONS = [
649
- { value: "left", label: "Left", Icon: AlignLeft },
650
- { value: "center", label: "Center", Icon: AlignCenter },
651
- { value: "right", label: "Right", Icon: AlignRight },
652
- { value: "justify", label: "Justify", Icon: AlignJustify }
653
- ];
654
- function AlignControl({
655
- tokens,
656
- value,
657
- disabled,
658
- onChange
659
- }) {
660
- const current = ALIGN_OPTIONS.find((option) => option.value === value);
661
- const Icon = current?.Icon ?? AlignLeft;
662
- return /* @__PURE__ */ jsxs4(DropdownMenu, { children: [
663
- /* @__PURE__ */ jsx7(
664
- DropdownMenuTrigger,
665
- {
666
- disabled,
667
- "aria-label": "Text alignment",
668
- title: "Text alignment",
669
- onMouseDown: (event) => event.preventDefault(),
670
- className: toolbarControlClass(tokens, value !== "left"),
671
- children: /* @__PURE__ */ jsx7(Icon, {})
672
- }
673
- ),
674
- /* @__PURE__ */ jsx7(DropdownMenuContent, { className: "min-w-36", children: /* @__PURE__ */ jsx7(
675
- DropdownMenuRadioGroup,
676
- {
677
- value,
678
- onValueChange: (next) => onChange(next),
679
- children: ALIGN_OPTIONS.map(
680
- ({ value: optionValue, label, Icon: OptionIcon }) => /* @__PURE__ */ jsxs4(DropdownMenuRadioItem, { value: optionValue, children: [
681
- /* @__PURE__ */ jsx7(OptionIcon, {}),
682
- label
683
- ] }, optionValue)
684
- )
685
- }
686
- ) })
687
- ] });
264
+ function ImageControl({ tokens, disabled, onInsert }) {
265
+ const [open, setOpen] = React.useState(false);
266
+ const [src, setSrc] = React.useState("");
267
+ function handleOpenChange(next) {
268
+ if (next) setSrc("");
269
+ setOpen(next);
270
+ }
271
+ function handleSubmit(event) {
272
+ event.preventDefault();
273
+ const trimmed = src.trim();
274
+ if (trimmed) onInsert(trimmed);
275
+ setOpen(false);
276
+ }
277
+ return /* @__PURE__ */ jsxs(Popover, {
278
+ open,
279
+ onOpenChange: handleOpenChange,
280
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
281
+ disabled,
282
+ "aria-label": "Insert image",
283
+ title: "Insert image",
284
+ onMouseDown: (event) => event.preventDefault(),
285
+ className: toolbarControlClass(tokens, false),
286
+ children: /* @__PURE__ */ jsx(ImageIcon, {})
287
+ }), /* @__PURE__ */ jsx(PopoverContent, {
288
+ showArrow: false,
289
+ align: "start",
290
+ sideOffset: 8,
291
+ children: /* @__PURE__ */ jsxs("form", {
292
+ className: "flex flex-col gap-3 px-4",
293
+ onSubmit: handleSubmit,
294
+ children: [/* @__PURE__ */ jsx(Input, {
295
+ autoFocus: true,
296
+ size: "sm",
297
+ type: "url",
298
+ placeholder: "https://example.com/image.jpg",
299
+ value: src,
300
+ onChange: (event) => setSrc(event.target.value)
301
+ }), /* @__PURE__ */ jsx("div", {
302
+ className: "flex items-center justify-end",
303
+ children: /* @__PURE__ */ jsx(Button, {
304
+ type: "submit",
305
+ size: "sm",
306
+ disabled: !src.trim(),
307
+ children: "Insert"
308
+ })
309
+ })]
310
+ })
311
+ })]
312
+ });
688
313
  }
689
- var EMPTY_STATE = {
690
- block: "paragraph",
691
- align: "left",
692
- color: "",
693
- linkHref: "",
694
- isBold: false,
695
- isItalic: false,
696
- isUnderline: false,
697
- isBulletList: false,
698
- isOrderedList: false,
699
- isBlockquote: false,
700
- isCodeBlock: false,
701
- isLink: false,
702
- canUndo: false,
703
- canRedo: false
704
- };
705
- function RichTextEditor({
706
- value,
707
- defaultValue,
708
- onChange,
709
- size,
710
- placeholder = "Start writing, or paste your content here. Format text and add lists, links, and images using the toolbar above.",
711
- disabled = false,
712
- className,
713
- "aria-label": ariaLabel = "Rich text editor"
714
- }) {
715
- const resolvedSize = useComponentSize(size);
716
- const tokens = SIZES[resolvedSize];
717
- const [focused, setFocused] = React.useState(false);
718
- const editor = useEditor({
719
- immediatelyRender: false,
720
- editable: !disabled,
721
- content: value ?? defaultValue ?? "",
722
- extensions: [
723
- StarterKit.configure({
724
- link: {
725
- openOnClick: false,
726
- HTMLAttributes: { rel: "noopener noreferrer nofollow" }
727
- }
728
- }),
729
- TextStyle,
730
- Color,
731
- TextAlign.configure({ types: ["heading", "paragraph"] }),
732
- Image.configure({ inline: false, allowBase64: true }),
733
- Placeholder.configure({ placeholder })
734
- ],
735
- editorProps: {
736
- attributes: {
737
- "aria-label": ariaLabel,
738
- role: "textbox",
739
- "aria-multiline": "true",
740
- class: cn("tiptap focus:outline-none", tokens.text)
741
- }
742
- },
743
- onFocus: () => setFocused(true),
744
- onBlur: () => setFocused(false),
745
- onUpdate: ({ editor: instance }) => onChange?.(instance.getHTML())
746
- });
747
- React.useEffect(() => {
748
- editor?.setEditable(!disabled);
749
- }, [editor, disabled]);
750
- React.useEffect(() => {
751
- if (!editor || value === void 0) return;
752
- if (value !== editor.getHTML()) {
753
- editor.commands.setContent(value, { emitUpdate: false });
754
- }
755
- }, [editor, value]);
756
- const state = useEditorState({
757
- editor,
758
- selector: ({ editor: instance }) => {
759
- if (!instance) return EMPTY_STATE;
760
- const block = instance.isActive("heading", { level: 1 }) ? "h1" : instance.isActive("heading", { level: 2 }) ? "h2" : instance.isActive("heading", { level: 3 }) ? "h3" : "paragraph";
761
- const align = instance.isActive({ textAlign: "center" }) ? "center" : instance.isActive({ textAlign: "right" }) ? "right" : instance.isActive({ textAlign: "justify" }) ? "justify" : "left";
762
- return {
763
- block,
764
- align,
765
- color: instance.getAttributes("textStyle").color ?? "",
766
- linkHref: instance.getAttributes("link").href ?? "",
767
- isBold: instance.isActive("bold"),
768
- isItalic: instance.isActive("italic"),
769
- isUnderline: instance.isActive("underline"),
770
- isBulletList: instance.isActive("bulletList"),
771
- isOrderedList: instance.isActive("orderedList"),
772
- isBlockquote: instance.isActive("blockquote"),
773
- isCodeBlock: instance.isActive("codeBlock"),
774
- isLink: instance.isActive("link"),
775
- canUndo: instance.can().undo(),
776
- canRedo: instance.can().redo()
777
- };
778
- }
779
- });
780
- const s = state ?? EMPTY_STATE;
781
- function setBlock(next) {
782
- if (!editor) return;
783
- const chain = editor.chain().focus();
784
- if (next === "paragraph") chain.setParagraph().run();
785
- else chain.toggleHeading({ level: Number(next[1]) }).run();
786
- }
787
- function setAlign(next) {
788
- editor?.chain().focus().setTextAlign(next).run();
789
- }
790
- function setColor(next) {
791
- if (!editor) return;
792
- if (next) editor.chain().focus().setColor(next).run();
793
- else editor.chain().focus().unsetColor().run();
794
- }
795
- function applyLink(href) {
796
- editor?.chain().focus().extendMarkRange("link").setLink({ href }).run();
797
- }
798
- function removeLink() {
799
- editor?.chain().focus().extendMarkRange("link").unsetLink().run();
800
- }
801
- function insertImage() {
802
- const url = window.prompt("Image URL");
803
- if (url) editor?.chain().focus().setImage({ src: url }).run();
804
- }
805
- return /* @__PURE__ */ jsxs4(
806
- "div",
807
- {
808
- "data-slot": "rich-text-editor",
809
- "data-disabled": disabled || void 0,
810
- "data-focused": focused || void 0,
811
- className: cn(
812
- "group/editor flex w-full flex-col overflow-hidden rounded-2xl border bg-surface text-fg-primary shadow-1 transition-[border-color,box-shadow]",
813
- disabled ? "border-line-subtle opacity-60" : focused ? "border-line-focus ring-2 ring-line-focus/35" : "border-line hover:border-line-strong",
814
- tokens.width,
815
- className
816
- ),
817
- children: [
818
- /* @__PURE__ */ jsxs4(
819
- "div",
820
- {
821
- role: "toolbar",
822
- "aria-label": "Formatting",
823
- "aria-orientation": "horizontal",
824
- className: cn(
825
- "flex flex-wrap items-center bg-surface-raised",
826
- tokens.toolbarPad,
827
- tokens.toolbarGap
828
- ),
829
- children: [
830
- /* @__PURE__ */ jsx7(
831
- BlockControl,
832
- {
833
- tokens,
834
- value: s.block,
835
- disabled,
836
- onChange: setBlock
837
- }
838
- ),
839
- /* @__PURE__ */ jsx7(
840
- ToolbarButton,
841
- {
842
- tokens,
843
- label: "Bold",
844
- active: s.isBold,
845
- disabled,
846
- onClick: () => editor?.chain().focus().toggleBold().run(),
847
- children: /* @__PURE__ */ jsx7(Bold, {})
848
- }
849
- ),
850
- /* @__PURE__ */ jsx7(
851
- ToolbarButton,
852
- {
853
- tokens,
854
- label: "Italic",
855
- active: s.isItalic,
856
- disabled,
857
- onClick: () => editor?.chain().focus().toggleItalic().run(),
858
- children: /* @__PURE__ */ jsx7(Italic, {})
859
- }
860
- ),
861
- /* @__PURE__ */ jsx7(
862
- ToolbarButton,
863
- {
864
- tokens,
865
- label: "Underline",
866
- active: s.isUnderline,
867
- disabled,
868
- onClick: () => editor?.chain().focus().toggleUnderline().run(),
869
- children: /* @__PURE__ */ jsx7(Underline, {})
870
- }
871
- ),
872
- /* @__PURE__ */ jsx7(
873
- ColorControl,
874
- {
875
- tokens,
876
- value: s.color,
877
- disabled,
878
- onChange: setColor
879
- }
880
- ),
881
- /* @__PURE__ */ jsx7(ToolbarDivider, { tokens }),
882
- /* @__PURE__ */ jsx7(
883
- ToolbarButton,
884
- {
885
- tokens,
886
- label: "Numbered list",
887
- active: s.isOrderedList,
888
- disabled,
889
- onClick: () => editor?.chain().focus().toggleOrderedList().run(),
890
- children: /* @__PURE__ */ jsx7(ListOrdered, {})
891
- }
892
- ),
893
- /* @__PURE__ */ jsx7(
894
- ToolbarButton,
895
- {
896
- tokens,
897
- label: "Bullet list",
898
- active: s.isBulletList,
899
- disabled,
900
- onClick: () => editor?.chain().focus().toggleBulletList().run(),
901
- children: /* @__PURE__ */ jsx7(List, {})
902
- }
903
- ),
904
- /* @__PURE__ */ jsx7(
905
- AlignControl,
906
- {
907
- tokens,
908
- value: s.align,
909
- disabled,
910
- onChange: setAlign
911
- }
912
- ),
913
- /* @__PURE__ */ jsx7(ToolbarDivider, { tokens }),
914
- /* @__PURE__ */ jsx7(
915
- LinkControl,
916
- {
917
- tokens,
918
- active: s.isLink,
919
- currentHref: s.linkHref,
920
- disabled,
921
- onApply: applyLink,
922
- onRemove: removeLink
923
- }
924
- ),
925
- /* @__PURE__ */ jsx7(
926
- ToolbarButton,
927
- {
928
- tokens,
929
- label: "Quote",
930
- active: s.isBlockquote,
931
- disabled,
932
- onClick: () => editor?.chain().focus().toggleBlockquote().run(),
933
- children: /* @__PURE__ */ jsx7(Quote, {})
934
- }
935
- ),
936
- /* @__PURE__ */ jsx7(
937
- ToolbarButton,
938
- {
939
- tokens,
940
- label: "Code block",
941
- active: s.isCodeBlock,
942
- disabled,
943
- onClick: () => editor?.chain().focus().toggleCodeBlock().run(),
944
- children: /* @__PURE__ */ jsx7(Code2, {})
945
- }
946
- ),
947
- /* @__PURE__ */ jsx7(
948
- ToolbarButton,
949
- {
950
- tokens,
951
- label: "Insert image",
952
- disabled,
953
- onClick: insertImage,
954
- children: /* @__PURE__ */ jsx7(ImageIcon, {})
955
- }
956
- ),
957
- /* @__PURE__ */ jsx7(ToolbarDivider, { tokens }),
958
- /* @__PURE__ */ jsx7(
959
- ToolbarButton,
960
- {
961
- tokens,
962
- label: "Undo",
963
- disabled: disabled || !s.canUndo,
964
- onClick: () => editor?.chain().focus().undo().run(),
965
- children: /* @__PURE__ */ jsx7(Undo2, {})
966
- }
967
- ),
968
- /* @__PURE__ */ jsx7(
969
- ToolbarButton,
970
- {
971
- tokens,
972
- label: "Redo",
973
- disabled: disabled || !s.canRedo,
974
- onClick: () => editor?.chain().focus().redo().run(),
975
- children: /* @__PURE__ */ jsx7(Redo2, {})
976
- }
977
- )
978
- ]
979
- }
980
- ),
981
- /* @__PURE__ */ jsx7("div", { className: "h-px w-full shrink-0 bg-line-subtle" }),
982
- /* @__PURE__ */ jsx7(
983
- EditorContent,
984
- {
985
- editor,
986
- className: cn(
987
- "gdt-rich-text min-w-0 flex-1 overflow-y-auto",
988
- tokens.content,
989
- tokens.contentPad
990
- )
991
- }
992
- )
993
- ]
994
- }
995
- );
314
+ const ALIGN_OPTIONS = [
315
+ {
316
+ value: "left",
317
+ label: "Left",
318
+ Icon: AlignLeft
319
+ },
320
+ {
321
+ value: "center",
322
+ label: "Center",
323
+ Icon: AlignCenter
324
+ },
325
+ {
326
+ value: "right",
327
+ label: "Right",
328
+ Icon: AlignRight
329
+ },
330
+ {
331
+ value: "justify",
332
+ label: "Justify",
333
+ Icon: AlignJustify
334
+ }
335
+ ];
336
+ function AlignControl({ tokens, value, disabled, onChange }) {
337
+ const Icon = ALIGN_OPTIONS.find((option) => option.value === value)?.Icon ?? AlignLeft;
338
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
339
+ disabled,
340
+ "aria-label": "Text alignment",
341
+ title: "Text alignment",
342
+ className: toolbarControlClass(tokens, value !== "left"),
343
+ children: /* @__PURE__ */ jsx(Icon, {})
344
+ }), /* @__PURE__ */ jsx(DropdownMenuContent, {
345
+ className: "min-w-36",
346
+ children: /* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
347
+ value,
348
+ onValueChange: (next) => onChange(next),
349
+ children: ALIGN_OPTIONS.map(({ value: optionValue, label, Icon: OptionIcon }) => /* @__PURE__ */ jsxs(DropdownMenuRadioItem, {
350
+ value: optionValue,
351
+ closeOnClick: true,
352
+ children: [/* @__PURE__ */ jsx(OptionIcon, {}), label]
353
+ }, optionValue))
354
+ })
355
+ })] });
996
356
  }
997
- export {
998
- RichTextEditor
357
+ const EMPTY_STATE = {
358
+ block: "paragraph",
359
+ align: "left",
360
+ color: "",
361
+ linkHref: "",
362
+ isBold: false,
363
+ isItalic: false,
364
+ isUnderline: false,
365
+ isBulletList: false,
366
+ isOrderedList: false,
367
+ isBlockquote: false,
368
+ isCodeBlock: false,
369
+ isLink: false,
370
+ canUndo: false,
371
+ canRedo: false
999
372
  };
1000
- //# sourceMappingURL=rich-text-editor.js.map
373
+ const RichTextEditor = React.forwardRef(function RichTextEditor({ value, defaultValue, onChange, size, placeholder = "Start writing, or paste your content here. Format text and add lists, links, and images using the toolbar above.", disabled = false, className, id, "aria-label": ariaLabel = "Rich text editor", "aria-invalid": ariaInvalid }, ref) {
374
+ const resolvedSize = useComponentSize(size);
375
+ const tokens = SIZES[resolvedSize];
376
+ const [focused, setFocused] = React.useState(false);
377
+ const invalid = ariaInvalid !== void 0 && ariaInvalid !== false && ariaInvalid !== "false";
378
+ const editor = useEditor({
379
+ immediatelyRender: false,
380
+ editable: !disabled,
381
+ content: value ?? defaultValue ?? "",
382
+ extensions: [
383
+ StarterKit.configure({ link: {
384
+ openOnClick: false,
385
+ HTMLAttributes: { rel: "noopener noreferrer nofollow" }
386
+ } }),
387
+ TextStyle,
388
+ Color,
389
+ TextAlign.configure({ types: ["heading", "paragraph"] }),
390
+ Image.configure({
391
+ inline: false,
392
+ allowBase64: true
393
+ }),
394
+ Placeholder.configure({ placeholder })
395
+ ],
396
+ editorProps: { attributes: {
397
+ "aria-label": ariaLabel,
398
+ role: "textbox",
399
+ "aria-multiline": "true",
400
+ class: cn("tiptap focus:outline-none", tokens.text)
401
+ } },
402
+ onFocus: () => setFocused(true),
403
+ onBlur: () => setFocused(false),
404
+ onUpdate: ({ editor: instance }) => onChange?.(instance.getHTML())
405
+ });
406
+ React.useImperativeHandle(ref, () => ({
407
+ focus: () => {
408
+ editor?.commands.focus();
409
+ },
410
+ blur: () => {
411
+ editor?.commands.blur();
412
+ }
413
+ }), [editor]);
414
+ React.useEffect(() => {
415
+ editor?.setEditable(!disabled);
416
+ }, [editor, disabled]);
417
+ React.useEffect(() => {
418
+ const dom = editor?.view.dom;
419
+ if (!dom) return;
420
+ if (invalid) dom.setAttribute("aria-invalid", "true");
421
+ else dom.removeAttribute("aria-invalid");
422
+ }, [editor, invalid]);
423
+ React.useEffect(() => {
424
+ if (!editor || !id || disabled) return;
425
+ const selector = `label[for="${CSS.escape(id)}"]`;
426
+ const handleLabelClick = (event) => {
427
+ if (event.target?.closest(selector)) editor.commands.focus();
428
+ };
429
+ document.addEventListener("click", handleLabelClick);
430
+ return () => document.removeEventListener("click", handleLabelClick);
431
+ }, [
432
+ editor,
433
+ id,
434
+ disabled
435
+ ]);
436
+ React.useEffect(() => {
437
+ if (!editor || value === void 0) return;
438
+ if (value !== editor.getHTML()) editor.commands.setContent(value, { emitUpdate: false });
439
+ }, [editor, value]);
440
+ const s = useEditorState({
441
+ editor,
442
+ selector: ({ editor: instance }) => {
443
+ if (!instance) return EMPTY_STATE;
444
+ return {
445
+ block: instance.isActive("heading", { level: 1 }) ? "h1" : instance.isActive("heading", { level: 2 }) ? "h2" : instance.isActive("heading", { level: 3 }) ? "h3" : "paragraph",
446
+ align: instance.isActive({ textAlign: "center" }) ? "center" : instance.isActive({ textAlign: "right" }) ? "right" : instance.isActive({ textAlign: "justify" }) ? "justify" : "left",
447
+ color: instance.getAttributes("textStyle").color ?? "",
448
+ linkHref: instance.getAttributes("link").href ?? "",
449
+ isBold: instance.isActive("bold"),
450
+ isItalic: instance.isActive("italic"),
451
+ isUnderline: instance.isActive("underline"),
452
+ isBulletList: instance.isActive("bulletList"),
453
+ isOrderedList: instance.isActive("orderedList"),
454
+ isBlockquote: instance.isActive("blockquote"),
455
+ isCodeBlock: instance.isActive("codeBlock"),
456
+ isLink: instance.isActive("link"),
457
+ canUndo: instance.can().undo(),
458
+ canRedo: instance.can().redo()
459
+ };
460
+ }
461
+ }) ?? EMPTY_STATE;
462
+ function setBlock(next) {
463
+ if (!editor) return;
464
+ const chain = editor.chain().focus();
465
+ if (next === "paragraph") chain.setParagraph().run();
466
+ else chain.toggleHeading({ level: Number(next[1]) }).run();
467
+ }
468
+ function setAlign(next) {
469
+ editor?.chain().focus().setTextAlign(next).run();
470
+ }
471
+ function setColor(next) {
472
+ if (!editor) return;
473
+ if (next) editor.chain().focus().setColor(next).run();
474
+ else editor.chain().focus().unsetColor().run();
475
+ }
476
+ function applyLink(href) {
477
+ editor?.chain().focus().extendMarkRange("link").setLink({ href }).run();
478
+ }
479
+ function removeLink() {
480
+ editor?.chain().focus().extendMarkRange("link").unsetLink().run();
481
+ }
482
+ function insertImage(src) {
483
+ editor?.chain().focus().setImage({ src }).run();
484
+ }
485
+ return /* @__PURE__ */ jsxs("div", {
486
+ id,
487
+ "data-slot": "rich-text-editor",
488
+ "data-disabled": disabled || void 0,
489
+ "data-focused": focused || void 0,
490
+ "data-invalid": invalid || void 0,
491
+ "aria-invalid": invalid || void 0,
492
+ className: cn("group/editor flex w-full flex-col overflow-hidden rounded-2xl border bg-surface text-fg-primary shadow-1 transition-[border-color,box-shadow]", disabled ? "border-line-subtle opacity-60" : invalid ? focused ? "border-line-danger ring-2 ring-line-danger/35" : "border-line-danger" : focused ? "border-line-focus ring-2 ring-line-focus/35" : "border-line hover:border-line-strong", className),
493
+ children: [
494
+ /* @__PURE__ */ jsxs("div", {
495
+ role: "toolbar",
496
+ "aria-label": "Formatting",
497
+ "aria-orientation": "horizontal",
498
+ className: cn("flex flex-wrap items-center bg-surface-raised", tokens.toolbarPad, tokens.toolbarGap),
499
+ children: [
500
+ /* @__PURE__ */ jsx(BlockControl, {
501
+ tokens,
502
+ value: s.block,
503
+ disabled,
504
+ onChange: setBlock
505
+ }),
506
+ /* @__PURE__ */ jsx(ToolbarButton, {
507
+ tokens,
508
+ label: "Bold",
509
+ active: s.isBold,
510
+ disabled,
511
+ onClick: () => editor?.chain().focus().toggleBold().run(),
512
+ children: /* @__PURE__ */ jsx(Bold, {})
513
+ }),
514
+ /* @__PURE__ */ jsx(ToolbarButton, {
515
+ tokens,
516
+ label: "Italic",
517
+ active: s.isItalic,
518
+ disabled,
519
+ onClick: () => editor?.chain().focus().toggleItalic().run(),
520
+ children: /* @__PURE__ */ jsx(Italic, {})
521
+ }),
522
+ /* @__PURE__ */ jsx(ToolbarButton, {
523
+ tokens,
524
+ label: "Underline",
525
+ active: s.isUnderline,
526
+ disabled,
527
+ onClick: () => editor?.chain().focus().toggleUnderline().run(),
528
+ children: /* @__PURE__ */ jsx(Underline, {})
529
+ }),
530
+ /* @__PURE__ */ jsx(ColorControl, {
531
+ tokens,
532
+ value: s.color,
533
+ disabled,
534
+ onChange: setColor
535
+ }),
536
+ /* @__PURE__ */ jsx(ToolbarDivider, { tokens }),
537
+ /* @__PURE__ */ jsx(ToolbarButton, {
538
+ tokens,
539
+ label: "Numbered list",
540
+ active: s.isOrderedList,
541
+ disabled,
542
+ onClick: () => editor?.chain().focus().toggleOrderedList().run(),
543
+ children: /* @__PURE__ */ jsx(ListOrdered, {})
544
+ }),
545
+ /* @__PURE__ */ jsx(ToolbarButton, {
546
+ tokens,
547
+ label: "Bullet list",
548
+ active: s.isBulletList,
549
+ disabled,
550
+ onClick: () => editor?.chain().focus().toggleBulletList().run(),
551
+ children: /* @__PURE__ */ jsx(List, {})
552
+ }),
553
+ /* @__PURE__ */ jsx(AlignControl, {
554
+ tokens,
555
+ value: s.align,
556
+ disabled,
557
+ onChange: setAlign
558
+ }),
559
+ /* @__PURE__ */ jsx(ToolbarDivider, { tokens }),
560
+ /* @__PURE__ */ jsx(LinkControl, {
561
+ tokens,
562
+ active: s.isLink,
563
+ currentHref: s.linkHref,
564
+ disabled,
565
+ onApply: applyLink,
566
+ onRemove: removeLink
567
+ }),
568
+ /* @__PURE__ */ jsx(ToolbarButton, {
569
+ tokens,
570
+ label: "Quote",
571
+ active: s.isBlockquote,
572
+ disabled,
573
+ onClick: () => editor?.chain().focus().toggleBlockquote().run(),
574
+ children: /* @__PURE__ */ jsx(Quote, {})
575
+ }),
576
+ /* @__PURE__ */ jsx(ToolbarButton, {
577
+ tokens,
578
+ label: "Code block",
579
+ active: s.isCodeBlock,
580
+ disabled,
581
+ onClick: () => editor?.chain().focus().toggleCodeBlock().run(),
582
+ children: /* @__PURE__ */ jsx(Code2, {})
583
+ }),
584
+ /* @__PURE__ */ jsx(ImageControl, {
585
+ tokens,
586
+ disabled,
587
+ onInsert: insertImage
588
+ }),
589
+ /* @__PURE__ */ jsx(ToolbarDivider, { tokens }),
590
+ /* @__PURE__ */ jsx(ToolbarButton, {
591
+ tokens,
592
+ label: "Undo",
593
+ disabled: disabled || !s.canUndo,
594
+ onClick: () => editor?.chain().focus().undo().run(),
595
+ children: /* @__PURE__ */ jsx(Undo2, {})
596
+ }),
597
+ /* @__PURE__ */ jsx(ToolbarButton, {
598
+ tokens,
599
+ label: "Redo",
600
+ disabled: disabled || !s.canRedo,
601
+ onClick: () => editor?.chain().focus().redo().run(),
602
+ children: /* @__PURE__ */ jsx(Redo2, {})
603
+ })
604
+ ]
605
+ }),
606
+ /* @__PURE__ */ jsx("div", { className: "h-px w-full shrink-0 bg-line-subtle" }),
607
+ /* @__PURE__ */ jsx(EditorContent, {
608
+ editor,
609
+ className: cn("gdt-rich-text min-w-0 flex-1 overflow-y-auto", tokens.content, tokens.contentPad)
610
+ })
611
+ ]
612
+ });
613
+ });
614
+ //#endregion
615
+ export { RichTextEditor };