@dreamtree-org/twreact-ui 1.3.0 → 1.3.2

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 (234) hide show
  1. package/DESIGN.md +2 -2
  2. package/README.md +258 -10
  3. package/ai-skills/dreamtree-ui.md +111 -15
  4. package/charts/package.json +5 -0
  5. package/dist/_shared/cn-DPPQUJu1.js +138 -0
  6. package/dist/ai-schema.json +1252 -179
  7. package/dist/charts/index.d.ts +9 -0
  8. package/dist/charts/index.d.ts.map +1 -0
  9. package/dist/charts/index.js +769 -0
  10. package/dist/components/charts/AreaChart.d.ts +4 -0
  11. package/dist/components/charts/AreaChart.d.ts.map +1 -0
  12. package/dist/components/charts/BarChart.d.ts +4 -0
  13. package/dist/components/charts/BarChart.d.ts.map +1 -0
  14. package/dist/components/charts/CartesianChart.d.ts +5 -0
  15. package/dist/components/charts/CartesianChart.d.ts.map +1 -0
  16. package/dist/components/charts/ChartFrame.d.ts +18 -0
  17. package/dist/components/charts/ChartFrame.d.ts.map +1 -0
  18. package/dist/components/charts/DonutChart.d.ts +4 -0
  19. package/dist/components/charts/DonutChart.d.ts.map +1 -0
  20. package/dist/components/charts/LineChart.d.ts +4 -0
  21. package/dist/components/charts/LineChart.d.ts.map +1 -0
  22. package/dist/components/charts/Sparkline.d.ts +5 -0
  23. package/dist/components/charts/Sparkline.d.ts.map +1 -0
  24. package/dist/components/charts/chartTheme.d.ts +26 -0
  25. package/dist/components/charts/chartTheme.d.ts.map +1 -0
  26. package/dist/components/core/Accordion.d.ts.map +1 -1
  27. package/dist/components/core/Button.d.ts.map +1 -1
  28. package/dist/components/core/Checkbox.d.ts.map +1 -1
  29. package/dist/components/core/ColorPicker.d.ts.map +1 -1
  30. package/dist/components/core/DatePicker.d.ts.map +1 -1
  31. package/dist/components/core/DateRangePicker.d.ts.map +1 -1
  32. package/dist/components/core/Form.d.ts.map +1 -1
  33. package/dist/components/core/Input.d.ts.map +1 -1
  34. package/dist/components/core/LocationPicker.d.ts.map +1 -1
  35. package/dist/components/core/Popover.d.ts +4 -0
  36. package/dist/components/core/Popover.d.ts.map +1 -0
  37. package/dist/components/core/PriceRangePicker.d.ts.map +1 -1
  38. package/dist/components/core/ProgressBar.d.ts.map +1 -1
  39. package/dist/components/core/Radio.d.ts.map +1 -1
  40. package/dist/components/core/Rate.d.ts.map +1 -1
  41. package/dist/components/core/Select.d.ts.map +1 -1
  42. package/dist/components/core/Skeleton.d.ts.map +1 -1
  43. package/dist/components/core/Slider.d.ts +4 -0
  44. package/dist/components/core/Slider.d.ts.map +1 -0
  45. package/dist/components/core/SpeechToText.d.ts.map +1 -1
  46. package/dist/components/core/Switch.d.ts.map +1 -1
  47. package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
  48. package/dist/components/core/Table/ColumnMenu.d.ts +2 -1
  49. package/dist/components/core/Table/ColumnMenu.d.ts.map +1 -1
  50. package/dist/components/core/Table/MobileCard.d.ts +2 -2
  51. package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
  52. package/dist/components/core/Table/Table.d.ts.map +1 -1
  53. package/dist/components/core/Table/TableRow.d.ts +4 -2
  54. package/dist/components/core/Table/TableRow.d.ts.map +1 -1
  55. package/dist/components/core/Tabs.d.ts.map +1 -1
  56. package/dist/components/core/Textarea.d.ts +4 -0
  57. package/dist/components/core/Textarea.d.ts.map +1 -0
  58. package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
  59. package/dist/components/core/Tooltip.d.ts.map +1 -1
  60. package/dist/components/feedback/Dialog.d.ts.map +1 -1
  61. package/dist/components/feedback/Drawer.d.ts +4 -0
  62. package/dist/components/feedback/Drawer.d.ts.map +1 -0
  63. package/dist/components/feedback/Toast.d.ts +14 -5
  64. package/dist/components/feedback/Toast.d.ts.map +1 -1
  65. package/dist/components/feedback/Tour.d.ts +4 -0
  66. package/dist/components/feedback/Tour.d.ts.map +1 -0
  67. package/dist/components/feedback/TourSpotlight.d.ts +9 -0
  68. package/dist/components/feedback/TourSpotlight.d.ts.map +1 -0
  69. package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
  70. package/dist/components/navigation/FootNav.d.ts.map +1 -1
  71. package/dist/components/navigation/Navbar.d.ts.map +1 -1
  72. package/dist/components/navigation/Sidebar.d.ts +8 -2
  73. package/dist/components/navigation/Sidebar.d.ts.map +1 -1
  74. package/dist/components/rich-text/RichTextEditor.d.ts +4 -0
  75. package/dist/components/rich-text/RichTextEditor.d.ts.map +1 -0
  76. package/dist/components/rich-text/RichTextToolbar.d.ts +219 -0
  77. package/dist/components/rich-text/RichTextToolbar.d.ts.map +1 -0
  78. package/dist/components/utility/Badge.d.ts.map +1 -1
  79. package/dist/components/utility/FileUpload.d.ts.map +1 -1
  80. package/dist/components/utility/Sortable.d.ts +4 -0
  81. package/dist/components/utility/Sortable.d.ts.map +1 -0
  82. package/dist/esm/_vendor/object-assign/index.js +99 -0
  83. package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.development.js +190 -0
  84. package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.production.min.js +26 -0
  85. package/dist/esm/_vendor/prop-types/_vendor/react-is/index.js +19 -0
  86. package/dist/esm/_vendor/prop-types/checkPropTypes.js +115 -0
  87. package/dist/esm/_vendor/prop-types/factoryWithThrowingShims.js +74 -0
  88. package/dist/esm/_vendor/prop-types/factoryWithTypeCheckers.js +625 -0
  89. package/dist/esm/_vendor/prop-types/index.js +30 -0
  90. package/dist/esm/_vendor/prop-types/lib/ReactPropTypesSecret.js +21 -0
  91. package/dist/esm/_vendor/prop-types/lib/has.js +11 -0
  92. package/dist/esm/_virtual/_commonjsHelpers.js +5 -0
  93. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
  94. package/dist/esm/_virtual/index.js +3 -0
  95. package/dist/esm/_virtual/index2.js +3 -0
  96. package/dist/esm/_virtual/react-is.development.js +3 -0
  97. package/dist/esm/_virtual/react-is.production.min.js +3 -0
  98. package/dist/esm/charts/index.js +5 -0
  99. package/dist/esm/components/blocks/AppShell.js +205 -0
  100. package/dist/esm/components/blocks/ConfirmDialog.js +57 -0
  101. package/dist/esm/components/blocks/EmptyState.js +44 -0
  102. package/dist/esm/components/blocks/ErrorState.js +53 -0
  103. package/dist/esm/components/blocks/LoadingState.js +134 -0
  104. package/dist/esm/components/blocks/PageHeader.js +51 -0
  105. package/dist/esm/components/blocks/StatCard.js +79 -0
  106. package/dist/esm/components/blocks/StatusPill.js +55 -0
  107. package/dist/esm/components/charts/AreaChart.js +16 -0
  108. package/dist/esm/components/charts/BarChart.js +16 -0
  109. package/dist/esm/components/charts/CartesianChart.js +250 -0
  110. package/dist/esm/components/charts/ChartFrame.js +170 -0
  111. package/dist/esm/components/charts/DonutChart.js +119 -0
  112. package/dist/esm/components/charts/LineChart.js +16 -0
  113. package/dist/esm/components/charts/Sparkline.js +110 -0
  114. package/dist/esm/components/charts/chartTheme.js +109 -0
  115. package/dist/esm/components/core/Accordion.js +260 -0
  116. package/dist/esm/components/core/Button.js +59 -0
  117. package/dist/esm/components/core/Checkbox.js +188 -0
  118. package/dist/esm/components/core/ColorPicker.js +348 -0
  119. package/dist/esm/components/core/DatePicker.js +436 -0
  120. package/dist/esm/components/core/DateRangePicker.js +494 -0
  121. package/dist/esm/components/core/Form.js +522 -0
  122. package/dist/esm/components/core/Input.js +179 -0
  123. package/dist/esm/components/core/Loader.js +141 -0
  124. package/dist/esm/components/core/LocationPicker.js +161 -0
  125. package/dist/esm/components/core/Popover.js +171 -0
  126. package/dist/esm/components/core/PriceRangePicker.js +376 -0
  127. package/dist/esm/components/core/ProgressBar.js +152 -0
  128. package/dist/esm/components/core/Radio.js +156 -0
  129. package/dist/esm/components/core/Rate.js +197 -0
  130. package/dist/esm/components/core/RoundedTag.js +118 -0
  131. package/dist/esm/components/core/Select.js +857 -0
  132. package/dist/esm/components/core/Skeleton.js +100 -0
  133. package/dist/esm/components/core/Slider.js +134 -0
  134. package/dist/esm/components/core/SpeechToText.js +226 -0
  135. package/dist/esm/components/core/Switch.js +207 -0
  136. package/dist/esm/components/core/Table/ActionMenu.js +251 -0
  137. package/dist/esm/components/core/Table/ColumnMenu.js +55 -0
  138. package/dist/esm/components/core/Table/FieldInput.js +157 -0
  139. package/dist/esm/components/core/Table/MobileCard.js +187 -0
  140. package/dist/esm/components/core/Table/MobileFilters.js +72 -0
  141. package/dist/esm/components/core/Table/Pagination.js +157 -0
  142. package/dist/esm/components/core/Table/Table.js +1533 -0
  143. package/dist/esm/components/core/Table/TableRow.js +254 -0
  144. package/dist/esm/components/core/Table/constants.js +35 -0
  145. package/dist/esm/components/core/Table/helpers.js +124 -0
  146. package/dist/esm/components/core/Table/useClickOutside.js +26 -0
  147. package/dist/esm/components/core/Tabs.js +289 -0
  148. package/dist/esm/components/core/TextToSpeech.js +52 -0
  149. package/dist/esm/components/core/Textarea.js +125 -0
  150. package/dist/esm/components/core/ThreeDotPopover.js +160 -0
  151. package/dist/esm/components/core/Tooltip.js +372 -0
  152. package/dist/esm/components/feedback/Alert.js +96 -0
  153. package/dist/esm/components/feedback/Dialog.js +200 -0
  154. package/dist/esm/components/feedback/Drawer.js +171 -0
  155. package/dist/esm/components/feedback/Toast.js +362 -0
  156. package/dist/esm/components/feedback/Tour.js +214 -0
  157. package/dist/esm/components/feedback/TourSpotlight.js +71 -0
  158. package/dist/esm/components/navigation/Breadcrumbs.js +75 -0
  159. package/dist/esm/components/navigation/Dropdown.js +53 -0
  160. package/dist/esm/components/navigation/FootNav.js +51 -0
  161. package/dist/esm/components/navigation/Navbar.js +437 -0
  162. package/dist/esm/components/navigation/Sidebar.js +567 -0
  163. package/dist/esm/components/rich-text/RichTextEditor.js +244 -0
  164. package/dist/esm/components/rich-text/RichTextToolbar.js +397 -0
  165. package/dist/esm/components/utility/Avatar.js +89 -0
  166. package/dist/esm/components/utility/Badge.js +47 -0
  167. package/dist/esm/components/utility/Card.js +85 -0
  168. package/dist/esm/components/utility/Carousel.js +97 -0
  169. package/dist/esm/components/utility/Condition.js +9 -0
  170. package/dist/esm/components/utility/FileUpload.js +177 -0
  171. package/dist/esm/components/utility/Pagination.js +111 -0
  172. package/dist/esm/components/utility/Sortable.js +190 -0
  173. package/dist/esm/components/utility/Stepper.js +101 -0
  174. package/dist/esm/hooks/useApi.js +169 -0
  175. package/dist/esm/hooks/useControllableState.js +32 -0
  176. package/dist/esm/hooks/useFocusTrap.js +85 -0
  177. package/dist/esm/hooks/useLatestRef.js +20 -0
  178. package/dist/esm/hooks/useMixins.js +100 -0
  179. package/dist/esm/hooks/useScrollLock.js +26 -0
  180. package/dist/esm/hooks/useSliderValues.js +135 -0
  181. package/dist/esm/hooks/useSortable.js +188 -0
  182. package/dist/esm/hooks/useTheme.js +53 -0
  183. package/dist/esm/hooks/useTourTarget.js +92 -0
  184. package/dist/esm/index.js +65 -0
  185. package/dist/esm/rich-text/index.js +1 -0
  186. package/dist/esm/store/index.js +26 -0
  187. package/dist/esm/store/store.js +107 -0
  188. package/dist/esm/store/storeSlice.js +45 -0
  189. package/dist/esm/utils/cn.js +11 -0
  190. package/dist/esm/utils/emitter.js +169 -0
  191. package/dist/esm/utils/helpers.js +161 -0
  192. package/dist/esm/utils/position.js +134 -0
  193. package/dist/hooks/useApi.d.ts +2 -1
  194. package/dist/hooks/useApi.d.ts.map +1 -1
  195. package/dist/hooks/useControllableState.d.ts +11 -0
  196. package/dist/hooks/useControllableState.d.ts.map +1 -0
  197. package/dist/hooks/useFocusTrap.d.ts +15 -0
  198. package/dist/hooks/useFocusTrap.d.ts.map +1 -0
  199. package/dist/hooks/useLatestRef.d.ts +8 -0
  200. package/dist/hooks/useLatestRef.d.ts.map +1 -0
  201. package/dist/hooks/useMixins.d.ts.map +1 -1
  202. package/dist/hooks/useScrollLock.d.ts +2 -0
  203. package/dist/hooks/useScrollLock.d.ts.map +1 -0
  204. package/dist/hooks/useSliderValues.d.ts +43 -0
  205. package/dist/hooks/useSliderValues.d.ts.map +1 -0
  206. package/dist/hooks/useSortable.d.ts +32 -0
  207. package/dist/hooks/useSortable.d.ts.map +1 -0
  208. package/dist/hooks/useTheme.d.ts.map +1 -1
  209. package/dist/hooks/useTourTarget.d.ts +15 -0
  210. package/dist/hooks/useTourTarget.d.ts.map +1 -0
  211. package/dist/index.css +1 -1
  212. package/dist/index.d.ts +8 -2
  213. package/dist/index.esm.css +1 -1
  214. package/dist/index.esm.js +4817 -2216
  215. package/dist/index.js +4822 -2214
  216. package/dist/rich-text/index.d.ts +5 -0
  217. package/dist/rich-text/index.d.ts.map +1 -0
  218. package/dist/rich-text/index.js +654 -0
  219. package/dist/tokens/brands/studio.css +14 -0
  220. package/dist/tokens/brands/studio.json +20 -0
  221. package/dist/types/charts.d.ts +97 -0
  222. package/dist/types/charts.d.ts.map +1 -0
  223. package/dist/types/index.d.ts +193 -5
  224. package/dist/types/index.d.ts.map +1 -1
  225. package/dist/types/rich-text.d.ts +50 -0
  226. package/dist/types/rich-text.d.ts.map +1 -0
  227. package/dist/utils/position.d.ts +30 -0
  228. package/dist/utils/position.d.ts.map +1 -0
  229. package/doc/README.md +20 -1
  230. package/mcp/catalog.snapshot.json +2505 -800
  231. package/mcp/server-core.mjs +30 -1
  232. package/package.json +51 -3
  233. package/rich-text/package.json +5 -0
  234. package/tokens/brands/studio.json +20 -0
@@ -0,0 +1,244 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2, toConsumableArray as _toConsumableArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import { forwardRef, useId, useRef, useEffect, useImperativeHandle } from 'react';
5
+ import { useEditor, useEditorState, EditorContent } from '@tiptap/react';
6
+ import StarterKit from '@tiptap/starter-kit';
7
+ import { AlertCircle } from 'lucide-react';
8
+ import { cn } from '../../utils/cn.js';
9
+ import { useLatestRef } from '../../hooks/useLatestRef.js';
10
+ import { selectToolbarState, DEFAULT_TOOLBAR, RichTextToolbar } from './RichTextToolbar.js';
11
+
12
+ var _excluded = ["id", "className", "editorClassName", "label", "error", "helperText", "required", "disabled", "readOnly", "placeholder", "value", "defaultValue", "onChange", "outputFormat", "onFocus", "onBlur", "toolbar", "toolbarLabel", "minHeight", "maxHeight", "autoFocus", "extensions", "aria-label", "aria-describedby"];
13
+ // Tailwind's preflight strips list bullets, heading sizes, etc. These arbitrary
14
+ // variants restore readable defaults inside the editable area only.
15
+ var CONTENT_CLASSES = cn("px-3 py-2 text-sm text-gray-900 focus:outline-none dark:text-gray-100", "[&_p]:my-1 [&_h1]:my-2 [&_h1]:text-2xl [&_h1]:font-bold [&_h2]:my-2 [&_h2]:text-xl [&_h2]:font-semibold [&_h3]:my-1.5 [&_h3]:text-lg [&_h3]:font-semibold", "[&_ul]:list-disc [&_ul]:pl-6 [&_ol]:list-decimal [&_ol]:pl-6 [&_li]:my-0.5", "[&_blockquote]:my-2 [&_blockquote]:border-l-4 [&_blockquote]:border-gray-300 [&_blockquote]:pl-3 [&_blockquote]:text-gray-600 dark:[&_blockquote]:border-gray-600 dark:[&_blockquote]:text-gray-300", "[&_code]:rounded [&_code]:bg-gray-100 [&_code]:px-1 [&_code]:font-mono [&_code]:text-[0.85em] dark:[&_code]:bg-gray-800", "[&_pre]:my-2 [&_pre]:rounded-md [&_pre]:bg-gray-100 [&_pre]:p-3 dark:[&_pre]:bg-gray-800 [&_pre_code]:bg-transparent [&_pre_code]:p-0", "[&_a]:text-primary-600 [&_a]:underline dark:[&_a]:text-primary-400 [&_hr]:my-3 [&_hr]:border-gray-200 dark:[&_hr]:border-gray-700");
16
+ var toCss = function toCss(v) {
17
+ return typeof v === "number" ? "".concat(v, "px") : v;
18
+ };
19
+ function sameContent(editor, value) {
20
+ if (typeof value === "string") return value === editor.getHTML();
21
+ return JSON.stringify(value) === JSON.stringify(editor.getJSON());
22
+ }
23
+ var RichTextEditor = /*#__PURE__*/forwardRef(function (_ref, ref) {
24
+ var _ref2;
25
+ var id = _ref.id,
26
+ className = _ref.className,
27
+ editorClassName = _ref.editorClassName,
28
+ label = _ref.label,
29
+ error = _ref.error,
30
+ helperText = _ref.helperText,
31
+ _ref$required = _ref.required,
32
+ required = _ref$required === void 0 ? false : _ref$required,
33
+ _ref$disabled = _ref.disabled,
34
+ disabled = _ref$disabled === void 0 ? false : _ref$disabled,
35
+ _ref$readOnly = _ref.readOnly,
36
+ readOnly = _ref$readOnly === void 0 ? false : _ref$readOnly,
37
+ placeholder = _ref.placeholder,
38
+ value = _ref.value,
39
+ defaultValue = _ref.defaultValue,
40
+ onChange = _ref.onChange,
41
+ _ref$outputFormat = _ref.outputFormat,
42
+ outputFormat = _ref$outputFormat === void 0 ? "html" : _ref$outputFormat,
43
+ onFocus = _ref.onFocus,
44
+ onBlur = _ref.onBlur,
45
+ _ref$toolbar = _ref.toolbar,
46
+ toolbar = _ref$toolbar === void 0 ? DEFAULT_TOOLBAR : _ref$toolbar,
47
+ _ref$toolbarLabel = _ref.toolbarLabel,
48
+ toolbarLabel = _ref$toolbarLabel === void 0 ? "Formatting" : _ref$toolbarLabel,
49
+ _ref$minHeight = _ref.minHeight,
50
+ minHeight = _ref$minHeight === void 0 ? 120 : _ref$minHeight,
51
+ maxHeight = _ref.maxHeight,
52
+ _ref$autoFocus = _ref.autoFocus,
53
+ autoFocus = _ref$autoFocus === void 0 ? false : _ref$autoFocus,
54
+ extensions = _ref.extensions,
55
+ ariaLabel = _ref["aria-label"],
56
+ ariaDescribedBy = _ref["aria-describedby"],
57
+ rest = _objectWithoutProperties(_ref, _excluded);
58
+ var reactId = useId();
59
+ var editorId = id || "rich-text-".concat(reactId);
60
+ var labelId = "".concat(editorId, "-label");
61
+ var errorId = "".concat(editorId, "-error");
62
+ var helperId = "".concat(editorId, "-helper");
63
+ var editable = !disabled && !readOnly;
64
+ var rootRef = useRef(null);
65
+ var callbacks = useLatestRef({
66
+ onChange: onChange,
67
+ onFocus: onFocus,
68
+ onBlur: onBlur,
69
+ outputFormat: outputFormat
70
+ });
71
+ var describedBy = [error ? errorId : null, helperText ? helperId : null, ariaDescribedBy].filter(Boolean).join(" ") || undefined;
72
+ var attributes = _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({
73
+ id: editorId,
74
+ role: "textbox",
75
+ "aria-multiline": "true"
76
+ }, label ? {
77
+ "aria-labelledby": labelId
78
+ } : {
79
+ "aria-label": ariaLabel || placeholder || "Rich text editor"
80
+ }), describedBy ? {
81
+ "aria-describedby": describedBy
82
+ } : {}), error ? {
83
+ "aria-invalid": "true"
84
+ } : {}), required ? {
85
+ "aria-required": "true"
86
+ } : {}), readOnly ? {
87
+ "aria-readonly": "true"
88
+ } : {}), disabled ? {
89
+ "aria-disabled": "true"
90
+ } : {}), placeholder ? {
91
+ "aria-placeholder": placeholder
92
+ } : {}), {}, {
93
+ "class": cn(CONTENT_CLASSES, editorClassName)
94
+ });
95
+ var attributesKey = JSON.stringify(attributes);
96
+ var editor = useEditor({
97
+ extensions: [StarterKit.configure({
98
+ link: {
99
+ openOnClick: false,
100
+ autolink: true,
101
+ defaultProtocol: "https"
102
+ }
103
+ })].concat(_toConsumableArray(extensions || [])),
104
+ content: (_ref2 = value !== null && value !== void 0 ? value : defaultValue) !== null && _ref2 !== void 0 ? _ref2 : "",
105
+ editable: editable,
106
+ autofocus: autoFocus,
107
+ // Render on the client after mount: safe for SSR / Next.js hydration.
108
+ immediatelyRender: false,
109
+ editorProps: {
110
+ attributes: attributes
111
+ },
112
+ onUpdate: function onUpdate(_ref3) {
113
+ var instance = _ref3.editor;
114
+ var _callbacks$current = callbacks.current,
115
+ cb = _callbacks$current.onChange,
116
+ format = _callbacks$current.outputFormat;
117
+ cb === null || cb === void 0 || cb(format === "json" ? instance.getJSON() : instance.getHTML(), instance);
118
+ },
119
+ onFocus: function onFocus(_ref4) {
120
+ var _callbacks$current$on, _callbacks$current2;
121
+ var event = _ref4.event;
122
+ return (_callbacks$current$on = (_callbacks$current2 = callbacks.current).onFocus) === null || _callbacks$current$on === void 0 ? void 0 : _callbacks$current$on.call(_callbacks$current2, event);
123
+ },
124
+ onBlur: function onBlur(_ref5) {
125
+ var _callbacks$current$on2, _callbacks$current3;
126
+ var event = _ref5.event;
127
+ return (_callbacks$current$on2 = (_callbacks$current3 = callbacks.current).onBlur) === null || _callbacks$current$on2 === void 0 ? void 0 : _callbacks$current$on2.call(_callbacks$current3, event);
128
+ }
129
+ });
130
+ var watched = useEditorState({
131
+ editor: editor,
132
+ selector: function selector(_ref6) {
133
+ var instance = _ref6.editor;
134
+ return selectToolbarState(instance);
135
+ }
136
+ });
137
+ // useEditorState only re-selects on the next transaction after the editor
138
+ // mounts, so read the state directly until then.
139
+ var state = watched !== null && watched !== void 0 ? watched : selectToolbarState(editor);
140
+ useEffect(function () {
141
+ if (editor && value !== undefined && value !== null && !sameContent(editor, value)) {
142
+ editor.commands.setContent(value, {
143
+ emitUpdate: false
144
+ });
145
+ }
146
+ }, [editor, value]);
147
+ useEffect(function () {
148
+ if (editor && editor.isEditable !== editable) editor.setEditable(editable, false);
149
+ }, [editor, editable]);
150
+ useEffect(function () {
151
+ if (editor) editor.setOptions({
152
+ editorProps: {
153
+ attributes: JSON.parse(attributesKey)
154
+ }
155
+ });
156
+ }, [editor, attributesKey]);
157
+ useImperativeHandle(ref, function () {
158
+ return {
159
+ editor: editor,
160
+ element: rootRef.current,
161
+ focus: function focus() {
162
+ return editor === null || editor === void 0 ? void 0 : editor.commands.focus();
163
+ },
164
+ clear: function clear() {
165
+ return editor === null || editor === void 0 ? void 0 : editor.commands.clearContent(true);
166
+ },
167
+ getHTML: function getHTML() {
168
+ return editor ? editor.getHTML() : "";
169
+ },
170
+ getJSON: function getJSON() {
171
+ return editor ? editor.getJSON() : null;
172
+ },
173
+ setContent: function setContent(content) {
174
+ return editor === null || editor === void 0 ? void 0 : editor.commands.setContent(content);
175
+ }
176
+ };
177
+ }, [editor]);
178
+ var focusEditor = function focusEditor() {
179
+ if (editable) editor === null || editor === void 0 || editor.commands.focus();
180
+ };
181
+ var items = Array.isArray(toolbar) ? toolbar : toolbar === false ? [] : DEFAULT_TOOLBAR;
182
+ var showToolbar = !readOnly && items.length > 0;
183
+ var showPlaceholder = placeholder && (state ? state.isEmpty : !(value !== null && value !== void 0 ? value : defaultValue));
184
+ return jsxs("div", _objectSpread2(_objectSpread2({
185
+ ref: rootRef,
186
+ className: cn("w-full", className),
187
+ "data-disabled": disabled || undefined
188
+ }, rest), {}, {
189
+ children: [label && jsxs("label", {
190
+ id: labelId,
191
+ onClick: focusEditor,
192
+ className: "mb-1 block text-sm font-medium text-gray-700 dark:text-gray-200",
193
+ children: [label, required && jsx("span", {
194
+ className: "ml-1 text-error-500",
195
+ "aria-hidden": "true",
196
+ children: "*"
197
+ })]
198
+ }), jsxs("div", {
199
+ className: cn("overflow-hidden rounded-md border bg-white dark:bg-gray-900", error ? "border-error-500" : "border-gray-300 dark:border-gray-600", disabled && "cursor-not-allowed opacity-50"),
200
+ children: [showToolbar && jsx(RichTextToolbar, {
201
+ editor: editor,
202
+ state: state,
203
+ items: items,
204
+ disabled: disabled,
205
+ controlsId: editorId,
206
+ label: toolbarLabel
207
+ }), jsxs("div", {
208
+ className: cn("relative overflow-y-auto focus-within:ring-2 focus-within:ring-inset", error ? "focus-within:ring-error-500" : "focus-within:ring-primary-500"),
209
+ style: {
210
+ minHeight: toCss(minHeight),
211
+ maxHeight: toCss(maxHeight)
212
+ },
213
+ onMouseDown: function onMouseDown(e) {
214
+ if (e.target === e.currentTarget) {
215
+ e.preventDefault();
216
+ focusEditor();
217
+ }
218
+ },
219
+ children: [showPlaceholder && jsx("div", {
220
+ className: "pointer-events-none absolute left-3 top-3 select-none text-sm text-gray-400 dark:text-gray-500",
221
+ "aria-hidden": "true",
222
+ children: placeholder
223
+ }), jsx(EditorContent, {
224
+ editor: editor
225
+ })]
226
+ })]
227
+ }), error && jsxs("p", {
228
+ id: errorId,
229
+ className: "mt-1 flex items-center gap-1 text-sm text-error-600 dark:text-error-400",
230
+ "aria-live": "polite",
231
+ children: [jsx(AlertCircle, {
232
+ className: "h-4 w-4 shrink-0",
233
+ "aria-hidden": "true"
234
+ }), error]
235
+ }), helperText && jsx("p", {
236
+ id: helperId,
237
+ className: "mt-1 text-sm text-gray-500 dark:text-gray-400",
238
+ children: helperText
239
+ })]
240
+ }));
241
+ });
242
+ RichTextEditor.displayName = "RichTextEditor";
243
+
244
+ export { RichTextEditor as default };
@@ -0,0 +1,397 @@
1
+ 'use client';
2
+ import { slicedToArray as _slicedToArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
4
+ import React, { useState, useRef, useEffect } from 'react';
5
+ import { Redo, Undo, Link, SquareCode, Quote, ListOrdered, List, Heading3, Heading2, Heading1, Code, Strikethrough, Italic, Bold } from 'lucide-react';
6
+ import { cn } from '../../utils/cn.js';
7
+
8
+ var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || "");
9
+ var shortcutLabel = function shortcutLabel(keys) {
10
+ return keys.replace("Mod", isMac ? "⌘" : "Ctrl").replace(/-/g, "+");
11
+ };
12
+ /** Every toolbar control, keyed by the name consumers pass in `toolbar`. */
13
+ var TOOLBAR_ITEMS = {
14
+ bold: {
15
+ label: "Bold",
16
+ icon: Bold,
17
+ group: "marks",
18
+ shortcut: "Mod-B",
19
+ toggle: true,
20
+ run: function run(c) {
21
+ return c.toggleBold();
22
+ }
23
+ },
24
+ italic: {
25
+ label: "Italic",
26
+ icon: Italic,
27
+ group: "marks",
28
+ shortcut: "Mod-I",
29
+ toggle: true,
30
+ run: function run(c) {
31
+ return c.toggleItalic();
32
+ }
33
+ },
34
+ strike: {
35
+ label: "Strikethrough",
36
+ icon: Strikethrough,
37
+ group: "marks",
38
+ shortcut: "Mod-Shift-S",
39
+ toggle: true,
40
+ run: function run(c) {
41
+ return c.toggleStrike();
42
+ }
43
+ },
44
+ code: {
45
+ label: "Inline code",
46
+ icon: Code,
47
+ group: "marks",
48
+ shortcut: "Mod-E",
49
+ toggle: true,
50
+ run: function run(c) {
51
+ return c.toggleCode();
52
+ }
53
+ },
54
+ heading1: {
55
+ label: "Heading 1",
56
+ icon: Heading1,
57
+ group: "blocks",
58
+ shortcut: "Mod-Alt-1",
59
+ toggle: true,
60
+ run: function run(c) {
61
+ return c.toggleHeading({
62
+ level: 1
63
+ });
64
+ }
65
+ },
66
+ heading2: {
67
+ label: "Heading 2",
68
+ icon: Heading2,
69
+ group: "blocks",
70
+ shortcut: "Mod-Alt-2",
71
+ toggle: true,
72
+ run: function run(c) {
73
+ return c.toggleHeading({
74
+ level: 2
75
+ });
76
+ }
77
+ },
78
+ heading3: {
79
+ label: "Heading 3",
80
+ icon: Heading3,
81
+ group: "blocks",
82
+ shortcut: "Mod-Alt-3",
83
+ toggle: true,
84
+ run: function run(c) {
85
+ return c.toggleHeading({
86
+ level: 3
87
+ });
88
+ }
89
+ },
90
+ bulletList: {
91
+ label: "Bulleted list",
92
+ icon: List,
93
+ group: "blocks",
94
+ shortcut: "Mod-Shift-8",
95
+ toggle: true,
96
+ run: function run(c) {
97
+ return c.toggleBulletList();
98
+ }
99
+ },
100
+ orderedList: {
101
+ label: "Numbered list",
102
+ icon: ListOrdered,
103
+ group: "blocks",
104
+ shortcut: "Mod-Shift-7",
105
+ toggle: true,
106
+ run: function run(c) {
107
+ return c.toggleOrderedList();
108
+ }
109
+ },
110
+ blockquote: {
111
+ label: "Quote",
112
+ icon: Quote,
113
+ group: "blocks",
114
+ shortcut: "Mod-Shift-B",
115
+ toggle: true,
116
+ run: function run(c) {
117
+ return c.toggleBlockquote();
118
+ }
119
+ },
120
+ codeBlock: {
121
+ label: "Code block",
122
+ icon: SquareCode,
123
+ group: "blocks",
124
+ shortcut: "Mod-Alt-C",
125
+ toggle: true,
126
+ run: function run(c) {
127
+ return c.toggleCodeBlock();
128
+ }
129
+ },
130
+ link: {
131
+ label: "Link",
132
+ icon: Link,
133
+ group: "insert",
134
+ toggle: true
135
+ },
136
+ undo: {
137
+ label: "Undo",
138
+ icon: Undo,
139
+ group: "history",
140
+ shortcut: "Mod-Z",
141
+ run: function run(c) {
142
+ return c.undo();
143
+ }
144
+ },
145
+ redo: {
146
+ label: "Redo",
147
+ icon: Redo,
148
+ group: "history",
149
+ shortcut: "Mod-Shift-Z",
150
+ run: function run(c) {
151
+ return c.redo();
152
+ }
153
+ }
154
+ };
155
+ var DEFAULT_TOOLBAR = ["bold", "italic", "strike", "code", "heading2", "heading3", "bulletList", "orderedList", "blockquote", "link", "undo", "redo"];
156
+ /** Toolbar state derived from the editor on every transaction (via useEditorState). */
157
+ function selectToolbarState(editor) {
158
+ if (!editor) return null;
159
+ return {
160
+ isEmpty: editor.isEmpty,
161
+ bold: editor.isActive("bold"),
162
+ italic: editor.isActive("italic"),
163
+ strike: editor.isActive("strike"),
164
+ code: editor.isActive("code"),
165
+ heading1: editor.isActive("heading", {
166
+ level: 1
167
+ }),
168
+ heading2: editor.isActive("heading", {
169
+ level: 2
170
+ }),
171
+ heading3: editor.isActive("heading", {
172
+ level: 3
173
+ }),
174
+ bulletList: editor.isActive("bulletList"),
175
+ orderedList: editor.isActive("orderedList"),
176
+ blockquote: editor.isActive("blockquote"),
177
+ codeBlock: editor.isActive("codeBlock"),
178
+ link: editor.isActive("link"),
179
+ undo: editor.can().undo(),
180
+ redo: editor.can().redo()
181
+ };
182
+ }
183
+ var SAFE_URL = /^(https?:|mailto:|tel:|\/|#)/i;
184
+ var HAS_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
185
+ /** Normalises a typed URL; returns null for schemes we refuse (javascript:, data:, …). */
186
+ function normalizeUrl(raw) {
187
+ var url = String(raw || "").trim();
188
+ if (!url) return "";
189
+ if (SAFE_URL.test(url)) return url;
190
+ if (HAS_SCHEME.test(url)) return null;
191
+ return "https://".concat(url);
192
+ }
193
+ function LinkForm(_ref) {
194
+ var editor = _ref.editor,
195
+ onClose = _ref.onClose;
196
+ var _useState = useState(function () {
197
+ return editor.getAttributes("link").href || "";
198
+ }),
199
+ _useState2 = _slicedToArray(_useState, 2),
200
+ href = _useState2[0],
201
+ setHref = _useState2[1];
202
+ var _useState3 = useState(false),
203
+ _useState4 = _slicedToArray(_useState3, 2),
204
+ invalid = _useState4[0],
205
+ setInvalid = _useState4[1];
206
+ var inputRef = useRef(null);
207
+ useEffect(function () {
208
+ var _inputRef$current;
209
+ (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 || _inputRef$current.focus();
210
+ }, []);
211
+ var close = function close() {
212
+ onClose();
213
+ editor.commands.focus();
214
+ };
215
+ var apply = function apply() {
216
+ var url = normalizeUrl(href);
217
+ if (url === null) {
218
+ setInvalid(true);
219
+ return;
220
+ }
221
+ var chain = editor.chain().focus().extendMarkRange("link");
222
+ if (!url) chain.unsetLink().run();else if (editor.state.selection.empty && !editor.isActive("link")) {
223
+ chain.insertContent({
224
+ type: "text",
225
+ text: url,
226
+ marks: [{
227
+ type: "link",
228
+ attrs: {
229
+ href: url
230
+ }
231
+ }]
232
+ }).run();
233
+ } else chain.setLink({
234
+ href: url
235
+ }).run();
236
+ onClose();
237
+ };
238
+ var remove = function remove() {
239
+ editor.chain().focus().extendMarkRange("link").unsetLink().run();
240
+ onClose();
241
+ };
242
+ return jsxs("div", {
243
+ className: "flex flex-wrap items-center gap-2 border-b border-gray-200 px-2 py-2 dark:border-gray-700",
244
+ children: [jsx("input", {
245
+ ref: inputRef,
246
+ type: "url",
247
+ value: href,
248
+ "aria-label": "Link URL",
249
+ "aria-invalid": invalid || undefined,
250
+ placeholder: "https://example.com",
251
+ onChange: function onChange(e) {
252
+ setHref(e.target.value);
253
+ setInvalid(false);
254
+ },
255
+ onKeyDown: function onKeyDown(e) {
256
+ if (e.key === "Enter") {
257
+ e.preventDefault();
258
+ apply();
259
+ } else if (e.key === "Escape") {
260
+ e.preventDefault();
261
+ close();
262
+ }
263
+ },
264
+ className: cn("h-8 min-w-0 flex-1 rounded-md border bg-white px-2 text-sm text-gray-900 placeholder-gray-400", "focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-gray-900 dark:text-gray-100 dark:placeholder-gray-500", invalid ? "border-error-500" : "border-gray-300 dark:border-gray-600")
265
+ }), jsx("button", {
266
+ type: "button",
267
+ onClick: apply,
268
+ className: formButton,
269
+ children: "Apply"
270
+ }), editor.isActive("link") && jsx("button", {
271
+ type: "button",
272
+ onClick: remove,
273
+ className: formButton,
274
+ children: "Remove link"
275
+ }), jsx("button", {
276
+ type: "button",
277
+ onClick: close,
278
+ className: formButton,
279
+ children: "Cancel"
280
+ }), invalid && jsx("p", {
281
+ className: "w-full text-xs text-error-600 dark:text-error-400",
282
+ role: "alert",
283
+ children: "Use an http(s), mailto: or tel: link."
284
+ })]
285
+ });
286
+ }
287
+ var formButton = "h-8 rounded-md px-2 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 dark:text-gray-200 dark:hover:bg-gray-800";
288
+ /**
289
+ * A WAI-ARIA toolbar: one tab stop, arrow keys / Home / End move between the
290
+ * buttons (roving tabindex), toggles report `aria-pressed`.
291
+ */
292
+ function RichTextToolbar(_ref2) {
293
+ var editor = _ref2.editor,
294
+ state = _ref2.state,
295
+ items = _ref2.items,
296
+ disabled = _ref2.disabled,
297
+ controlsId = _ref2.controlsId,
298
+ _ref2$label = _ref2.label,
299
+ label = _ref2$label === void 0 ? "Formatting" : _ref2$label;
300
+ var _useState5 = useState(0),
301
+ _useState6 = _slicedToArray(_useState5, 2),
302
+ focusIndex = _useState6[0],
303
+ setFocusIndex = _useState6[1];
304
+ var _useState7 = useState(false),
305
+ _useState8 = _slicedToArray(_useState7, 2),
306
+ linkOpen = _useState8[0],
307
+ setLinkOpen = _useState8[1];
308
+ var buttons = useRef([]);
309
+ var keys = items.filter(function (k) {
310
+ return TOOLBAR_ITEMS[k];
311
+ });
312
+ var moveFocus = function moveFocus(i) {
313
+ var _buttons$current$next;
314
+ var next = (i + keys.length) % keys.length;
315
+ setFocusIndex(next);
316
+ (_buttons$current$next = buttons.current[next]) === null || _buttons$current$next === void 0 || _buttons$current$next.focus();
317
+ };
318
+ var onKeyDown = function onKeyDown(e) {
319
+ var map = {
320
+ ArrowRight: focusIndex + 1,
321
+ ArrowLeft: focusIndex - 1,
322
+ Home: 0,
323
+ End: keys.length - 1
324
+ };
325
+ if (!(e.key in map)) return;
326
+ e.preventDefault();
327
+ moveFocus(map[e.key]);
328
+ };
329
+ var activate = function activate(key) {
330
+ if (!editor) return;
331
+ if (key === "link") {
332
+ setLinkOpen(function (open) {
333
+ return !open;
334
+ });
335
+ return;
336
+ }
337
+ var item = TOOLBAR_ITEMS[key];
338
+ if (!item.toggle && state && !state[key]) return;
339
+ item.run(editor.chain().focus()).run();
340
+ };
341
+ return jsxs(Fragment, {
342
+ children: [jsx("div", {
343
+ role: "toolbar",
344
+ "aria-label": label,
345
+ "aria-controls": controlsId,
346
+ "aria-orientation": "horizontal",
347
+ onKeyDown: onKeyDown,
348
+ className: "flex flex-wrap items-center gap-0.5 border-b border-gray-200 bg-gray-50 px-1 py-1 dark:border-gray-700 dark:bg-gray-800/60",
349
+ children: keys.map(function (key, i) {
350
+ var item = TOOLBAR_ITEMS[key];
351
+ var Icon = item.icon;
352
+ var pressed = item.toggle ? Boolean(state === null || state === void 0 ? void 0 : state[key]) || key === "link" && linkOpen : undefined;
353
+ var unavailable = !item.toggle && state ? !state[key] : false;
354
+ var newGroup = i > 0 && TOOLBAR_ITEMS[keys[i - 1]].group !== item.group;
355
+ return jsxs(React.Fragment, {
356
+ children: [newGroup && jsx("span", {
357
+ className: "mx-1 h-5 w-px bg-gray-300 dark:bg-gray-600",
358
+ "aria-hidden": "true"
359
+ }), jsx("button", {
360
+ ref: function ref(node) {
361
+ buttons.current[i] = node;
362
+ },
363
+ type: "button",
364
+ tabIndex: i === focusIndex ? 0 : -1,
365
+ "aria-label": item.label,
366
+ "aria-pressed": pressed,
367
+ "aria-disabled": unavailable || undefined,
368
+ "aria-keyshortcuts": item.shortcut ? item.shortcut.replace("Mod", isMac ? "Meta" : "Control").replace(/-/g, "+") : undefined,
369
+ title: item.shortcut ? "".concat(item.label, " (").concat(shortcutLabel(item.shortcut), ")") : item.label,
370
+ disabled: disabled || !editor,
371
+ onFocus: function onFocus() {
372
+ return setFocusIndex(i);
373
+ },
374
+ onMouseDown: function onMouseDown(e) {
375
+ return e.preventDefault();
376
+ },
377
+ onClick: function onClick() {
378
+ return activate(key);
379
+ },
380
+ className: cn("inline-flex h-8 w-8 items-center justify-center rounded-md text-gray-600 transition-colors", "hover:bg-gray-200 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-700 dark:hover:text-gray-100", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500", "disabled:cursor-not-allowed disabled:opacity-50", pressed && "bg-primary-100 text-primary-700 dark:bg-primary-900/40 dark:text-primary-300", unavailable && "opacity-40"),
381
+ children: jsx(Icon, {
382
+ className: "h-4 w-4",
383
+ "aria-hidden": "true"
384
+ })
385
+ })]
386
+ }, key);
387
+ })
388
+ }), linkOpen && editor && jsx(LinkForm, {
389
+ editor: editor,
390
+ onClose: function onClose() {
391
+ return setLinkOpen(false);
392
+ }
393
+ })]
394
+ });
395
+ }
396
+
397
+ export { DEFAULT_TOOLBAR, RichTextToolbar, TOOLBAR_ITEMS, normalizeUrl, selectToolbarState };