@mieweb/ui 0.11.0-dev.34 → 0.11.0-dev.36

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 (156) hide show
  1. package/MIGRATION.md +45 -11
  2. package/dist/{EncounterMdyEditor-73PTTIRY.cjs → EncounterMdyEditor-46WMYRFI.cjs} +6 -6
  3. package/dist/{EncounterMdyEditor-73PTTIRY.cjs.map → EncounterMdyEditor-46WMYRFI.cjs.map} +1 -1
  4. package/dist/{EncounterMdyEditor-3SQY4MK2.js → EncounterMdyEditor-L7RBLE7B.js} +3 -3
  5. package/dist/{EncounterMdyEditor-3SQY4MK2.js.map → EncounterMdyEditor-L7RBLE7B.js.map} +1 -1
  6. package/dist/{chunk-4SUEBKTY.js → chunk-2OTPQPJS.js} +52 -44
  7. package/dist/chunk-2OTPQPJS.js.map +1 -0
  8. package/dist/{chunk-MZR634HI.cjs → chunk-3M2BBOXF.cjs} +9 -9
  9. package/dist/{chunk-MZR634HI.cjs.map → chunk-3M2BBOXF.cjs.map} +1 -1
  10. package/dist/{chunk-6UYMO3PF.cjs → chunk-47AOS5EC.cjs} +10 -2
  11. package/dist/chunk-47AOS5EC.cjs.map +1 -0
  12. package/dist/{chunk-DXNVQQYN.cjs → chunk-6L7CTEX2.cjs} +51 -44
  13. package/dist/chunk-6L7CTEX2.cjs.map +1 -0
  14. package/dist/{chunk-RTADGBBN.js → chunk-AIO2GCTL.js} +3 -3
  15. package/dist/{chunk-RTADGBBN.js.map → chunk-AIO2GCTL.js.map} +1 -1
  16. package/dist/{chunk-EX7Q5545.js → chunk-AKC677ZF.js} +5 -5
  17. package/dist/{chunk-EX7Q5545.js.map → chunk-AKC677ZF.js.map} +1 -1
  18. package/dist/{chunk-XEHD2HA5.cjs → chunk-FRPELUI5.cjs} +3 -3
  19. package/dist/{chunk-XEHD2HA5.cjs.map → chunk-FRPELUI5.cjs.map} +1 -1
  20. package/dist/{chunk-DGHS5IVD.js → chunk-GJSLKD4Q.js} +3 -3
  21. package/dist/{chunk-DGHS5IVD.js.map → chunk-GJSLKD4Q.js.map} +1 -1
  22. package/dist/{chunk-VMEVLBI3.js → chunk-GKMMDKYY.js} +3 -3
  23. package/dist/{chunk-VMEVLBI3.js.map → chunk-GKMMDKYY.js.map} +1 -1
  24. package/dist/{chunk-46RYJYN2.cjs → chunk-GU6TPVXF.cjs} +6 -6
  25. package/dist/{chunk-46RYJYN2.cjs.map → chunk-GU6TPVXF.cjs.map} +1 -1
  26. package/dist/chunk-IALTKN3Y.js +1017 -0
  27. package/dist/chunk-IALTKN3Y.js.map +1 -0
  28. package/dist/{chunk-33Y3KQWL.js → chunk-IGRHPZOJ.js} +3 -3
  29. package/dist/{chunk-33Y3KQWL.js.map → chunk-IGRHPZOJ.js.map} +1 -1
  30. package/dist/{chunk-PLBWZW4F.js → chunk-KAQNYX7B.js} +3 -3
  31. package/dist/{chunk-PLBWZW4F.js.map → chunk-KAQNYX7B.js.map} +1 -1
  32. package/dist/{chunk-SPGP252Q.js → chunk-KB2PLV5Q.js} +4 -4
  33. package/dist/{chunk-SPGP252Q.js.map → chunk-KB2PLV5Q.js.map} +1 -1
  34. package/dist/{chunk-NCPDUJKJ.cjs → chunk-KQXD6BFO.cjs} +4 -4
  35. package/dist/{chunk-NCPDUJKJ.cjs.map → chunk-KQXD6BFO.cjs.map} +1 -1
  36. package/dist/{chunk-4VSK3EE5.cjs → chunk-L77XJPKC.cjs} +3 -3
  37. package/dist/{chunk-4VSK3EE5.cjs.map → chunk-L77XJPKC.cjs.map} +1 -1
  38. package/dist/{chunk-PGJLW2NO.cjs → chunk-LLIG4X6M.cjs} +7 -7
  39. package/dist/{chunk-PGJLW2NO.cjs.map → chunk-LLIG4X6M.cjs.map} +1 -1
  40. package/dist/{chunk-NW6D6AFL.js → chunk-LWLHCUDP.js} +10 -10
  41. package/dist/{chunk-NW6D6AFL.js.map → chunk-LWLHCUDP.js.map} +1 -1
  42. package/dist/{chunk-YR45POH2.js → chunk-MAEANAAJ.js} +3 -3
  43. package/dist/{chunk-YR45POH2.js.map → chunk-MAEANAAJ.js.map} +1 -1
  44. package/dist/{chunk-X5HLVACK.js → chunk-MLCIINXT.js} +4 -4
  45. package/dist/{chunk-X5HLVACK.js.map → chunk-MLCIINXT.js.map} +1 -1
  46. package/dist/{chunk-JEXEFWEM.js → chunk-MNXIN4MS.js} +10 -2
  47. package/dist/chunk-MNXIN4MS.js.map +1 -0
  48. package/dist/{chunk-PHUTJKHL.cjs → chunk-MXIIPFTA.cjs} +3 -3
  49. package/dist/{chunk-PHUTJKHL.cjs.map → chunk-MXIIPFTA.cjs.map} +1 -1
  50. package/dist/{chunk-QO4A6U73.cjs → chunk-NCG7NJAW.cjs} +93 -30
  51. package/dist/chunk-NCG7NJAW.cjs.map +1 -0
  52. package/dist/{chunk-25MPUVTM.js → chunk-NIE3WBJH.js} +94 -31
  53. package/dist/chunk-NIE3WBJH.js.map +1 -0
  54. package/dist/{chunk-4GSFVD5V.js → chunk-NUHHWELE.js} +3 -3
  55. package/dist/{chunk-4GSFVD5V.js.map → chunk-NUHHWELE.js.map} +1 -1
  56. package/dist/{chunk-4M2KE4O5.cjs → chunk-OGFSFUIX.cjs} +7 -7
  57. package/dist/{chunk-4M2KE4O5.cjs.map → chunk-OGFSFUIX.cjs.map} +1 -1
  58. package/dist/{chunk-YSIFPHLX.js → chunk-OJQMC426.js} +2 -2
  59. package/dist/{chunk-YSIFPHLX.js.map → chunk-OJQMC426.js.map} +1 -1
  60. package/dist/{chunk-SVC7NPQ6.cjs → chunk-PDLVSJMZ.cjs} +6 -6
  61. package/dist/{chunk-SVC7NPQ6.cjs.map → chunk-PDLVSJMZ.cjs.map} +1 -1
  62. package/dist/{chunk-KD7YD6US.cjs → chunk-QOQQVNP3.cjs} +2 -2
  63. package/dist/{chunk-KD7YD6US.cjs.map → chunk-QOQQVNP3.cjs.map} +1 -1
  64. package/dist/{chunk-6O6EYKOG.cjs → chunk-R4QWCP2T.cjs} +65 -65
  65. package/dist/{chunk-6O6EYKOG.cjs.map → chunk-R4QWCP2T.cjs.map} +1 -1
  66. package/dist/chunk-RCTIPBLU.cjs +1039 -0
  67. package/dist/chunk-RCTIPBLU.cjs.map +1 -0
  68. package/dist/{chunk-FSWHZY3T.cjs → chunk-RD2I67C4.cjs} +3 -3
  69. package/dist/{chunk-FSWHZY3T.cjs.map → chunk-RD2I67C4.cjs.map} +1 -1
  70. package/dist/{chunk-YGSPIDE4.js → chunk-RM4CBS7Y.js} +3 -3
  71. package/dist/{chunk-YGSPIDE4.js.map → chunk-RM4CBS7Y.js.map} +1 -1
  72. package/dist/{chunk-3O3Q3DX7.cjs → chunk-S3LTUSO5.cjs} +21 -21
  73. package/dist/{chunk-3O3Q3DX7.cjs.map → chunk-S3LTUSO5.cjs.map} +1 -1
  74. package/dist/{chunk-2OXNJJHJ.cjs → chunk-TERHGQ73.cjs} +3 -3
  75. package/dist/{chunk-2OXNJJHJ.cjs.map → chunk-TERHGQ73.cjs.map} +1 -1
  76. package/dist/{chunk-DO7EED3B.cjs → chunk-WZ7WTIVU.cjs} +3 -3
  77. package/dist/{chunk-DO7EED3B.cjs.map → chunk-WZ7WTIVU.cjs.map} +1 -1
  78. package/dist/{chunk-566FIEPE.js → chunk-YFZNSP7F.js} +3 -3
  79. package/dist/{chunk-566FIEPE.js.map → chunk-YFZNSP7F.js.map} +1 -1
  80. package/dist/{chunk-I6Y2KLTZ.js → chunk-ZP4H5HA4.js} +3 -3
  81. package/dist/{chunk-I6Y2KLTZ.js.map → chunk-ZP4H5HA4.js.map} +1 -1
  82. package/dist/components/ActionPlan/index.cjs +1 -1
  83. package/dist/components/ActionPlan/index.js +1 -1
  84. package/dist/components/AlertDialog/index.cjs +7 -7
  85. package/dist/components/AlertDialog/index.js +3 -3
  86. package/dist/components/CustomizableDashboard/index.cjs +1 -1
  87. package/dist/components/CustomizableDashboard/index.js +1 -1
  88. package/dist/components/DateInput/index.cjs +3 -3
  89. package/dist/components/DateInput/index.js +2 -2
  90. package/dist/components/EmailEditor/index.cjs +16 -13
  91. package/dist/components/EmailEditor/index.js +7 -4
  92. package/dist/components/KeyboardShortcutsOverlay/index.cjs +5 -5
  93. package/dist/components/KeyboardShortcutsOverlay/index.js +3 -3
  94. package/dist/components/Markdown/index.cjs +10 -10
  95. package/dist/components/Markdown/index.js +2 -2
  96. package/dist/components/MediaEditor/index.cjs +9 -9
  97. package/dist/components/MediaEditor/index.js +4 -4
  98. package/dist/components/MediaFeed/index.cjs +4 -4
  99. package/dist/components/MediaFeed/index.js +3 -3
  100. package/dist/components/Modal/index.cjs +10 -10
  101. package/dist/components/Modal/index.js +2 -2
  102. package/dist/components/RadialExplorer/index.cjs +3 -3
  103. package/dist/components/RadialExplorer/index.js +2 -2
  104. package/dist/components/RecordHeader/index.cjs +4 -4
  105. package/dist/components/RecordHeader/index.js +2 -2
  106. package/dist/components/RecordLayout/index.cjs +1 -1
  107. package/dist/components/RecordLayout/index.js +1 -1
  108. package/dist/components/Sheet/index.cjs +1 -1
  109. package/dist/components/Sheet/index.js +1 -1
  110. package/dist/components/SuperChat/index.cjs +6 -6
  111. package/dist/components/SuperChat/index.js +5 -5
  112. package/dist/components/SuperChat/plugins/index.cjs +1 -1
  113. package/dist/components/SuperChat/plugins/index.js +1 -1
  114. package/dist/components/TagEditor/index.cjs +4 -4
  115. package/dist/components/TagEditor/index.js +2 -2
  116. package/dist/components/Textarea/index.cjs +7 -4
  117. package/dist/components/Textarea/index.js +4 -1
  118. package/dist/esheet.cjs +122 -123
  119. package/dist/esheet.cjs.map +1 -1
  120. package/dist/esheet.js +25 -26
  121. package/dist/esheet.js.map +1 -1
  122. package/dist/hooks/index.cjs +15 -15
  123. package/dist/hooks/index.js +3 -3
  124. package/dist/index.cjs +456 -425
  125. package/dist/index.cjs.map +1 -1
  126. package/dist/index.d.cts +19 -10
  127. package/dist/index.d.ts +19 -10
  128. package/dist/index.js +80 -42
  129. package/dist/index.js.map +1 -1
  130. package/dist/kerebron.cjs +32 -62
  131. package/dist/kerebron.cjs.map +1 -1
  132. package/dist/kerebron.css +145 -8
  133. package/dist/kerebron.d.cts +299 -1
  134. package/dist/kerebron.d.ts +299 -1
  135. package/dist/kerebron.js +22 -63
  136. package/dist/kerebron.js.map +1 -1
  137. package/dist/{model-EFXX5JZN.cjs → model-5PB6KNYH.cjs} +20 -20
  138. package/dist/{model-EFXX5JZN.cjs.map → model-5PB6KNYH.cjs.map} +1 -1
  139. package/dist/{model-TAARSYDY.js → model-OGWTZEXR.js} +6 -6
  140. package/dist/{model-TAARSYDY.js.map → model-OGWTZEXR.js.map} +1 -1
  141. package/dist/styles.css +1 -1
  142. package/dist/tailwind-preset.cjs +4 -4
  143. package/dist/tailwind-preset.js +1 -1
  144. package/dist/templates.cjs +31 -31
  145. package/dist/templates.js +2 -2
  146. package/dist/utils/index.cjs +5 -5
  147. package/dist/utils/index.d.cts +12 -12
  148. package/dist/utils/index.d.ts +12 -12
  149. package/dist/utils/index.js +1 -1
  150. package/package.json +3 -13
  151. package/dist/chunk-25MPUVTM.js.map +0 -1
  152. package/dist/chunk-4SUEBKTY.js.map +0 -1
  153. package/dist/chunk-6UYMO3PF.cjs.map +0 -1
  154. package/dist/chunk-DXNVQQYN.cjs.map +0 -1
  155. package/dist/chunk-JEXEFWEM.js.map +0 -1
  156. package/dist/chunk-QO4A6U73.cjs.map +0 -1
@@ -0,0 +1,1039 @@
1
+ 'use strict';
2
+
3
+ var chunkNCG7NJAW_cjs = require('./chunk-NCG7NJAW.cjs');
4
+ var chunkS2CJ57BX_cjs = require('./chunk-S2CJ57BX.cjs');
5
+ var chunkFSLI5IKP_cjs = require('./chunk-FSLI5IKP.cjs');
6
+ var chunkPINIBEIU_cjs = require('./chunk-PINIBEIU.cjs');
7
+ var chunkPHYQSCP6_cjs = require('./chunk-PHYQSCP6.cjs');
8
+ var chunkYW2AKBLS_cjs = require('./chunk-YW2AKBLS.cjs');
9
+ var chunkZ3WMDVMR_cjs = require('./chunk-Z3WMDVMR.cjs');
10
+ var chunkFSARTLUE_cjs = require('./chunk-FSARTLUE.cjs');
11
+ var chunkIEY3ZJIT_cjs = require('./chunk-IEY3ZJIT.cjs');
12
+ var chunkS5RVSXDV_cjs = require('./chunk-S5RVSXDV.cjs');
13
+ var React2 = require('react');
14
+ var editor = require('@kerebron/editor');
15
+ var CodeEditorKit = require('@kerebron/editor-kits/CodeEditorKit');
16
+ var web = require('@kerebron/wasm/web');
17
+ var jsxRuntime = require('react/jsx-runtime');
18
+ var prosemirrorState = require('prosemirror-state');
19
+ var extensionMenu = require('@kerebron/extension-menu');
20
+ var lucideReact = require('lucide-react');
21
+
22
+ function _interopNamespace(e) {
23
+ if (e && e.__esModule) return e;
24
+ var n = Object.create(null);
25
+ if (e) {
26
+ Object.keys(e).forEach(function (k) {
27
+ if (k !== 'default') {
28
+ var d = Object.getOwnPropertyDescriptor(e, k);
29
+ Object.defineProperty(n, k, d.get ? d : {
30
+ enumerable: true,
31
+ get: function () { return e[k]; }
32
+ });
33
+ }
34
+ });
35
+ }
36
+ n.default = e;
37
+ return Object.freeze(n);
38
+ }
39
+
40
+ var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
41
+
42
+ var CodeEditor = ({
43
+ value = "",
44
+ onChange,
45
+ lang = "typescript"
46
+ }) => {
47
+ const editorRef = React2.useRef(null);
48
+ const editorInstance = React2.useRef(null);
49
+ const onChangeRef = React2.useRef(onChange);
50
+ onChangeRef.current = onChange;
51
+ React2.useEffect(() => {
52
+ const root = editorRef.current;
53
+ if (!root) return;
54
+ const applySelectLabel = () => {
55
+ root.querySelectorAll("select.codejar-select").forEach((element) => {
56
+ if (!element.getAttribute("aria-label")) {
57
+ element.setAttribute("aria-label", "Code editor language");
58
+ }
59
+ });
60
+ };
61
+ applySelectLabel();
62
+ const observer = new MutationObserver(() => applySelectLabel());
63
+ observer.observe(root, { childList: true, subtree: true });
64
+ return () => observer.disconnect();
65
+ }, []);
66
+ React2.useEffect(() => {
67
+ if (!editorRef.current) return;
68
+ const editor$1 = editor.CoreEditor.create({
69
+ element: editorRef.current,
70
+ uri: "file:///untitled.ts",
71
+ assetLoad: web.createAssetLoad("/kerebron-wasm"),
72
+ editorKits: [new CodeEditorKit.CodeEditorKit(lang)]
73
+ });
74
+ editorInstance.current = editor$1;
75
+ const onTransaction = async () => {
76
+ if (!editorInstance.current) return;
77
+ try {
78
+ const buffer = await editorInstance.current.saveDocument("text/plain");
79
+ onChangeRef.current?.(new globalThis.TextDecoder().decode(buffer));
80
+ } catch (err) {
81
+ console.error("Failed to read code:", err);
82
+ }
83
+ };
84
+ editor$1.addEventListener("transaction", onTransaction);
85
+ if (value) {
86
+ editor$1.loadDocumentText("text/plain", value).catch((err) => console.error("Failed to load code:", err));
87
+ }
88
+ return () => {
89
+ editor$1.removeEventListener("transaction", onTransaction);
90
+ editor$1.destroy();
91
+ };
92
+ }, []);
93
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: editorRef, className: "kb-component" }) }) });
94
+ };
95
+ CodeEditor.displayName = "CodeEditor";
96
+
97
+ // src/components/TextAreaRich/speech.ts
98
+ function getSpeechRecognition() {
99
+ if (typeof window === "undefined") return void 0;
100
+ const w = window;
101
+ return w.SpeechRecognition || w.webkitSpeechRecognition;
102
+ }
103
+ var TextAreaRichExtension = class extends editor.Extension {
104
+ constructor(onKeyDown) {
105
+ super({});
106
+ this.onKeyDown = onKeyDown;
107
+ }
108
+ onKeyDown;
109
+ name = "textAreaRichShortcuts";
110
+ getProseMirrorPlugins() {
111
+ return [new prosemirrorState.Plugin({ props: { handleKeyDown: this.onKeyDown } })];
112
+ }
113
+ };
114
+ var viewOf = (editor) => editor.view;
115
+ var UNITLESS_STYLE_PROPS = /* @__PURE__ */ new Set([
116
+ "animationIterationCount",
117
+ "aspectRatio",
118
+ "borderImageOutset",
119
+ "borderImageSlice",
120
+ "borderImageWidth",
121
+ "boxFlex",
122
+ "boxFlexGroup",
123
+ "boxOrdinalGroup",
124
+ "columnCount",
125
+ "columns",
126
+ "flex",
127
+ "flexGrow",
128
+ "flexPositive",
129
+ "flexShrink",
130
+ "flexNegative",
131
+ "flexOrder",
132
+ "fontWeight",
133
+ "gridArea",
134
+ "gridRow",
135
+ "gridRowEnd",
136
+ "gridRowSpan",
137
+ "gridRowStart",
138
+ "gridColumn",
139
+ "gridColumnEnd",
140
+ "gridColumnSpan",
141
+ "gridColumnStart",
142
+ "lineClamp",
143
+ "lineHeight",
144
+ "opacity",
145
+ "order",
146
+ "orphans",
147
+ "tabSize",
148
+ "widows",
149
+ "zIndex",
150
+ "zoom",
151
+ // SVG-related
152
+ "fillOpacity",
153
+ "floodOpacity",
154
+ "stopOpacity",
155
+ "strokeDasharray",
156
+ "strokeDashoffset",
157
+ "strokeMiterlimit",
158
+ "strokeOpacity",
159
+ "strokeWidth"
160
+ ]);
161
+ function insertPlainText(view, text, from = view.state.selection.from, to = view.state.selection.to) {
162
+ const { schema, selection, storedMarks } = view.state;
163
+ const marks = (from === selection.from && to === selection.to ? storedMarks : null) ?? view.state.doc.resolve(from).marks();
164
+ const br = schema.nodes.br ?? schema.nodes.hard_break;
165
+ const lines = text.replace(/\r\n?/g, "\n").split("\n");
166
+ const nodes = [];
167
+ lines.forEach((line, index) => {
168
+ if (index > 0) {
169
+ if (br) nodes.push(br.create(null, null, marks));
170
+ else if (line) nodes.push(schema.text(" ", marks));
171
+ }
172
+ if (line) nodes.push(schema.text(line, marks));
173
+ });
174
+ let tr = view.state.tr.replaceWith(from, to, nodes);
175
+ const end = Math.min(
176
+ from + nodes.reduce((size, node) => size + node.nodeSize, 0),
177
+ tr.doc.content.size
178
+ );
179
+ tr = tr.setSelection(prosemirrorState.TextSelection.near(tr.doc.resolve(end)));
180
+ view.dispatch(tr.scrollIntoView());
181
+ }
182
+ function docIsEmpty(view) {
183
+ const { doc } = view.state;
184
+ return doc.childCount === 1 && !!doc.firstChild && doc.firstChild.isTextblock && doc.firstChild.content.size === 0;
185
+ }
186
+ var BLOCK_FORMAT_ITEMS = [
187
+ { key: "text", label: "Text", command: "setParagraph" },
188
+ { key: "heading1", label: "Heading 1", command: "setHeading1" },
189
+ { key: "heading2", label: "Heading 2", command: "setHeading2" },
190
+ { key: "heading3", label: "Heading 3", command: "setHeading3" },
191
+ { key: "bulletList", label: "Bullet list", command: "toggleBulletList" },
192
+ { key: "numberedList", label: "Numbered list", command: "toggleOrderedList" },
193
+ { key: "quote", label: "Quote", command: "toggleBlockquote" }
194
+ ];
195
+ var TextAreaRichKerebron = React2__namespace.forwardRef(
196
+ ({
197
+ value = "",
198
+ onChange,
199
+ placeholder,
200
+ className,
201
+ enableDictation = true,
202
+ onDictationError,
203
+ disabled = false,
204
+ macros,
205
+ defaultMacrosOpen = false,
206
+ macrosOnFocus = false,
207
+ compactMacros = false,
208
+ onMacroInsert,
209
+ macroLabels,
210
+ onCreateMacro,
211
+ toolbar,
212
+ defaultToolbar = "hidden",
213
+ onToolbarChange,
214
+ blockMenuLabels,
215
+ id,
216
+ readOnly = false,
217
+ editorClassName,
218
+ editorStyle,
219
+ "aria-label": ariaLabel,
220
+ "aria-labelledby": ariaLabelledBy,
221
+ "aria-describedby": ariaDescribedBy,
222
+ "aria-invalid": ariaInvalid,
223
+ "aria-required": ariaRequired
224
+ }, ref) => {
225
+ const inert = disabled || readOnly;
226
+ const wrapperRef = React2__namespace.useRef(null);
227
+ const gutterWrapperRef = React2__namespace.useRef(null);
228
+ const editorHandleRef = React2__namespace.useRef(null);
229
+ const editorRef = React2__namespace.useRef(null);
230
+ const [ready, setReady] = React2__namespace.useState(false);
231
+ React2__namespace.useImperativeHandle(
232
+ ref,
233
+ () => ready && editorRef.current ? viewOf(editorRef.current).dom : wrapperRef.current,
234
+ [ready]
235
+ );
236
+ const [macrosOpen, setMacrosOpen] = React2__namespace.useState(
237
+ defaultMacrosOpen && !macrosOnFocus
238
+ );
239
+ const [uncontrolledToolbar, setUncontrolledToolbar] = React2__namespace.useState(defaultToolbar);
240
+ const toolbarVisible = (toolbar ?? uncontrolledToolbar) === "visible";
241
+ const [isListening, setIsListening] = React2__namespace.useState(false);
242
+ const [speechSupported, setSpeechSupported] = React2__namespace.useState(false);
243
+ const [isEmpty, setIsEmpty] = React2__namespace.useState(true);
244
+ const [editorTop, setEditorTop] = React2__namespace.useState(0);
245
+ const [blockMenuOpen, setBlockMenuOpen] = React2__namespace.useState(false);
246
+ const [gutterTop, setGutterTop] = React2__namespace.useState(4);
247
+ const recognitionRef = React2__namespace.useRef(null);
248
+ const isListeningRef = React2__namespace.useRef(false);
249
+ const shouldRestartRef = React2__namespace.useRef(false);
250
+ const dictationSessionRef = React2__namespace.useRef(0);
251
+ const hoverBlockRef = React2__namespace.useRef(null);
252
+ const blockTargetPosRef = React2__namespace.useRef(null);
253
+ const firstBlockItemRef = React2__namespace.useRef(null);
254
+ const macroPanelId = React2__namespace.useId();
255
+ const macroSidePanel = chunkPHYQSCP6_cjs.useMediaQuery("(min-width: 768px)");
256
+ const prefersReducedMotion = chunkYW2AKBLS_cjs.usePrefersReducedMotion();
257
+ const direction = chunkZ3WMDVMR_cjs.useDirection(wrapperRef);
258
+ const hasMacros = Boolean(macros);
259
+ const hasMacroEntries = Boolean(
260
+ macros?.some((group) => group.macros.length > 0)
261
+ );
262
+ const gutterActive = !inert;
263
+ const macrosRef = React2__namespace.useRef(macros);
264
+ macrosRef.current = macros;
265
+ const hasMacrosRef = React2__namespace.useRef(hasMacros);
266
+ hasMacrosRef.current = hasMacros;
267
+ const onMacroInsertRef = React2__namespace.useRef(onMacroInsert);
268
+ onMacroInsertRef.current = onMacroInsert;
269
+ const onChangeRef = React2__namespace.useRef(onChange);
270
+ onChangeRef.current = onChange;
271
+ const inertRef = React2__namespace.useRef(inert);
272
+ inertRef.current = inert;
273
+ const macrosOpenRef = React2__namespace.useRef(macrosOpen);
274
+ macrosOpenRef.current = macrosOpen;
275
+ const toolbarVisibleRef = React2__namespace.useRef(toolbarVisible);
276
+ toolbarVisibleRef.current = toolbarVisible;
277
+ const dictationAvailableRef = React2__namespace.useRef(false);
278
+ dictationAvailableRef.current = enableDictation && speechSupported;
279
+ const onDictationErrorRef = React2__namespace.useRef(onDictationError);
280
+ onDictationErrorRef.current = onDictationError;
281
+ const m = chunkFSLI5IKP_cjs.useMessages();
282
+ const reportError = (message) => {
283
+ if (onDictationErrorRef.current) onDictationErrorRef.current(message);
284
+ else if (typeof console !== "undefined") console.warn(message);
285
+ };
286
+ const setToolbarVisibility = (next) => {
287
+ if (toolbar === void 0) setUncontrolledToolbar(next);
288
+ onToolbarChange?.(next);
289
+ };
290
+ const focusEditor = () => editorHandleRef.current?.focus();
291
+ const currentView = () => editorRef.current ? viewOf(editorRef.current) : null;
292
+ const changeWaitersRef = React2__namespace.useRef([]);
293
+ const publishedDocRef = React2__namespace.useRef(null);
294
+ const handleChange = (next) => {
295
+ publishedDocRef.current = currentView()?.state.doc ?? null;
296
+ onChangeRef.current?.(next);
297
+ const waiters = changeWaitersRef.current;
298
+ changeWaitersRef.current = [];
299
+ for (const resolve of waiters) resolve();
300
+ };
301
+ const afterNextChange = () => new Promise((resolve) => {
302
+ const timer = setTimeout(resolve, 250);
303
+ changeWaitersRef.current.push(() => {
304
+ clearTimeout(timer);
305
+ resolve();
306
+ });
307
+ });
308
+ const insertMacro = (macro) => {
309
+ if (inertRef.current) return;
310
+ if (!onMacroInsertRef.current) {
311
+ const view2 = currentView();
312
+ if (!view2) return;
313
+ view2.focus();
314
+ insertPlainText(view2, macro.content);
315
+ return;
316
+ }
317
+ const view = currentView();
318
+ const pending = view && view.state.doc !== publishedDocRef.current;
319
+ const invoke = () => {
320
+ if (inertRef.current) return;
321
+ const liveView = currentView();
322
+ if (!liveView) return;
323
+ liveView.focus();
324
+ if (onMacroInsertRef.current?.(macro) === true) return;
325
+ insertPlainText(liveView, macro.content);
326
+ };
327
+ if (pending) void afterNextChange().then(invoke);
328
+ else invoke();
329
+ };
330
+ const expandTypedShortcut = (view) => {
331
+ const groups = macrosRef.current;
332
+ if (!groups) return false;
333
+ const { selection } = view.state;
334
+ if (!selection.empty) return false;
335
+ const { $from } = selection;
336
+ const textBefore = $from.parent.textBetween(
337
+ 0,
338
+ $from.parentOffset,
339
+ void 0,
340
+ "\n"
341
+ );
342
+ const match = /(\S+)$/.exec(textBefore);
343
+ if (!match) return false;
344
+ const lowered = match[1].toLowerCase();
345
+ const macro = groups.flatMap((group) => group.macros).find((candidate) => candidate.shortcut?.toLowerCase() === lowered);
346
+ if (!macro) return false;
347
+ const from = $from.pos - match[1].length;
348
+ if (!onMacroInsertRef.current) {
349
+ insertPlainText(view, macro.content, from, $from.pos);
350
+ return true;
351
+ }
352
+ const editor = editorRef.current;
353
+ view.dispatch(view.state.tr.delete(from, $from.pos));
354
+ if (!editor) return true;
355
+ let insertAt = from;
356
+ let targetValid = true;
357
+ const trackInsertionPoint = (event) => {
358
+ const tr = event.detail?.transaction;
359
+ if (!tr) return;
360
+ const mapped = tr.mapping.mapResult(insertAt);
361
+ if (mapped.deleted) targetValid = false;
362
+ insertAt = mapped.pos;
363
+ };
364
+ editor.addEventListener("transaction", trackInsertionPoint);
365
+ void afterNextChange().then(() => {
366
+ editor.removeEventListener("transaction", trackInsertionPoint);
367
+ if (inertRef.current || editorRef.current !== editor) return;
368
+ if (onMacroInsertRef.current?.(macro) === true) return;
369
+ if (!targetValid) return;
370
+ const liveView = viewOf(editor);
371
+ liveView.focus();
372
+ const at = Math.min(insertAt, liveView.state.doc.content.size);
373
+ insertPlainText(liveView, macro.content, at, at);
374
+ });
375
+ return true;
376
+ };
377
+ const resetGutter = () => {
378
+ hoverBlockRef.current = null;
379
+ setGutterTop(editorTop + 4);
380
+ };
381
+ const handleGutterMouseMove = (event) => {
382
+ if (blockMenuOpen) return;
383
+ const view = currentView();
384
+ const wrapper = gutterWrapperRef.current;
385
+ if (!view || !wrapper) return;
386
+ let target = null;
387
+ let top = null;
388
+ for (const child of Array.from(view.dom.children)) {
389
+ const rect = child.getBoundingClientRect();
390
+ if (rect.width === 0 && rect.height === 0) continue;
391
+ if (rect.top <= event.clientY) {
392
+ target = child;
393
+ top = rect.top;
394
+ }
395
+ }
396
+ if (!target || top === null) {
397
+ resetGutter();
398
+ return;
399
+ }
400
+ hoverBlockRef.current = target;
401
+ const wrapperTop = wrapper.getBoundingClientRect().top;
402
+ const next = Math.max(Math.round(top - wrapperTop), editorTop + 4);
403
+ setGutterTop((current) => current === next ? current : next);
404
+ };
405
+ const handleBlockMenuOpenChange = (open) => {
406
+ const view = currentView();
407
+ if (open) {
408
+ const block = hoverBlockRef.current;
409
+ blockTargetPosRef.current = view && block && view.dom.contains(block) ? view.posAtDOM(block, 0) : null;
410
+ } else if (view && document.activeElement?.closest('[role="menu"]')) {
411
+ view.focus();
412
+ }
413
+ setBlockMenuOpen(open);
414
+ };
415
+ const openBlockMenuAtCaret = () => {
416
+ const view = currentView();
417
+ const wrapper = gutterWrapperRef.current;
418
+ if (view && wrapper) {
419
+ const { from } = view.state.selection;
420
+ blockTargetPosRef.current = from;
421
+ try {
422
+ const coords = view.coordsAtPos(from);
423
+ const wrapperTop = wrapper.getBoundingClientRect().top;
424
+ setGutterTop(
425
+ Math.max(Math.round(coords.top - wrapperTop), editorTop + 4)
426
+ );
427
+ } catch {
428
+ }
429
+ }
430
+ setBlockMenuOpen(true);
431
+ };
432
+ const applyBlockTarget = (view) => {
433
+ const pos = blockTargetPosRef.current;
434
+ if (pos === null) return;
435
+ const clamped = Math.min(pos, view.state.doc.content.size);
436
+ view.dispatch(
437
+ view.state.tr.setSelection(
438
+ prosemirrorState.TextSelection.near(view.state.doc.resolve(clamped))
439
+ )
440
+ );
441
+ };
442
+ const applyBlockFormat = (command) => {
443
+ const editor = editorRef.current;
444
+ if (inert || !editor) return;
445
+ setBlockMenuOpen(false);
446
+ const view = viewOf(editor);
447
+ view.focus();
448
+ applyBlockTarget(view);
449
+ editor.run[command]?.();
450
+ };
451
+ React2__namespace.useEffect(() => {
452
+ if (!blockMenuOpen) return;
453
+ const frame = requestAnimationFrame(
454
+ () => firstBlockItemRef.current?.focus()
455
+ );
456
+ return () => cancelAnimationFrame(frame);
457
+ }, [blockMenuOpen]);
458
+ const toggleDictation = React2__namespace.useRef(async () => {
459
+ const SpeechRecognition = getSpeechRecognition();
460
+ if (!SpeechRecognition) return;
461
+ if (isListeningRef.current || recognitionRef.current) {
462
+ stopDictation();
463
+ return;
464
+ }
465
+ const session = ++dictationSessionRef.current;
466
+ try {
467
+ const stream = await navigator.mediaDevices.getUserMedia({
468
+ audio: true
469
+ });
470
+ stream.getTracks().forEach((track) => track.stop());
471
+ } catch {
472
+ reportError(
473
+ "Microphone access is required for dictation. Please allow microphone access in your browser settings and try again."
474
+ );
475
+ return;
476
+ }
477
+ if (session !== dictationSessionRef.current) return;
478
+ if (!toolbarVisibleRef.current || inertRef.current) return;
479
+ const recognition = new SpeechRecognition();
480
+ recognition.continuous = true;
481
+ recognition.interimResults = true;
482
+ recognition.lang = "en-US";
483
+ recognition.maxAlternatives = 1;
484
+ recognition.onstart = () => {
485
+ if (session !== dictationSessionRef.current) {
486
+ try {
487
+ recognition.stop();
488
+ } catch {
489
+ }
490
+ return;
491
+ }
492
+ setIsListening(true);
493
+ isListeningRef.current = true;
494
+ shouldRestartRef.current = true;
495
+ };
496
+ recognition.onresult = (event) => {
497
+ if (session !== dictationSessionRef.current || recognitionRef.current !== recognition) {
498
+ return;
499
+ }
500
+ if (inertRef.current) return;
501
+ let finalTranscript = "";
502
+ for (let i = event.resultIndex; i < event.results.length; i++) {
503
+ const result = event.results[i];
504
+ if (result.isFinal) finalTranscript += result[0].transcript;
505
+ }
506
+ const view = currentView();
507
+ if (finalTranscript && view) {
508
+ view.focus();
509
+ insertPlainText(view, chunkS2CJ57BX_cjs.processDictation(finalTranscript) + " ");
510
+ }
511
+ };
512
+ recognition.onerror = (event) => {
513
+ if (session !== dictationSessionRef.current || recognitionRef.current !== recognition) {
514
+ return;
515
+ }
516
+ if (event.error === "no-speech" || event.error === "aborted") return;
517
+ if (event.error === "not-allowed") {
518
+ reportError(
519
+ "Microphone access was denied. Please allow microphone access in your browser settings and try again."
520
+ );
521
+ shouldRestartRef.current = false;
522
+ isListeningRef.current = false;
523
+ setIsListening(false);
524
+ return;
525
+ }
526
+ if (event.error === "network") return;
527
+ shouldRestartRef.current = false;
528
+ isListeningRef.current = false;
529
+ setIsListening(false);
530
+ };
531
+ recognition.onend = () => {
532
+ if (session === dictationSessionRef.current && shouldRestartRef.current && isListeningRef.current && !inertRef.current) {
533
+ setTimeout(() => {
534
+ if (session === dictationSessionRef.current && shouldRestartRef.current && isListeningRef.current && !inertRef.current) {
535
+ try {
536
+ recognition.start();
537
+ } catch {
538
+ shouldRestartRef.current = false;
539
+ isListeningRef.current = false;
540
+ if (recognitionRef.current === recognition)
541
+ recognitionRef.current = null;
542
+ setIsListening(false);
543
+ }
544
+ }
545
+ }, 100);
546
+ } else {
547
+ if (recognitionRef.current === recognition)
548
+ recognitionRef.current = null;
549
+ if (session === dictationSessionRef.current) setIsListening(false);
550
+ }
551
+ };
552
+ recognitionRef.current = recognition;
553
+ try {
554
+ recognition.start();
555
+ } catch {
556
+ recognitionRef.current = null;
557
+ reportError("Failed to start speech recognition. Please try again.");
558
+ }
559
+ }).current;
560
+ const stopDictation = React2__namespace.useCallback(() => {
561
+ dictationSessionRef.current += 1;
562
+ shouldRestartRef.current = false;
563
+ isListeningRef.current = false;
564
+ const recognition = recognitionRef.current;
565
+ recognitionRef.current = null;
566
+ try {
567
+ recognition?.stop();
568
+ } catch {
569
+ }
570
+ setIsListening(false);
571
+ }, []);
572
+ React2__namespace.useEffect(() => {
573
+ setSpeechSupported(Boolean(getSpeechRecognition()));
574
+ }, []);
575
+ React2__namespace.useEffect(() => {
576
+ if (!toolbarVisible || inert || !enableDictation) stopDictation();
577
+ }, [toolbarVisible, inert, enableDictation, stopDictation]);
578
+ React2__namespace.useEffect(() => stopDictation, [stopDictation]);
579
+ const openBlockMenuAtCaretRef = React2__namespace.useRef(openBlockMenuAtCaret);
580
+ openBlockMenuAtCaretRef.current = openBlockMenuAtCaret;
581
+ const expandTypedShortcutRef = React2__namespace.useRef(expandTypedShortcut);
582
+ expandTypedShortcutRef.current = expandTypedShortcut;
583
+ const [menuAddon] = React2__namespace.useState(() => {
584
+ const macrosItem = new extensionMenu.MenuItem({
585
+ icon: {
586
+ width: 24,
587
+ height: 24,
588
+ // Material Symbols "text snippet" (Apache-2.0)
589
+ path: "M20.41 8.41l-4.83-4.83c-.37-.37-.88-.58-1.41-.58H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V9.83c0-.53-.21-1.04-.59-1.42zM7 7h7v2H7V7zm10 10H7v-2h10v2zm0-4H7v-2h10v2z"
590
+ },
591
+ title: macroLabels?.showMacros ?? "Show macros",
592
+ class: "tar-menu-macros",
593
+ select: () => hasMacrosRef.current,
594
+ enable: () => !inertRef.current,
595
+ active: () => macrosOpenRef.current,
596
+ run: () => {
597
+ setMacrosOpen((open) => !open);
598
+ return true;
599
+ }
600
+ });
601
+ const dictateItem = new extensionMenu.MenuItem({
602
+ icon: {
603
+ width: 24,
604
+ height: 24,
605
+ // Material Symbols "mic" (Apache-2.0)
606
+ path: "M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z"
607
+ },
608
+ title: m("Start dictation"),
609
+ class: "tar-menu-dictate",
610
+ select: () => dictationAvailableRef.current,
611
+ enable: () => !inertRef.current,
612
+ active: () => isListeningRef.current,
613
+ run: () => {
614
+ void toggleDictation();
615
+ return true;
616
+ }
617
+ });
618
+ const modifyMenu = (menus) => [
619
+ ...menus,
620
+ // The patched MenuItem types `render().dom` as nullable, which no
621
+ // longer satisfies MenuElement; our items always render a button.
622
+ [macrosItem, dictateItem]
623
+ ];
624
+ const kit = {
625
+ getExtensions: () => [
626
+ new TextAreaRichExtension((view, event) => {
627
+ if (inertRef.current) return false;
628
+ if (event.key === "/" && (event.ctrlKey || event.metaKey) && !event.altKey) {
629
+ openBlockMenuAtCaretRef.current();
630
+ return true;
631
+ }
632
+ if (event.key !== " " || event.isComposing || event.ctrlKey || event.metaKey || event.altKey) {
633
+ return false;
634
+ }
635
+ return expandTypedShortcutRef.current(view);
636
+ })
637
+ ]
638
+ };
639
+ return { modifyMenu, kits: [kit] };
640
+ });
641
+ React2__namespace.useEffect(() => {
642
+ const root = wrapperRef.current;
643
+ if (!root || !ready) return;
644
+ const sync = () => {
645
+ for (const toolbar2 of root.querySelectorAll(
646
+ ".kb-custom-menu, .kb-custom-menu__overflow-menu"
647
+ )) {
648
+ toolbar2.inert = inert;
649
+ }
650
+ for (const macrosButton of root.querySelectorAll(
651
+ ".tar-menu-macros"
652
+ )) {
653
+ macrosButton.style.display = hasMacros ? "" : "none";
654
+ macrosButton.classList.toggle("kb-menu__button--disabled", inert);
655
+ macrosButton.setAttribute("aria-disabled", String(inert));
656
+ macrosButton.classList.toggle("kb-menu__button--active", macrosOpen);
657
+ macrosButton.setAttribute("aria-pressed", String(macrosOpen));
658
+ const title = macrosOpen ? macroLabels?.hideMacros ?? "Hide macros" : macroLabels?.showMacros ?? "Show macros";
659
+ macrosButton.setAttribute("title", title);
660
+ macrosButton.setAttribute("aria-label", title);
661
+ }
662
+ for (const dictateButton of root.querySelectorAll(
663
+ ".tar-menu-dictate"
664
+ )) {
665
+ dictateButton.style.display = enableDictation && speechSupported ? "" : "none";
666
+ dictateButton.classList.toggle("kb-menu__button--disabled", inert);
667
+ dictateButton.setAttribute("aria-disabled", String(inert));
668
+ dictateButton.classList.toggle(
669
+ "kb-menu__button--active",
670
+ isListening
671
+ );
672
+ dictateButton.setAttribute("aria-pressed", String(isListening));
673
+ const title = isListening ? m("Stop dictation") : m("Start dictation");
674
+ dictateButton.setAttribute("title", title);
675
+ dictateButton.setAttribute("aria-label", title);
676
+ }
677
+ };
678
+ sync();
679
+ const observer = new MutationObserver((mutations) => {
680
+ if (mutations.some((mutation) => mutation.addedNodes.length > 0)) {
681
+ sync();
682
+ }
683
+ });
684
+ observer.observe(root, { childList: true, subtree: true });
685
+ return () => observer.disconnect();
686
+ }, [
687
+ ready,
688
+ inert,
689
+ hasMacros,
690
+ macrosOpen,
691
+ macroLabels,
692
+ enableDictation,
693
+ speechSupported,
694
+ isListening,
695
+ toolbarVisible,
696
+ m
697
+ ]);
698
+ const handleReady = (editor) => {
699
+ editorRef.current = editor;
700
+ publishedDocRef.current = viewOf(editor).state.doc;
701
+ setIsEmpty(docIsEmpty(viewOf(editor)));
702
+ editor.addEventListener("transaction", () => {
703
+ if (editorRef.current !== editor) return;
704
+ setIsEmpty(docIsEmpty(viewOf(editor)));
705
+ });
706
+ setReady(true);
707
+ };
708
+ React2__namespace.useEffect(() => {
709
+ const view = currentView();
710
+ if (!view || !ready) return;
711
+ view.setProps({
712
+ attributes: {
713
+ role: "textbox",
714
+ "aria-multiline": "true",
715
+ ...id ? { id } : {},
716
+ ...ariaLabel ?? placeholder ? { "aria-label": ariaLabel ?? placeholder } : {},
717
+ ...ariaLabelledBy ? { "aria-labelledby": ariaLabelledBy } : {},
718
+ ...ariaDescribedBy ? { "aria-describedby": ariaDescribedBy } : {},
719
+ ...ariaInvalid ? { "aria-invalid": String(ariaInvalid) } : {},
720
+ // Booleanish: the string "false" must not read as required.
721
+ ...ariaRequired !== void 0 ? { "aria-required": String(ariaRequired) } : {},
722
+ ...readOnly ? { "aria-readonly": "true" } : {},
723
+ ...disabled ? { "aria-disabled": "true" } : {},
724
+ // Read-only keeps keyboard focus and text selection available;
725
+ // ProseMirror drops natural tabbability once `editable` is false.
726
+ tabindex: disabled ? "-1" : "0",
727
+ // setProps replaces the create-time attributes, so the base
728
+ // kb-editor class must be restated alongside any custom class.
729
+ class: editorClassName ? `kb-editor ${editorClassName}` : "kb-editor"
730
+ }
731
+ });
732
+ }, [
733
+ ready,
734
+ id,
735
+ ariaLabel,
736
+ placeholder,
737
+ ariaLabelledBy,
738
+ ariaDescribedBy,
739
+ ariaInvalid,
740
+ ariaRequired,
741
+ readOnly,
742
+ disabled,
743
+ editorClassName
744
+ ]);
745
+ const appliedEditorStyle = React2__namespace.useRef([]);
746
+ React2__namespace.useEffect(() => {
747
+ const view = currentView();
748
+ const wrapper = wrapperRef.current;
749
+ if (!view || !wrapper || !ready) return;
750
+ const editableStyle = view.dom.style;
751
+ for (const [style, property] of appliedEditorStyle.current) {
752
+ style.removeProperty(property);
753
+ }
754
+ appliedEditorStyle.current = [];
755
+ if (!editorStyle) return;
756
+ for (const [key, raw] of Object.entries(editorStyle)) {
757
+ if (raw === null || raw === void 0) continue;
758
+ const isCustomProperty = key.startsWith("--");
759
+ const property = isCustomProperty ? key : key.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
760
+ const value2 = typeof raw === "number" && !isCustomProperty && !UNITLESS_STYLE_PROPS.has(key) ? `${raw}px` : String(raw);
761
+ const style = isCustomProperty ? wrapper.style : editableStyle;
762
+ style.setProperty(property, value2);
763
+ appliedEditorStyle.current.push([style, property]);
764
+ }
765
+ }, [ready, editorStyle]);
766
+ React2__namespace.useEffect(() => {
767
+ const view = currentView();
768
+ const wrapper = gutterWrapperRef.current;
769
+ if (!view || !wrapper || !ready) return;
770
+ const measure = () => {
771
+ const top = Math.max(
772
+ Math.round(
773
+ view.dom.getBoundingClientRect().top - wrapper.getBoundingClientRect().top
774
+ ),
775
+ 0
776
+ );
777
+ setEditorTop((current) => current === top ? current : top);
778
+ const hovered = hoverBlockRef.current;
779
+ if (hovered?.isConnected) {
780
+ const next = Math.max(
781
+ Math.round(
782
+ hovered.getBoundingClientRect().top - wrapper.getBoundingClientRect().top
783
+ ),
784
+ top + 4
785
+ );
786
+ setGutterTop((current) => current === next ? current : next);
787
+ } else {
788
+ hoverBlockRef.current = null;
789
+ setGutterTop(top + 4);
790
+ }
791
+ };
792
+ measure();
793
+ const observer = new ResizeObserver(measure);
794
+ observer.observe(wrapper);
795
+ return () => observer.disconnect();
796
+ }, [ready, toolbarVisible]);
797
+ return /* @__PURE__ */ jsxRuntime.jsx(
798
+ "div",
799
+ {
800
+ ref: wrapperRef,
801
+ "data-slot": "textarea-rich",
802
+ "data-toolbar": toolbarVisible ? "visible" : "hidden",
803
+ "data-inert": inert ? "" : void 0,
804
+ "data-macros-open": hasMacros && macrosOpen ? "" : void 0,
805
+ "data-compact-macros": compactMacros ? "" : void 0,
806
+ "data-gutter": gutterActive ? "" : void 0,
807
+ "data-block-menu": blockMenuOpen ? "" : void 0,
808
+ className: chunkS5RVSXDV_cjs.cn(
809
+ "border-input rounded-lg border",
810
+ "transition-colors duration-200",
811
+ "focus-within:ring-ring focus-within:border-transparent focus-within:ring-2",
812
+ "flex flex-col",
813
+ disabled && "bg-muted/20",
814
+ className
815
+ ),
816
+ onFocus: hasMacros && macrosOnFocus ? () => setMacrosOpen(true) : void 0,
817
+ onBlur: hasMacros && macrosOnFocus ? (event) => {
818
+ const related = event.relatedTarget;
819
+ if (related && event.currentTarget.contains(related)) return;
820
+ let menu = related?.closest('[role="menu"]');
821
+ while (menu && menu.id) {
822
+ const trigger = document.querySelector(
823
+ `[aria-controls="${globalThis.CSS.escape(menu.id)}"]`
824
+ );
825
+ if (!trigger) break;
826
+ if (event.currentTarget.contains(trigger)) return;
827
+ menu = trigger.closest('[role="menu"]');
828
+ }
829
+ setMacrosOpen(false);
830
+ } : void 0,
831
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex min-h-0 flex-1 flex-col", children: [
832
+ /* @__PURE__ */ jsxRuntime.jsxs(
833
+ "div",
834
+ {
835
+ ref: gutterWrapperRef,
836
+ "data-slot": "textarea-rich-body",
837
+ className: chunkS5RVSXDV_cjs.cn("relative flex-1", "group/tar-body"),
838
+ onMouseMove: gutterActive ? handleGutterMouseMove : void 0,
839
+ children: [
840
+ gutterActive && // eslint-disable-next-line jsx-a11y/no-static-element-interactions -- mousedown here only guards editor focus (preventDefault); the real controls inside are native buttons.
841
+ /* @__PURE__ */ jsxRuntime.jsx(
842
+ "div",
843
+ {
844
+ "data-slot": "textarea-rich-block-gutter",
845
+ className: "absolute start-1 z-10",
846
+ style: { top: gutterTop },
847
+ onMouseDown: (event) => event.preventDefault(),
848
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
849
+ chunkPINIBEIU_cjs.Dropdown,
850
+ {
851
+ open: blockMenuOpen,
852
+ onOpenChange: handleBlockMenuOpenChange,
853
+ placement: "bottom-start",
854
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(
855
+ chunkFSARTLUE_cjs.Button,
856
+ {
857
+ type: "button",
858
+ variant: "ghost",
859
+ size: "sm",
860
+ className: chunkS5RVSXDV_cjs.cn(
861
+ "h-6 w-6 p-0",
862
+ "opacity-0 transition-opacity",
863
+ "group-hover/tar-body:opacity-100",
864
+ "focus-visible:opacity-100",
865
+ "[@media(hover:none)]:opacity-100",
866
+ blockMenuOpen && "opacity-100"
867
+ ),
868
+ "aria-label": blockMenuLabels?.blockMenu ?? "Block menu",
869
+ title: blockMenuLabels?.blockMenu ?? "Block menu",
870
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4" })
871
+ }
872
+ ),
873
+ children: [
874
+ BLOCK_FORMAT_ITEMS.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
875
+ chunkPINIBEIU_cjs.DropdownItem,
876
+ {
877
+ ref: index === 0 ? firstBlockItemRef : void 0,
878
+ onClick: () => applyBlockFormat(item.command),
879
+ children: blockMenuLabels?.[item.key] ?? item.label
880
+ },
881
+ item.key
882
+ )),
883
+ /* @__PURE__ */ jsxRuntime.jsx(chunkPINIBEIU_cjs.DropdownSeparator, {}),
884
+ hasMacros && macros && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
885
+ /* @__PURE__ */ jsxRuntime.jsx(
886
+ chunkPINIBEIU_cjs.DropdownSubmenu,
887
+ {
888
+ label: blockMenuLabels?.insertMacro ?? "Insert macro",
889
+ disabled: !hasMacroEntries,
890
+ children: blockMenuOpen && macros.flatMap((group) => [
891
+ ...macros.length > 1 ? [
892
+ /* @__PURE__ */ jsxRuntime.jsx(chunkPINIBEIU_cjs.DropdownLabel, { children: group.label }, `h:${group.id}`)
893
+ ] : [],
894
+ ...group.macros.map((macro) => /* @__PURE__ */ jsxRuntime.jsx(
895
+ chunkPINIBEIU_cjs.DropdownItem,
896
+ {
897
+ className: "[&>[data-slot=dropdown-item-label]]:min-w-0 [&>[data-slot=dropdown-item-label]]:flex-1",
898
+ onClick: () => {
899
+ setBlockMenuOpen(false);
900
+ const view = currentView();
901
+ if (view) {
902
+ view.focus();
903
+ applyBlockTarget(view);
904
+ }
905
+ insertMacro(macro);
906
+ },
907
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-2", children: [
908
+ macro.shortcut && /* @__PURE__ */ jsxRuntime.jsx(
909
+ "span",
910
+ {
911
+ dir: "ltr",
912
+ className: "border-border bg-background text-muted-foreground rounded border px-1 font-mono text-[11px]",
913
+ children: macro.shortcut
914
+ }
915
+ ),
916
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: macro.label })
917
+ ] })
918
+ },
919
+ `m:${JSON.stringify([group.id, macro.id])}`
920
+ ))
921
+ ])
922
+ }
923
+ ),
924
+ /* @__PURE__ */ jsxRuntime.jsx(
925
+ chunkPINIBEIU_cjs.DropdownItem,
926
+ {
927
+ onClick: () => {
928
+ setBlockMenuOpen(false);
929
+ setMacrosOpen(true);
930
+ focusEditor();
931
+ },
932
+ children: blockMenuLabels?.showMacroLibrary ?? "Show macro library"
933
+ }
934
+ ),
935
+ /* @__PURE__ */ jsxRuntime.jsx(chunkPINIBEIU_cjs.DropdownSeparator, {})
936
+ ] }),
937
+ /* @__PURE__ */ jsxRuntime.jsx(
938
+ chunkPINIBEIU_cjs.DropdownItem,
939
+ {
940
+ onClick: () => {
941
+ setBlockMenuOpen(false);
942
+ setToolbarVisibility(
943
+ toolbarVisible ? "hidden" : "visible"
944
+ );
945
+ focusEditor();
946
+ },
947
+ children: toolbarVisible ? blockMenuLabels?.hideToolbar ?? "Hide toolbar" : blockMenuLabels?.showToolbar ?? "Show toolbar"
948
+ }
949
+ )
950
+ ]
951
+ }
952
+ )
953
+ }
954
+ ),
955
+ isEmpty && placeholder && /* @__PURE__ */ jsxRuntime.jsx(
956
+ "div",
957
+ {
958
+ "aria-hidden": "true",
959
+ className: chunkS5RVSXDV_cjs.cn(
960
+ "text-muted-foreground pointer-events-none absolute start-0 end-0 z-[1]",
961
+ "truncate px-3 py-[7px]",
962
+ "transition-[padding] duration-200 motion-reduce:transition-none",
963
+ // Mirrors the editable's sliding gutter indent (permanent
964
+ // on touch devices, where the + trigger is always visible).
965
+ gutterActive && "group-focus-within/tar-body:ps-10 group-hover/tar-body:ps-10 [@media(hover:none)]:ps-10",
966
+ gutterActive && blockMenuOpen && "ps-10",
967
+ hasMacros && macrosOpen && "md:me-72",
968
+ editorClassName
969
+ ),
970
+ style: {
971
+ top: editorTop,
972
+ // Match the editable's metrics by construction: the same
973
+ // variables (inherited from the wrapper) with the same
974
+ // kerebron.css fallbacks that size the .kb-editor rule.
975
+ fontSize: "var(--textarea-rich-font-size, 1rem)",
976
+ lineHeight: "var(--textarea-rich-line-height, 1.5rem)"
977
+ },
978
+ children: placeholder
979
+ }
980
+ ),
981
+ /* @__PURE__ */ jsxRuntime.jsx(
982
+ chunkNCG7NJAW_cjs.RichEditor,
983
+ {
984
+ ref: editorHandleRef,
985
+ value,
986
+ onChange: handleChange,
987
+ valueType: "text/html",
988
+ strictValue: true,
989
+ modifyMenu: menuAddon.modifyMenu,
990
+ editorKits: menuAddon.kits,
991
+ onReady: handleReady,
992
+ disabled,
993
+ readOnly
994
+ }
995
+ )
996
+ ]
997
+ }
998
+ ),
999
+ hasMacros && /* @__PURE__ */ jsxRuntime.jsx(chunkIEY3ZJIT_cjs.AnimatedPresence, { children: macrosOpen && /* @__PURE__ */ jsxRuntime.jsx(
1000
+ chunkIEY3ZJIT_cjs.Animated,
1001
+ {
1002
+ preset: macroSidePanel ? "menu" : "collapse",
1003
+ enabled: macroSidePanel || !prefersReducedMotion,
1004
+ mode: "presence",
1005
+ custom: direction === "rtl" ? "left" : "right",
1006
+ fallbackClassName: "animate-fade-in",
1007
+ className: "border-border flex max-h-72 flex-col overflow-hidden border-t md:absolute md:end-0 md:bottom-0 md:max-h-none md:w-72 md:overflow-visible md:border-s md:border-t-0",
1008
+ style: { top: editorTop },
1009
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1010
+ chunkS2CJ57BX_cjs.MacroLibrary,
1011
+ {
1012
+ id: macroPanelId,
1013
+ groups: macros,
1014
+ onSelect: insertMacro,
1015
+ targetLabel: ariaLabel ?? placeholder,
1016
+ onClose: macrosOnFocus ? void 0 : () => {
1017
+ setMacrosOpen(false);
1018
+ focusEditor();
1019
+ },
1020
+ onCreateMacro,
1021
+ labels: macroLabels,
1022
+ compact: compactMacros,
1023
+ className: "min-h-0 flex-1"
1024
+ }
1025
+ )
1026
+ },
1027
+ "macro-panel"
1028
+ ) })
1029
+ ] })
1030
+ }
1031
+ );
1032
+ }
1033
+ );
1034
+ TextAreaRichKerebron.displayName = "TextAreaRichKerebron";
1035
+
1036
+ exports.CodeEditor = CodeEditor;
1037
+ exports.TextAreaRichKerebron = TextAreaRichKerebron;
1038
+ //# sourceMappingURL=chunk-RCTIPBLU.cjs.map
1039
+ //# sourceMappingURL=chunk-RCTIPBLU.cjs.map