@powerduck/schema-designer 0.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 (102) hide show
  1. package/README.md +217 -0
  2. package/dist/InlineSchemaEditor-BssSx3SI.d.ts +6 -0
  3. package/dist/InlineSchemaEditor-Bua-lDhE.d.cts +6 -0
  4. package/dist/chunk-2XUQB6BQ.js +1896 -0
  5. package/dist/chunk-4H3LXOL4.cjs +1900 -0
  6. package/dist/chunk-7LG4MVMD.cjs +2 -0
  7. package/dist/chunk-BXFABOMJ.js +1475 -0
  8. package/dist/chunk-FTALJIVZ.js +1 -0
  9. package/dist/chunk-GTZH37JS.cjs +1120 -0
  10. package/dist/chunk-GWHDTTQK.js +1437 -0
  11. package/dist/chunk-GXXD6ITE.cjs +1477 -0
  12. package/dist/chunk-HI5FBHCO.js +1057 -0
  13. package/dist/chunk-KX3LFFOV.js +88 -0
  14. package/dist/chunk-MADPN2PJ.js +185 -0
  15. package/dist/chunk-NOUORNCI.cjs +1452 -0
  16. package/dist/chunk-O6PTRJQ5.js +1195 -0
  17. package/dist/chunk-OBHJC3I2.cjs +2 -0
  18. package/dist/chunk-OOSNM45O.cjs +264 -0
  19. package/dist/chunk-P5B3HSPY.js +244 -0
  20. package/dist/chunk-PBE36BVA.js +1 -0
  21. package/dist/chunk-PVEYKCM6.js +1 -0
  22. package/dist/chunk-QZADGAP3.cjs +1218 -0
  23. package/dist/chunk-S7GNTGEE.js +1 -0
  24. package/dist/chunk-SMBDRWV2.cjs +2 -0
  25. package/dist/chunk-THYDOHOP.cjs +2 -0
  26. package/dist/chunk-WRHWOMZQ.cjs +190 -0
  27. package/dist/chunk-YNKP5JJA.cjs +32 -0
  28. package/dist/chunk-YWDKCX6N.cjs +91 -0
  29. package/dist/chunk-ZHNYNFGL.js +28 -0
  30. package/dist/compat/inline.cjs +137 -0
  31. package/dist/compat/inline.css +275 -0
  32. package/dist/compat/inline.d.cts +6 -0
  33. package/dist/compat/inline.d.ts +6 -0
  34. package/dist/compat/inline.js +4 -0
  35. package/dist/compat/parameters.cjs +90 -0
  36. package/dist/compat/parameters.css +997 -0
  37. package/dist/compat/parameters.d.cts +70 -0
  38. package/dist/compat/parameters.d.ts +70 -0
  39. package/dist/compat/parameters.js +9 -0
  40. package/dist/compat/tree.cjs +142 -0
  41. package/dist/compat/tree.css +1069 -0
  42. package/dist/compat/tree.d.cts +4 -0
  43. package/dist/compat/tree.d.ts +4 -0
  44. package/dist/compat/tree.js +5 -0
  45. package/dist/compat/variable-editor.cjs +82 -0
  46. package/dist/compat/variable-editor.d.cts +68 -0
  47. package/dist/compat/variable-editor.d.ts +68 -0
  48. package/dist/compat/variable-editor.js +1 -0
  49. package/dist/core/index.cjs +197 -0
  50. package/dist/core/index.d.cts +21 -0
  51. package/dist/core/index.d.ts +21 -0
  52. package/dist/core/index.js +4 -0
  53. package/dist/index.cjs +35 -0
  54. package/dist/index.css +1791 -0
  55. package/dist/index.d.cts +9 -0
  56. package/dist/index.d.ts +9 -0
  57. package/dist/index.js +10 -0
  58. package/dist/parameterValue-2pL9n-3q.d.ts +8 -0
  59. package/dist/parameterValue-Cky9Lnd3.d.cts +8 -0
  60. package/dist/react/index.cjs +35 -0
  61. package/dist/react/index.css +1791 -0
  62. package/dist/react/index.d.cts +9 -0
  63. package/dist/react/index.d.ts +9 -0
  64. package/dist/react/index.js +10 -0
  65. package/dist/react/inlineSchemaEditor/index.cjs +97 -0
  66. package/dist/react/inlineSchemaEditor/index.css +275 -0
  67. package/dist/react/inlineSchemaEditor/index.d.cts +6 -0
  68. package/dist/react/inlineSchemaEditor/index.d.ts +6 -0
  69. package/dist/react/inlineSchemaEditor/index.js +4 -0
  70. package/dist/react/parametersTable/index.cjs +22 -0
  71. package/dist/react/parametersTable/index.css +997 -0
  72. package/dist/react/parametersTable/index.d.cts +7 -0
  73. package/dist/react/parametersTable/index.d.ts +7 -0
  74. package/dist/react/parametersTable/index.js +9 -0
  75. package/dist/react/parametersTable/libs/generateValue.cjs +558 -0
  76. package/dist/react/parametersTable/libs/generateValue.d.cts +17 -0
  77. package/dist/react/parametersTable/libs/generateValue.d.ts +17 -0
  78. package/dist/react/parametersTable/libs/generateValue.js +551 -0
  79. package/dist/react/schemaTreeEditor/index.cjs +18 -0
  80. package/dist/react/schemaTreeEditor/index.css +1069 -0
  81. package/dist/react/schemaTreeEditor/index.d.cts +7 -0
  82. package/dist/react/schemaTreeEditor/index.d.ts +7 -0
  83. package/dist/react/schemaTreeEditor/index.js +5 -0
  84. package/dist/react/variableTextEditor/index.cjs +11 -0
  85. package/dist/react/variableTextEditor/index.css +306 -0
  86. package/dist/react/variableTextEditor/index.d.cts +6 -0
  87. package/dist/react/variableTextEditor/index.d.ts +6 -0
  88. package/dist/react/variableTextEditor/index.js +2 -0
  89. package/dist/schema-CKAPsYeW.d.cts +41 -0
  90. package/dist/schema-o7OJRaJ8.d.ts +41 -0
  91. package/dist/styles.css +1791 -0
  92. package/dist/tree-D06Xa6_N.d.ts +95 -0
  93. package/dist/tree-Dq1Rk-CF.d.cts +95 -0
  94. package/dist/types-B27Dw9do.d.cts +163 -0
  95. package/dist/types-B27Dw9do.d.ts +163 -0
  96. package/dist/types-Bk9rzr6l.d.cts +48 -0
  97. package/dist/types-D2jEaM9Z.d.cts +145 -0
  98. package/dist/types-D2jEaM9Z.d.ts +145 -0
  99. package/dist/types-xAihO_KW.d.ts +48 -0
  100. package/dist/variableTextEditor.types-ClzvARvK.d.cts +49 -0
  101. package/dist/variableTextEditor.types-ClzvARvK.d.ts +49 -0
  102. package/package.json +130 -0
@@ -0,0 +1,1477 @@
1
+ 'use strict';
2
+
3
+ var chunkOOSNM45O_cjs = require('./chunk-OOSNM45O.cjs');
4
+ var react = require('react');
5
+ var react$1 = require('@chakra-ui/react');
6
+ var autocomplete = require('@codemirror/autocomplete');
7
+ var commands = require('@codemirror/commands');
8
+ var state = require('@codemirror/state');
9
+ var view = require('@codemirror/view');
10
+ var jsxRuntime = require('react/jsx-runtime');
11
+
12
+ // src/react/variableTextEditor/VariableTextEditor.module.css
13
+ var VariableTextEditor_default = {
14
+ root: "VariableTextEditor_root",
15
+ variableToken: "VariableTextEditor_variableToken",
16
+ variableToken_unknown: "VariableTextEditor_variableToken_unknown",
17
+ variableToken_environment: "VariableTextEditor_variableToken_environment",
18
+ variableToken_secret: "VariableTextEditor_variableToken_secret",
19
+ variableToken_request: "VariableTextEditor_variableToken_request",
20
+ variableToken_dynamic: "VariableTextEditor_variableToken_dynamic",
21
+ hoverPopover: "VariableTextEditor_hoverPopover",
22
+ hoverPopoverArrow: "VariableTextEditor_hoverPopoverArrow",
23
+ popoverHeader: "VariableTextEditor_popoverHeader",
24
+ popoverType: "VariableTextEditor_popoverType",
25
+ popoverValue: "VariableTextEditor_popoverValue",
26
+ popoverDesc: "VariableTextEditor_popoverDesc"
27
+ };
28
+ var EMPTY_VARIABLES = Object.freeze([]);
29
+ var TOKEN_SELECTOR = `.${VariableTextEditor_default.variableToken}`;
30
+ var HOVER_OPEN_DELAY = 260;
31
+ var HOVER_CLOSE_DELAY = 50;
32
+ var POPOVER_GAP = 14;
33
+ var VIEWPORT_MARGIN = 12;
34
+ var POPOVER_MAX_WIDTH = 360;
35
+ var POPOVER_FALLBACK_HEIGHT = 200;
36
+ var MAX_PENDING_CONTROLLED_VALUES = 16;
37
+ var ExternalValueUpdate = state.Annotation.define();
38
+ var VariablesSnapshotUpdate = state.Annotation.define();
39
+ function variablesEqual(a, b) {
40
+ if (a === b) return true;
41
+ if (a.length !== b.length) return false;
42
+ for (let i = 0; i < a.length; i += 1) {
43
+ const left = a[i];
44
+ const right = b[i];
45
+ if (left.name !== right.name || left.value !== right.value || left.description !== right.description || left.type !== right.type || left.color !== right.color || left.backgroundColor !== right.backgroundColor) {
46
+ return false;
47
+ }
48
+ }
49
+ return true;
50
+ }
51
+ function mergeRanges(ranges) {
52
+ if (ranges.length <= 1) return ranges.slice();
53
+ const sorted = ranges.filter((range) => range.to > range.from).slice().sort((a, b) => {
54
+ if (a.from !== b.from) return a.from - b.from;
55
+ return a.to - b.to;
56
+ });
57
+ if (sorted.length <= 1) return sorted;
58
+ const result = [];
59
+ let current = {
60
+ from: sorted[0].from,
61
+ to: sorted[0].to
62
+ };
63
+ for (let i = 1; i < sorted.length; i += 1) {
64
+ const next = sorted[i];
65
+ if (next.from <= current.to) {
66
+ current.to = Math.max(current.to, next.to);
67
+ continue;
68
+ }
69
+ result.push(current);
70
+ current = {
71
+ from: next.from,
72
+ to: next.to
73
+ };
74
+ }
75
+ result.push(current);
76
+ return result;
77
+ }
78
+ function createInputInvariantFilter(maxLengthRef, allowLineBreaksRef, isComposingRef) {
79
+ return state.EditorState.transactionFilter.of((transaction) => {
80
+ if (!transaction.docChanged) {
81
+ return transaction;
82
+ }
83
+ if (isComposingRef.current) {
84
+ return transaction;
85
+ }
86
+ const newDoc = transaction.newDoc;
87
+ const invalidRanges = [];
88
+ if (!allowLineBreaksRef.current) {
89
+ const text = newDoc.toString();
90
+ const newlineRegex = /[\r\n\u2028\u2029]+/g;
91
+ let match;
92
+ while ((match = newlineRegex.exec(text)) !== null) {
93
+ const from = match.index;
94
+ const to = from + match[0].length;
95
+ invalidRanges.push({ from, to });
96
+ }
97
+ }
98
+ const limit = maxLengthRef.current;
99
+ if (Number.isFinite(limit) && newDoc.length > limit) {
100
+ invalidRanges.push({
101
+ from: Math.max(0, Math.floor(limit)),
102
+ to: newDoc.length
103
+ });
104
+ }
105
+ if (invalidRanges.length === 0) {
106
+ return transaction;
107
+ }
108
+ const merged = mergeRanges(invalidRanges);
109
+ return [
110
+ transaction,
111
+ {
112
+ changes: merged.map(({ from, to }) => ({
113
+ from,
114
+ to,
115
+ insert: ""
116
+ })),
117
+ sequential: true
118
+ }
119
+ ];
120
+ });
121
+ }
122
+ var VariableDecorationPlugin = class {
123
+ constructor(view, getSnapshot, tokenIndexRef, classes) {
124
+ this.getSnapshot = getSnapshot;
125
+ this.tokenIndexRef = tokenIndexRef;
126
+ this.classes = classes;
127
+ this.rebuild(view.state);
128
+ }
129
+ getSnapshot;
130
+ tokenIndexRef;
131
+ classes;
132
+ decorations = view.Decoration.none;
133
+ rebuild(state) {
134
+ const snapshot = this.getSnapshot();
135
+ const doc = state.doc.toString();
136
+ const tokens = chunkOOSNM45O_cjs.findVariableTokens(doc, snapshot.variables);
137
+ this.tokenIndexRef.current = {
138
+ doc,
139
+ variablesVersion: snapshot.version,
140
+ tokens
141
+ };
142
+ this.decorations = chunkOOSNM45O_cjs.createTokenDecorations(
143
+ state,
144
+ snapshot.variables,
145
+ this.classes,
146
+ tokens
147
+ );
148
+ }
149
+ update(update) {
150
+ if (update.docChanged || update.transactions.some(
151
+ (transaction) => transaction.annotation(VariablesSnapshotUpdate) !== void 0
152
+ ))
153
+ this.rebuild(update.state);
154
+ }
155
+ };
156
+ function createVariableDecorationExtension(snapshotRef, tokenIndexRef) {
157
+ const getSnapshot = () => snapshotRef.current;
158
+ const plugin = view.ViewPlugin.fromClass(
159
+ class extends VariableDecorationPlugin {
160
+ constructor(view) {
161
+ super(view, getSnapshot, tokenIndexRef, VariableTextEditor_default);
162
+ }
163
+ },
164
+ {
165
+ decorations: (plugin2) => plugin2.decorations
166
+ }
167
+ );
168
+ return plugin;
169
+ }
170
+ function createVariableCompletionExtension(variables) {
171
+ return autocomplete.autocompletion({
172
+ override: [chunkOOSNM45O_cjs.createVariableCompletionSource(variables)],
173
+ activateOnTyping: true,
174
+ defaultKeymap: false
175
+ });
176
+ }
177
+ var VariableTextEditor = react.memo(
178
+ (props) => {
179
+ const {
180
+ value,
181
+ variables: variablesProp,
182
+ disabled = false,
183
+ readOnly = false,
184
+ placeholder = "",
185
+ ariaLabel = "Variable text editor",
186
+ className,
187
+ autoFocus = false,
188
+ submitOnEnter = false,
189
+ minHeight = 32,
190
+ expansionMode = "inline",
191
+ safePadding = 8,
192
+ maxFocusedHeight = 320,
193
+ maxLength,
194
+ allowLineBreaks = false,
195
+ onChange,
196
+ onSubmit,
197
+ onFocus,
198
+ onBlur
199
+ } = props;
200
+ const variables = variablesProp ?? EMPTY_VARIABLES;
201
+ const safeMaxLength = chunkOOSNM45O_cjs.normalizeMaximumLength(maxLength);
202
+ const normalizedValue = chunkOOSNM45O_cjs.sanitizePlainText(
203
+ value,
204
+ safeMaxLength,
205
+ allowLineBreaks
206
+ );
207
+ const safeMinHeight = Number.isFinite(minHeight) ? Math.max(32, Math.round(minHeight)) : 32;
208
+ const safeMaxHeight = Number.isFinite(maxFocusedHeight) ? Math.max(safeMinHeight, Math.round(maxFocusedHeight)) : Math.max(safeMinHeight, 320);
209
+ const hostRef = react.useRef(null);
210
+ const tooltipRef = react.useRef(null);
211
+ const viewRef = react.useRef(null);
212
+ const destroyedRef = react.useRef(false);
213
+ const isComposingRef = react.useRef(false);
214
+ const pendingCompositionSyncRef = react.useRef(false);
215
+ const initialValueRef = react.useRef(normalizedValue);
216
+ const editorValueRef = react.useRef(normalizedValue);
217
+ const lastAcknowledgedPropValueRef = react.useRef(normalizedValue);
218
+ const pendingEmittedValuesRef = react.useRef([]);
219
+ const [hover, setHover] = react.useState(null);
220
+ const hoverRef = react.useRef(null);
221
+ const [focused, setFocused] = react.useState(false);
222
+ const focusedRef = react.useRef(false);
223
+ const [focusedHeight, setFocusedHeight] = react.useState(safeMinHeight);
224
+ const focusedHeightRef = react.useRef(safeMinHeight);
225
+ const [wrapped, setWrapped] = react.useState(false);
226
+ const wrappedRef = react.useRef(false);
227
+ const anchorRef = react.useRef(null);
228
+ const [overlayStyle, setOverlayStyle] = react.useState();
229
+ react.useLayoutEffect(() => {
230
+ if (!focused || expansionMode !== "overlay") {
231
+ setOverlayStyle(void 0);
232
+ return;
233
+ }
234
+ let frame = 0;
235
+ const position = () => {
236
+ frame = 0;
237
+ const anchor = anchorRef.current;
238
+ if (!anchor) return;
239
+ const rect = anchor.getBoundingClientRect();
240
+ if (rect.bottom <= 0 || rect.top >= window.innerHeight) {
241
+ viewRef.current?.contentDOM.blur();
242
+ return;
243
+ }
244
+ const height = Math.min(focusedHeight, window.innerHeight - 16);
245
+ const top = Math.max(
246
+ 8,
247
+ Math.min(rect.top, window.innerHeight - height - 8)
248
+ );
249
+ setOverlayStyle({
250
+ position: "fixed",
251
+ top,
252
+ left: Math.max(8, rect.left),
253
+ width: Math.min(
254
+ rect.width,
255
+ window.innerWidth - Math.max(8, rect.left) - 8
256
+ ),
257
+ maxHeight: Math.max(safeMinHeight, window.innerHeight - top - 8),
258
+ zIndex: 1100
259
+ });
260
+ };
261
+ const schedule = () => {
262
+ if (!frame) frame = requestAnimationFrame(position);
263
+ };
264
+ position();
265
+ window.addEventListener("scroll", schedule, true);
266
+ window.addEventListener("resize", schedule);
267
+ const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(schedule);
268
+ if (anchorRef.current) observer?.observe(anchorRef.current);
269
+ return () => {
270
+ cancelAnimationFrame(frame);
271
+ observer?.disconnect();
272
+ window.removeEventListener("scroll", schedule, true);
273
+ window.removeEventListener("resize", schedule);
274
+ };
275
+ }, [focused, expansionMode, focusedHeight, safeMinHeight]);
276
+ const [popoverPosition, setPopoverPosition] = react.useState(null);
277
+ const activeTokenKeyRef = react.useRef(null);
278
+ const lastPointerTokenKeyRef = react.useRef(null);
279
+ const openTimerRef = react.useRef(null);
280
+ const closeTimerRef = react.useRef(null);
281
+ const frameRef = react.useRef(null);
282
+ const pointerRafRef = react.useRef(null);
283
+ const repositionRafRef = react.useRef(null);
284
+ const resizeObserverRef = react.useRef(null);
285
+ const tooltipResizeObserverRef = react.useRef(null);
286
+ const pointerInEditorRef = react.useRef(false);
287
+ const pointerInPopoverRef = react.useRef(false);
288
+ const markPopoverPointerDownUntilRef = react.useRef(0);
289
+ const variablesSnapshotRef = react.useRef({
290
+ variables,
291
+ version: 1
292
+ });
293
+ const disabledRef = react.useRef(disabled);
294
+ const readOnlyRef = react.useRef(readOnly);
295
+ const submitOnEnterRef = react.useRef(submitOnEnter);
296
+ const allowLineBreaksRef = react.useRef(allowLineBreaks);
297
+ const maxLengthRef = react.useRef(safeMaxLength);
298
+ const onChangeRef = react.useRef(onChange);
299
+ const onSubmitRef = react.useRef(onSubmit);
300
+ const onFocusRef = react.useRef(onFocus);
301
+ const onBlurRef = react.useRef(onBlur);
302
+ const editableCompartmentRef = react.useRef(new state.Compartment());
303
+ const variableDecorationCompartmentRef = react.useRef(new state.Compartment());
304
+ const variableCompletionCompartmentRef = react.useRef(new state.Compartment());
305
+ const placeholderCompartmentRef = react.useRef(new state.Compartment());
306
+ const ariaCompartmentRef = react.useRef(new state.Compartment());
307
+ const wrappingCompartmentRef = react.useRef(new state.Compartment());
308
+ const tokenIndexRef = react.useRef({
309
+ doc: normalizedValue,
310
+ variablesVersion: variablesSnapshotRef.current.version,
311
+ tokens: []
312
+ });
313
+ const pendingPointerRef = react.useRef(null);
314
+ const rootStyle = react.useMemo(
315
+ () => ({
316
+ "--editor-min-height": `${safeMinHeight}px`,
317
+ "--editor-max-focused-height": `${safeMaxHeight}px`,
318
+ "--editor-padding-block": `${Number.isFinite(safePadding) ? Math.max(0, safePadding) : 8}px`,
319
+ "--editor-focused-height": `${focusedHeight}px`
320
+ }),
321
+ [focusedHeight, safeMaxHeight, safeMinHeight, safePadding]
322
+ );
323
+ const sameRect = react.useCallback(
324
+ (a, b, eps = 0.01) => {
325
+ return Math.abs(a.left - b.left) < eps && Math.abs(a.top - b.top) < eps && Math.abs(a.width - b.width) < eps && Math.abs(a.height - b.height) < eps;
326
+ },
327
+ []
328
+ );
329
+ react.useEffect(() => {
330
+ focusedHeightRef.current = focusedHeight;
331
+ }, [focusedHeight]);
332
+ react.useEffect(() => {
333
+ wrappedRef.current = wrapped;
334
+ }, [wrapped]);
335
+ const cancelOpen = react.useCallback(() => {
336
+ if (openTimerRef.current !== null) {
337
+ window.clearTimeout(openTimerRef.current);
338
+ openTimerRef.current = null;
339
+ }
340
+ }, []);
341
+ const cancelClose = react.useCallback(() => {
342
+ if (closeTimerRef.current !== null) {
343
+ window.clearTimeout(closeTimerRef.current);
344
+ closeTimerRef.current = null;
345
+ }
346
+ }, []);
347
+ const cancelFrame = react.useCallback(() => {
348
+ if (frameRef.current !== null) {
349
+ window.cancelAnimationFrame(frameRef.current);
350
+ frameRef.current = null;
351
+ }
352
+ }, []);
353
+ const cancelRepositionFrame = react.useCallback(() => {
354
+ if (repositionRafRef.current !== null) {
355
+ window.cancelAnimationFrame(repositionRafRef.current);
356
+ repositionRafRef.current = null;
357
+ }
358
+ }, []);
359
+ const commitHover = react.useCallback(
360
+ (next) => {
361
+ if (destroyedRef.current) {
362
+ return;
363
+ }
364
+ const current = hoverRef.current;
365
+ if (!current && !next) {
366
+ return;
367
+ }
368
+ if (current && next && current.tokenKey === next.tokenKey && sameRect(current.rect, next.rect)) {
369
+ return;
370
+ }
371
+ hoverRef.current = next;
372
+ activeTokenKeyRef.current = next?.tokenKey ?? null;
373
+ setHover(next);
374
+ if (!next) {
375
+ setPopoverPosition(null);
376
+ }
377
+ },
378
+ [sameRect]
379
+ );
380
+ const closeHover = react.useCallback(() => {
381
+ cancelOpen();
382
+ cancelClose();
383
+ cancelRepositionFrame();
384
+ commitHover(null);
385
+ }, [cancelClose, cancelOpen, cancelRepositionFrame, commitHover]);
386
+ const markPopoverPointerDown = react.useCallback(() => {
387
+ markPopoverPointerDownUntilRef.current = Date.now() + 150;
388
+ }, []);
389
+ const requestFinalClose = react.useCallback(() => {
390
+ cancelClose();
391
+ closeTimerRef.current = window.setTimeout(() => {
392
+ closeTimerRef.current = null;
393
+ if (destroyedRef.current) {
394
+ return;
395
+ }
396
+ if (Date.now() < markPopoverPointerDownUntilRef.current) {
397
+ return;
398
+ }
399
+ const shouldClose = !pointerInEditorRef.current && !pointerInPopoverRef.current && !focusedRef.current;
400
+ if (!shouldClose) {
401
+ return;
402
+ }
403
+ closeHover();
404
+ setWrapped(false);
405
+ setFocusedHeight(safeMinHeight);
406
+ }, HOVER_CLOSE_DELAY);
407
+ }, [cancelClose, closeHover, safeMinHeight]);
408
+ const scheduleClose = react.useCallback(() => {
409
+ cancelClose();
410
+ closeTimerRef.current = window.setTimeout(() => {
411
+ closeTimerRef.current = null;
412
+ if (destroyedRef.current) {
413
+ return;
414
+ }
415
+ if (Date.now() < markPopoverPointerDownUntilRef.current) {
416
+ return;
417
+ }
418
+ if (tooltipRef.current?.matches(":hover, :focus-within")) {
419
+ return;
420
+ }
421
+ commitHover(null);
422
+ }, HOVER_CLOSE_DELAY);
423
+ }, [cancelClose, commitHover]);
424
+ const getTokensCurrent = react.useCallback(
425
+ (view) => {
426
+ const doc = view.state.doc.toString();
427
+ const snapshot = variablesSnapshotRef.current;
428
+ const cached = tokenIndexRef.current;
429
+ if (cached.doc === doc && cached.variablesVersion === snapshot.version) {
430
+ return cached.tokens;
431
+ }
432
+ const tokens = chunkOOSNM45O_cjs.findVariableTokens(doc, snapshot.variables);
433
+ tokenIndexRef.current = {
434
+ doc,
435
+ variablesVersion: snapshot.version,
436
+ tokens
437
+ };
438
+ return tokens;
439
+ },
440
+ []
441
+ );
442
+ const getTokenAtPointer = react.useCallback(
443
+ (snapshot) => {
444
+ const view = viewRef.current;
445
+ if (destroyedRef.current || !view) {
446
+ return null;
447
+ }
448
+ const tokens = getTokensCurrent(view);
449
+ if (!tokens.length) {
450
+ return null;
451
+ }
452
+ const pos = view.posAtCoords({
453
+ x: snapshot.clientX,
454
+ y: snapshot.clientY
455
+ });
456
+ if (pos == null) {
457
+ return null;
458
+ }
459
+ return chunkOOSNM45O_cjs.tokenAtPosition(tokens, pos) ?? null;
460
+ },
461
+ [getTokensCurrent]
462
+ );
463
+ const fullLineTokenRectFromView = react.useCallback(
464
+ (view, from, to) => {
465
+ if (view.state.doc.length === 0) return null;
466
+ const host = view.dom;
467
+ const selector = `${TOKEN_SELECTOR}[data-variable-from="${chunkOOSNM45O_cjs.escapeCssAttrValue(String(from))}"][data-variable-to="${chunkOOSNM45O_cjs.escapeCssAttrValue(String(to))}"]`;
468
+ const element = host.querySelector(selector);
469
+ if (element) {
470
+ const tokenRect = element.getBoundingClientRect();
471
+ const lineElement = element.closest(".cm-line");
472
+ const lineRect = lineElement?.getBoundingClientRect();
473
+ const editorRect = view.dom.getBoundingClientRect();
474
+ const top2 = Math.max(editorRect.top, lineRect?.top ?? tokenRect.top);
475
+ const bottom2 = Math.min(
476
+ editorRect.bottom,
477
+ lineRect?.bottom ?? tokenRect.bottom
478
+ );
479
+ const height2 = Math.max(tokenRect.height, bottom2 - top2);
480
+ const width2 = tokenRect.width;
481
+ if (width2 <= 0 || height2 <= 0) {
482
+ return null;
483
+ }
484
+ return new DOMRect(tokenRect.left, top2, width2, height2);
485
+ }
486
+ const startCoords = view.coordsAtPos(from);
487
+ const endCoords = view.coordsAtPos(to);
488
+ if (!startCoords || !endCoords) {
489
+ return null;
490
+ }
491
+ const left = startCoords.left;
492
+ const right = endCoords.right;
493
+ const top = Math.min(startCoords.top, endCoords.top);
494
+ const bottom = Math.max(startCoords.bottom, endCoords.bottom);
495
+ const width = right - left;
496
+ const height = bottom - top;
497
+ if (width <= 0 || height <= 0) {
498
+ return null;
499
+ }
500
+ return new DOMRect(left, top, width, height);
501
+ },
502
+ []
503
+ );
504
+ const buildHoverFromToken = react.useCallback(
505
+ (view, token) => {
506
+ if (destroyedRef.current) {
507
+ return null;
508
+ }
509
+ const rect = fullLineTokenRectFromView(view, token.from, token.to);
510
+ if (!rect || rect.width <= 0 || rect.height <= 0) {
511
+ return null;
512
+ }
513
+ const tokenKey = `${token.from}:${token.to}:${token.name}`;
514
+ return {
515
+ tokenKey,
516
+ rect,
517
+ from: token.from,
518
+ to: token.to,
519
+ name: token.name,
520
+ variable: token.variable
521
+ };
522
+ },
523
+ [fullLineTokenRectFromView]
524
+ );
525
+ const showToken = react.useCallback(
526
+ (token) => {
527
+ if (destroyedRef.current) {
528
+ return;
529
+ }
530
+ const view = viewRef.current;
531
+ if (!view || disabledRef.current) {
532
+ return;
533
+ }
534
+ const nextHover = buildHoverFromToken(view, token);
535
+ if (!nextHover) {
536
+ closeHover();
537
+ return;
538
+ }
539
+ if (activeTokenKeyRef.current === nextHover.tokenKey && hoverRef.current && hoverRef.current.tokenKey === nextHover.tokenKey && sameRect(hoverRef.current.rect, nextHover.rect)) {
540
+ return;
541
+ }
542
+ commitHover(nextHover);
543
+ },
544
+ [buildHoverFromToken, closeHover, commitHover, sameRect]
545
+ );
546
+ const scheduleOpen = react.useCallback(
547
+ (snapshot, token) => {
548
+ cancelClose();
549
+ cancelOpen();
550
+ openTimerRef.current = window.setTimeout(() => {
551
+ openTimerRef.current = null;
552
+ if (destroyedRef.current) {
553
+ return;
554
+ }
555
+ const view = viewRef.current;
556
+ if (!view || disabledRef.current) {
557
+ return;
558
+ }
559
+ const tokens = getTokensCurrent(view);
560
+ const latest = tokens.find(
561
+ (candidate) => candidate.from === token.from && candidate.to === token.to && candidate.token === token.token
562
+ );
563
+ if (!latest) {
564
+ return;
565
+ }
566
+ const latestToken = getTokenAtPointer(snapshot);
567
+ if (!latestToken || latestToken.from !== latest.from || latestToken.to !== latest.to) {
568
+ return;
569
+ }
570
+ showToken(latest);
571
+ }, HOVER_OPEN_DELAY);
572
+ },
573
+ [cancelClose, cancelOpen, getTokenAtPointer, getTokensCurrent, showToken]
574
+ );
575
+ const flushPointer = react.useCallback(() => {
576
+ pointerRafRef.current = null;
577
+ const snapshot = pendingPointerRef.current;
578
+ pendingPointerRef.current = null;
579
+ if (!snapshot || destroyedRef.current) {
580
+ return;
581
+ }
582
+ pointerInEditorRef.current = true;
583
+ const token = getTokenAtPointer(snapshot);
584
+ if (token) {
585
+ const tokenKey = `${token.from}:${token.to}:${token.name}`;
586
+ if (lastPointerTokenKeyRef.current !== tokenKey) {
587
+ lastPointerTokenKeyRef.current = tokenKey;
588
+ scheduleOpen(snapshot, token);
589
+ } else if (!hoverRef.current) {
590
+ scheduleOpen(snapshot, token);
591
+ }
592
+ return;
593
+ }
594
+ lastPointerTokenKeyRef.current = null;
595
+ if (hoverRef.current) {
596
+ requestFinalClose();
597
+ } else {
598
+ cancelOpen();
599
+ }
600
+ }, [cancelOpen, getTokenAtPointer, requestFinalClose, scheduleOpen]);
601
+ const schedulePointerFlush = react.useCallback(
602
+ (event) => {
603
+ pendingPointerRef.current = {
604
+ clientX: event.clientX,
605
+ clientY: event.clientY
606
+ };
607
+ if (pointerRafRef.current !== null) {
608
+ return;
609
+ }
610
+ pointerRafRef.current = window.requestAnimationFrame(flushPointer);
611
+ },
612
+ [flushPointer]
613
+ );
614
+ const handlePointerMove = react.useCallback(
615
+ (event) => {
616
+ schedulePointerFlush(event);
617
+ },
618
+ [schedulePointerFlush]
619
+ );
620
+ const handleHostPointerEnter = react.useCallback(() => {
621
+ pointerInEditorRef.current = true;
622
+ }, []);
623
+ const handleHostPointerLeave = react.useCallback(() => {
624
+ pointerInEditorRef.current = false;
625
+ cancelOpen();
626
+ requestFinalClose();
627
+ }, [cancelOpen, requestFinalClose]);
628
+ const handleTooltipPointerEnter = react.useCallback(() => {
629
+ pointerInPopoverRef.current = true;
630
+ cancelClose();
631
+ }, [cancelClose]);
632
+ const handleTooltipPointerLeave = react.useCallback(() => {
633
+ pointerInPopoverRef.current = false;
634
+ requestFinalClose();
635
+ }, [requestFinalClose]);
636
+ const measureFocusedHeight = react.useCallback(() => {
637
+ if (destroyedRef.current || !focusedRef.current) {
638
+ return;
639
+ }
640
+ const expectedView = viewRef.current;
641
+ if (!expectedView) {
642
+ return;
643
+ }
644
+ if (frameRef.current !== null) {
645
+ return;
646
+ }
647
+ frameRef.current = window.requestAnimationFrame(() => {
648
+ frameRef.current = null;
649
+ if (destroyedRef.current) {
650
+ return;
651
+ }
652
+ if (viewRef.current !== expectedView) {
653
+ return;
654
+ }
655
+ if (!focusedRef.current) {
656
+ return;
657
+ }
658
+ const content = expectedView.contentDOM;
659
+ const measuredRaw = Math.max(
660
+ safeMinHeight,
661
+ Math.ceil(content.scrollHeight)
662
+ );
663
+ const stableHeight = measuredRaw <= safeMinHeight + 2 ? safeMinHeight : measuredRaw;
664
+ const nextHeight = Math.min(stableHeight, safeMaxHeight);
665
+ const nextWrapped = stableHeight > safeMinHeight;
666
+ const currentHeight = focusedHeightRef.current;
667
+ const currentWrapped = wrappedRef.current;
668
+ if (nextHeight === currentHeight && nextWrapped === currentWrapped) {
669
+ return;
670
+ }
671
+ focusedHeightRef.current = nextHeight;
672
+ wrappedRef.current = nextWrapped;
673
+ setFocusedHeight(nextHeight);
674
+ setWrapped(nextWrapped);
675
+ });
676
+ }, [safeMaxHeight, safeMinHeight]);
677
+ const calculatePopoverPosition = react.useCallback(
678
+ (rect, width, height) => {
679
+ const safeWidth = Math.min(
680
+ POPOVER_MAX_WIDTH,
681
+ Math.max(1, window.innerWidth - VIEWPORT_MARGIN * 2)
682
+ );
683
+ const actualWidth = Math.min(
684
+ safeWidth,
685
+ Math.max(1, width || safeWidth)
686
+ );
687
+ const actualHeight = Math.max(1, height || POPOVER_FALLBACK_HEIGHT);
688
+ const tokenCenter = rect.left + rect.width / 2;
689
+ const left = Math.max(
690
+ VIEWPORT_MARGIN,
691
+ Math.min(
692
+ tokenCenter - actualWidth / 2,
693
+ window.innerWidth - actualWidth - VIEWPORT_MARGIN
694
+ )
695
+ );
696
+ const canPlaceBelow = rect.bottom + POPOVER_GAP + actualHeight <= window.innerHeight - VIEWPORT_MARGIN;
697
+ const canPlaceAbove = rect.top - POPOVER_GAP - actualHeight >= VIEWPORT_MARGIN;
698
+ const showAbove = !canPlaceBelow && canPlaceAbove;
699
+ const top = showAbove ? Math.max(VIEWPORT_MARGIN, rect.top - actualHeight - POPOVER_GAP) : Math.min(
700
+ Math.max(VIEWPORT_MARGIN, rect.bottom + POPOVER_GAP),
701
+ Math.max(
702
+ VIEWPORT_MARGIN,
703
+ window.innerHeight - actualHeight - VIEWPORT_MARGIN
704
+ )
705
+ );
706
+ return {
707
+ left,
708
+ top,
709
+ placement: showAbove ? "top" : "bottom",
710
+ arrowLeft: Math.max(
711
+ 12,
712
+ Math.min(tokenCenter - left, actualWidth - 12)
713
+ )
714
+ };
715
+ },
716
+ []
717
+ );
718
+ const repositionPopover = react.useCallback(() => {
719
+ if (destroyedRef.current) {
720
+ return;
721
+ }
722
+ const currentHover = hoverRef.current;
723
+ if (!currentHover) {
724
+ return;
725
+ }
726
+ const tooltip = tooltipRef.current;
727
+ const rect = currentHover.rect;
728
+ const tooltipRect = tooltip?.getBoundingClientRect();
729
+ const width = tooltipRect?.width || Math.min(POPOVER_MAX_WIDTH, window.innerWidth - VIEWPORT_MARGIN * 2);
730
+ const height = tooltipRect?.height || POPOVER_FALLBACK_HEIGHT;
731
+ const next = calculatePopoverPosition(rect, width, height);
732
+ setPopoverPosition((previous) => {
733
+ if (previous && previous.left === next.left && previous.top === next.top && previous.placement === next.placement && previous.arrowLeft === next.arrowLeft) {
734
+ return previous;
735
+ }
736
+ return next;
737
+ });
738
+ }, [calculatePopoverPosition]);
739
+ const schedulePopoverReposition = react.useCallback(() => {
740
+ if (repositionRafRef.current !== null) {
741
+ return;
742
+ }
743
+ repositionRafRef.current = window.requestAnimationFrame(() => {
744
+ repositionRafRef.current = null;
745
+ repositionPopover();
746
+ });
747
+ }, [repositionPopover]);
748
+ const applyExternalValue = react.useCallback(
749
+ (view, nextValue) => {
750
+ if (destroyedRef.current || viewRef.current !== view) {
751
+ return false;
752
+ }
753
+ const currentDoc = view.state.doc.toString();
754
+ if (currentDoc === nextValue) {
755
+ editorValueRef.current = currentDoc;
756
+ return false;
757
+ }
758
+ closeHover();
759
+ view.dispatch({
760
+ changes: {
761
+ from: 0,
762
+ to: currentDoc.length,
763
+ insert: nextValue
764
+ },
765
+ annotations: ExternalValueUpdate.of(true)
766
+ });
767
+ editorValueRef.current = nextValue;
768
+ return true;
769
+ },
770
+ [closeHover]
771
+ );
772
+ react.useLayoutEffect(() => {
773
+ disabledRef.current = disabled;
774
+ readOnlyRef.current = readOnly;
775
+ submitOnEnterRef.current = submitOnEnter;
776
+ allowLineBreaksRef.current = allowLineBreaks;
777
+ maxLengthRef.current = safeMaxLength;
778
+ onChangeRef.current = onChange;
779
+ onSubmitRef.current = onSubmit;
780
+ onFocusRef.current = onFocus;
781
+ onBlurRef.current = onBlur;
782
+ }, [
783
+ disabled,
784
+ readOnly,
785
+ submitOnEnter,
786
+ allowLineBreaks,
787
+ safeMaxLength,
788
+ onChange,
789
+ onSubmit,
790
+ onFocus,
791
+ onBlur
792
+ ]);
793
+ const measurementRef = react.useRef(measureFocusedHeight);
794
+ const minimumHeightRef = react.useRef(safeMinHeight);
795
+ react.useLayoutEffect(() => {
796
+ measurementRef.current = measureFocusedHeight;
797
+ minimumHeightRef.current = safeMinHeight;
798
+ measureFocusedHeight();
799
+ }, [measureFocusedHeight, safeMinHeight]);
800
+ react.useLayoutEffect(() => {
801
+ const host = hostRef.current;
802
+ if (!host || viewRef.current) {
803
+ return;
804
+ }
805
+ destroyedRef.current = false;
806
+ const editable = !disabledRef.current && !readOnlyRef.current;
807
+ const view$1 = new view.EditorView({
808
+ parent: host,
809
+ state: state.EditorState.create({
810
+ doc: initialValueRef.current,
811
+ extensions: [
812
+ commands.history(),
813
+ view.drawSelection({
814
+ cursorBlinkRate: 1200
815
+ }),
816
+ state.EditorState.allowMultipleSelections.of(false),
817
+ editableCompartmentRef.current.of([
818
+ state.EditorState.readOnly.of(!editable),
819
+ view.EditorView.editable.of(editable)
820
+ ]),
821
+ /**
822
+ * P0:
823
+ *
824
+ * All document invariants are enforced at the transaction level.
825
+ */
826
+ createInputInvariantFilter(
827
+ maxLengthRef,
828
+ allowLineBreaksRef,
829
+ isComposingRef
830
+ ),
831
+ wrappingCompartmentRef.current.of([]),
832
+ view.EditorView.updateListener.of((update) => {
833
+ if (update.docChanged) {
834
+ closeHover();
835
+ const newLength = update.state.doc.length;
836
+ if (newLength === 0) {
837
+ hoverRef.current = null;
838
+ activeTokenKeyRef.current = null;
839
+ lastPointerTokenKeyRef.current = null;
840
+ setHover(null);
841
+ setPopoverPosition(null);
842
+ cancelRepositionFrame();
843
+ }
844
+ }
845
+ if (!update.docChanged) {
846
+ return;
847
+ }
848
+ const isExternal = update.transactions.some(
849
+ (transaction) => transaction.annotation(ExternalValueUpdate) === true
850
+ );
851
+ const rawValue = update.state.doc.toString();
852
+ editorValueRef.current = rawValue;
853
+ if (isComposingRef.current) {
854
+ pendingCompositionSyncRef.current = true;
855
+ return;
856
+ }
857
+ if (isExternal) {
858
+ return;
859
+ }
860
+ const nextValue = chunkOOSNM45O_cjs.sanitizePlainText(
861
+ rawValue,
862
+ maxLengthRef.current,
863
+ allowLineBreaksRef.current
864
+ );
865
+ if (nextValue !== rawValue) {
866
+ return;
867
+ }
868
+ if (focusedRef.current) {
869
+ measurementRef.current();
870
+ }
871
+ pendingEmittedValuesRef.current.push(nextValue);
872
+ if (pendingEmittedValuesRef.current.length > MAX_PENDING_CONTROLLED_VALUES) {
873
+ pendingEmittedValuesRef.current = pendingEmittedValuesRef.current.slice(
874
+ -MAX_PENDING_CONTROLLED_VALUES
875
+ );
876
+ }
877
+ onChangeRef.current?.(nextValue);
878
+ }),
879
+ variableDecorationCompartmentRef.current.of(
880
+ createVariableDecorationExtension(
881
+ variablesSnapshotRef,
882
+ tokenIndexRef
883
+ )
884
+ ),
885
+ variableCompletionCompartmentRef.current.of(
886
+ createVariableCompletionExtension(
887
+ variablesSnapshotRef.current.variables
888
+ )
889
+ ),
890
+ placeholderCompartmentRef.current.of(
891
+ placeholder ? view.placeholder(placeholder) : []
892
+ ),
893
+ ariaCompartmentRef.current.of(
894
+ view.EditorView.contentAttributes.of({
895
+ "aria-label": ariaLabel,
896
+ "aria-disabled": disabledRef.current ? "true" : "false",
897
+ "aria-readonly": readOnlyRef.current ? "true" : "false",
898
+ spellcheck: "false",
899
+ autocapitalize: "off",
900
+ autocomplete: "off"
901
+ })
902
+ ),
903
+ view.keymap.of([
904
+ ...autocomplete.completionKeymap,
905
+ ...commands.historyKeymap,
906
+ ...commands.defaultKeymap
907
+ ]),
908
+ view.EditorView.domEventHandlers({
909
+ compositionstart() {
910
+ isComposingRef.current = true;
911
+ return false;
912
+ },
913
+ compositionend() {
914
+ isComposingRef.current = false;
915
+ queueMicrotask(() => {
916
+ if (destroyedRef.current || viewRef.current !== view$1) {
917
+ return;
918
+ }
919
+ if (!pendingCompositionSyncRef.current) {
920
+ return;
921
+ }
922
+ pendingCompositionSyncRef.current = false;
923
+ const rawValue = view$1.state.doc.toString();
924
+ const normalized = chunkOOSNM45O_cjs.sanitizePlainText(
925
+ rawValue,
926
+ maxLengthRef.current,
927
+ allowLineBreaksRef.current
928
+ );
929
+ if (normalized !== rawValue) {
930
+ view$1.dispatch({
931
+ changes: {
932
+ from: 0,
933
+ to: rawValue.length,
934
+ insert: normalized
935
+ },
936
+ annotations: ExternalValueUpdate.of(true)
937
+ });
938
+ editorValueRef.current = normalized;
939
+ pendingEmittedValuesRef.current.push(normalized);
940
+ onChangeRef.current?.(normalized);
941
+ return;
942
+ }
943
+ editorValueRef.current = rawValue;
944
+ pendingEmittedValuesRef.current.push(rawValue);
945
+ onChangeRef.current?.(rawValue);
946
+ });
947
+ return false;
948
+ },
949
+ keydown(event, currentView) {
950
+ if (event.isComposing || isComposingRef.current || disabledRef.current || readOnlyRef.current)
951
+ return false;
952
+ if (event.key !== "Enter") {
953
+ return false;
954
+ }
955
+ if (allowLineBreaksRef.current) {
956
+ return false;
957
+ }
958
+ if (autocomplete.acceptCompletion(currentView)) {
959
+ event.preventDefault();
960
+ event.stopPropagation();
961
+ return true;
962
+ }
963
+ event.preventDefault();
964
+ event.stopPropagation();
965
+ if (submitOnEnterRef.current) {
966
+ onSubmitRef.current?.(currentView.state.doc.toString());
967
+ }
968
+ return true;
969
+ },
970
+ beforeinput(event, currentView) {
971
+ if (disabledRef.current || readOnlyRef.current) {
972
+ event.preventDefault();
973
+ return true;
974
+ }
975
+ if (isComposingRef.current) {
976
+ return false;
977
+ }
978
+ if (!event.inputType.startsWith("insert")) {
979
+ return false;
980
+ }
981
+ const text = event.data;
982
+ if (!allowLineBreaksRef.current) {
983
+ if (event.inputType === "insertLineBreak" || event.inputType === "insertParagraph" || event.inputType === "insertNewline") {
984
+ event.preventDefault();
985
+ return true;
986
+ }
987
+ if (text != null && /[\r\n\u2028\u2029]/.test(text)) {
988
+ event.preventDefault();
989
+ return true;
990
+ }
991
+ }
992
+ if (!text) {
993
+ return false;
994
+ }
995
+ const normalizedInsert = allowLineBreaksRef.current ? text : text.replace(/[\r\n\u2028\u2029]+/g, " ");
996
+ const selection = currentView.state.selection.main;
997
+ const insert = chunkOOSNM45O_cjs.truncateInsertion(
998
+ normalizedInsert,
999
+ currentView.state.doc.length,
1000
+ selection.to - selection.from,
1001
+ maxLengthRef.current
1002
+ );
1003
+ if (insert === text) {
1004
+ return false;
1005
+ }
1006
+ event.preventDefault();
1007
+ if (insert) {
1008
+ currentView.dispatch(
1009
+ currentView.state.replaceSelection(insert)
1010
+ );
1011
+ }
1012
+ return true;
1013
+ },
1014
+ paste(event, currentView) {
1015
+ if (disabledRef.current || readOnlyRef.current) {
1016
+ event.preventDefault();
1017
+ return true;
1018
+ }
1019
+ const text = event.clipboardData?.getData("text/plain");
1020
+ if (text === void 0) {
1021
+ return false;
1022
+ }
1023
+ event.preventDefault();
1024
+ const normalizedInsert = allowLineBreaksRef.current ? text : text.replace(/[\r\n\u2028\u2029]+/g, " ");
1025
+ const selection = currentView.state.selection.main;
1026
+ const insert = chunkOOSNM45O_cjs.truncateInsertion(
1027
+ normalizedInsert,
1028
+ currentView.state.doc.length,
1029
+ selection.to - selection.from,
1030
+ maxLengthRef.current
1031
+ );
1032
+ if (insert) {
1033
+ currentView.dispatch(
1034
+ currentView.state.replaceSelection(insert)
1035
+ );
1036
+ }
1037
+ return true;
1038
+ },
1039
+ drop(event, currentView) {
1040
+ if (disabledRef.current || readOnlyRef.current) {
1041
+ event.preventDefault();
1042
+ return true;
1043
+ }
1044
+ const text = event.dataTransfer?.getData("text/plain");
1045
+ if (text === void 0) {
1046
+ return false;
1047
+ }
1048
+ event.preventDefault();
1049
+ const normalizedInsert = allowLineBreaksRef.current ? text : text.replace(/[\r\n\u2028\u2029]+/g, " ");
1050
+ const position = currentView.posAtCoords({
1051
+ x: event.clientX,
1052
+ y: event.clientY
1053
+ });
1054
+ const selection = currentView.state.selection.main;
1055
+ const hasSelection = !selection.empty && position != null;
1056
+ let from;
1057
+ let to;
1058
+ let replacedLength;
1059
+ if (hasSelection) {
1060
+ from = selection.from;
1061
+ to = selection.to;
1062
+ replacedLength = to - from;
1063
+ } else {
1064
+ from = position ?? selection.from;
1065
+ to = from;
1066
+ replacedLength = 0;
1067
+ }
1068
+ const insert = chunkOOSNM45O_cjs.truncateInsertion(
1069
+ normalizedInsert,
1070
+ currentView.state.doc.length,
1071
+ replacedLength,
1072
+ maxLengthRef.current
1073
+ );
1074
+ if (insert) {
1075
+ currentView.dispatch({
1076
+ changes: {
1077
+ from,
1078
+ to,
1079
+ insert
1080
+ },
1081
+ selection: {
1082
+ anchor: from + insert.length
1083
+ },
1084
+ scrollIntoView: true,
1085
+ userEvent: "input.drop"
1086
+ });
1087
+ }
1088
+ return true;
1089
+ },
1090
+ focus() {
1091
+ if (destroyedRef.current || viewRef.current !== view$1) {
1092
+ return false;
1093
+ }
1094
+ focusedRef.current = true;
1095
+ setFocused(true);
1096
+ view$1.dispatch({
1097
+ effects: wrappingCompartmentRef.current.reconfigure([
1098
+ view.EditorView.lineWrapping
1099
+ ])
1100
+ });
1101
+ queueMicrotask(() => {
1102
+ if (destroyedRef.current || viewRef.current !== view$1) {
1103
+ return;
1104
+ }
1105
+ if (!view$1.hasFocus) {
1106
+ return;
1107
+ }
1108
+ measurementRef.current();
1109
+ });
1110
+ onFocusRef.current?.();
1111
+ return false;
1112
+ },
1113
+ blur() {
1114
+ if (destroyedRef.current || viewRef.current !== view$1) {
1115
+ return false;
1116
+ }
1117
+ focusedRef.current = false;
1118
+ setFocused(false);
1119
+ setWrapped(false);
1120
+ focusedHeightRef.current = minimumHeightRef.current;
1121
+ setFocusedHeight(minimumHeightRef.current);
1122
+ scheduleClose();
1123
+ view$1.dispatch({
1124
+ effects: wrappingCompartmentRef.current.reconfigure([])
1125
+ });
1126
+ onBlurRef.current?.();
1127
+ return false;
1128
+ }
1129
+ })
1130
+ ]
1131
+ })
1132
+ });
1133
+ viewRef.current = view$1;
1134
+ editorValueRef.current = view$1.state.doc.toString();
1135
+ if (typeof ResizeObserver !== "undefined") {
1136
+ resizeObserverRef.current = new ResizeObserver(() => {
1137
+ if (destroyedRef.current) {
1138
+ return;
1139
+ }
1140
+ const currentView = viewRef.current;
1141
+ if (!currentView || currentView !== view$1) {
1142
+ return;
1143
+ }
1144
+ if (focusedRef.current) {
1145
+ measurementRef.current();
1146
+ }
1147
+ });
1148
+ resizeObserverRef.current.observe(host);
1149
+ }
1150
+ if (autoFocus && editable) {
1151
+ queueMicrotask(() => {
1152
+ if (destroyedRef.current || viewRef.current !== view$1) {
1153
+ return;
1154
+ }
1155
+ if (!view$1.hasFocus) {
1156
+ view$1.focus();
1157
+ }
1158
+ });
1159
+ }
1160
+ return () => {
1161
+ destroyedRef.current = true;
1162
+ focusedRef.current = false;
1163
+ isComposingRef.current = false;
1164
+ pendingCompositionSyncRef.current = false;
1165
+ cancelOpen();
1166
+ cancelClose();
1167
+ cancelFrame();
1168
+ cancelRepositionFrame();
1169
+ resizeObserverRef.current?.disconnect();
1170
+ resizeObserverRef.current = null;
1171
+ tooltipResizeObserverRef.current?.disconnect();
1172
+ tooltipResizeObserverRef.current = null;
1173
+ if (pointerRafRef.current !== null) {
1174
+ window.cancelAnimationFrame(pointerRafRef.current);
1175
+ pointerRafRef.current = null;
1176
+ }
1177
+ pendingPointerRef.current = null;
1178
+ hoverRef.current = null;
1179
+ activeTokenKeyRef.current = null;
1180
+ lastPointerTokenKeyRef.current = null;
1181
+ tokenIndexRef.current = {
1182
+ doc: "",
1183
+ variablesVersion: variablesSnapshotRef.current.version,
1184
+ tokens: []
1185
+ };
1186
+ setHover(null);
1187
+ setPopoverPosition(null);
1188
+ if (viewRef.current === view$1) {
1189
+ viewRef.current = null;
1190
+ }
1191
+ try {
1192
+ view$1.destroy();
1193
+ } catch {
1194
+ }
1195
+ };
1196
+ }, []);
1197
+ react.useEffect(() => {
1198
+ const view = viewRef.current;
1199
+ if (!view || destroyedRef.current) {
1200
+ return;
1201
+ }
1202
+ if (isComposingRef.current) {
1203
+ return;
1204
+ }
1205
+ const nextValue = normalizedValue;
1206
+ const currentDoc = view.state.doc.toString();
1207
+ if (currentDoc === nextValue) {
1208
+ editorValueRef.current = currentDoc;
1209
+ lastAcknowledgedPropValueRef.current = nextValue;
1210
+ pendingEmittedValuesRef.current = [];
1211
+ return;
1212
+ }
1213
+ if (nextValue === lastAcknowledgedPropValueRef.current) {
1214
+ return;
1215
+ }
1216
+ const pendingIndex = pendingEmittedValuesRef.current.indexOf(nextValue);
1217
+ if (pendingIndex !== -1) {
1218
+ lastAcknowledgedPropValueRef.current = nextValue;
1219
+ pendingEmittedValuesRef.current = pendingEmittedValuesRef.current.slice(
1220
+ pendingIndex + 1
1221
+ );
1222
+ return;
1223
+ }
1224
+ pendingEmittedValuesRef.current = [];
1225
+ lastAcknowledgedPropValueRef.current = nextValue;
1226
+ applyExternalValue(view, nextValue);
1227
+ }, [applyExternalValue, normalizedValue]);
1228
+ react.useEffect(() => {
1229
+ const view$1 = viewRef.current;
1230
+ if (!view$1 || destroyedRef.current) {
1231
+ return;
1232
+ }
1233
+ const editableNow = !disabled && !readOnly;
1234
+ if (!editableNow) {
1235
+ closeHover();
1236
+ if (view$1.hasFocus) {
1237
+ try {
1238
+ view$1.contentDOM.blur();
1239
+ } catch {
1240
+ }
1241
+ }
1242
+ focusedRef.current = false;
1243
+ setFocused(false);
1244
+ setWrapped(false);
1245
+ focusedHeightRef.current = safeMinHeight;
1246
+ setFocusedHeight(safeMinHeight);
1247
+ view$1.dispatch({
1248
+ effects: wrappingCompartmentRef.current.reconfigure([])
1249
+ });
1250
+ }
1251
+ view$1.dispatch({
1252
+ effects: [
1253
+ editableCompartmentRef.current.reconfigure([
1254
+ state.EditorState.readOnly.of(!editableNow),
1255
+ view.EditorView.editable.of(editableNow)
1256
+ ]),
1257
+ ariaCompartmentRef.current.reconfigure(
1258
+ view.EditorView.contentAttributes.of({
1259
+ "aria-label": ariaLabel,
1260
+ "aria-disabled": disabled ? "true" : "false",
1261
+ "aria-readonly": readOnly ? "true" : "false",
1262
+ spellcheck: "false",
1263
+ autocapitalize: "off",
1264
+ autocomplete: "off"
1265
+ })
1266
+ )
1267
+ ]
1268
+ });
1269
+ }, [ariaLabel, closeHover, disabled, readOnly, safeMinHeight]);
1270
+ react.useEffect(() => {
1271
+ const view = viewRef.current;
1272
+ if (!view || destroyedRef.current) {
1273
+ return;
1274
+ }
1275
+ const currentSnapshot = variablesSnapshotRef.current;
1276
+ if (variablesEqual(currentSnapshot.variables, variables)) {
1277
+ return;
1278
+ }
1279
+ closeHover();
1280
+ activeTokenKeyRef.current = null;
1281
+ lastPointerTokenKeyRef.current = null;
1282
+ const nextVersion = currentSnapshot.version + 1;
1283
+ variablesSnapshotRef.current = {
1284
+ variables,
1285
+ version: nextVersion
1286
+ };
1287
+ tokenIndexRef.current = {
1288
+ doc: view.state.doc.toString(),
1289
+ variablesVersion: nextVersion,
1290
+ tokens: []
1291
+ };
1292
+ view.dispatch({
1293
+ annotations: VariablesSnapshotUpdate.of(nextVersion)
1294
+ });
1295
+ view.dispatch({
1296
+ effects: variableCompletionCompartmentRef.current.reconfigure(
1297
+ createVariableCompletionExtension(variables)
1298
+ )
1299
+ });
1300
+ }, [closeHover, variables]);
1301
+ react.useEffect(() => {
1302
+ const view$1 = viewRef.current;
1303
+ if (!view$1 || destroyedRef.current) {
1304
+ return;
1305
+ }
1306
+ view$1.dispatch({
1307
+ effects: placeholderCompartmentRef.current.reconfigure(
1308
+ placeholder ? view.placeholder(placeholder) : []
1309
+ )
1310
+ });
1311
+ }, [placeholder]);
1312
+ react.useLayoutEffect(() => {
1313
+ if (!hover) {
1314
+ tooltipResizeObserverRef.current?.disconnect();
1315
+ tooltipResizeObserverRef.current = null;
1316
+ setPopoverPosition(null);
1317
+ return;
1318
+ }
1319
+ setPopoverPosition(null);
1320
+ repositionPopover();
1321
+ if (typeof ResizeObserver !== "undefined" && tooltipRef.current) {
1322
+ tooltipResizeObserverRef.current?.disconnect();
1323
+ const observer = new ResizeObserver(() => {
1324
+ schedulePopoverReposition();
1325
+ });
1326
+ observer.observe(tooltipRef.current);
1327
+ tooltipResizeObserverRef.current = observer;
1328
+ }
1329
+ return () => {
1330
+ tooltipResizeObserverRef.current?.disconnect();
1331
+ tooltipResizeObserverRef.current = null;
1332
+ };
1333
+ }, [hover?.tokenKey, repositionPopover, schedulePopoverReposition]);
1334
+ react.useEffect(() => {
1335
+ if (!hover?.tokenKey) {
1336
+ return;
1337
+ }
1338
+ const reposition = () => {
1339
+ if (destroyedRef.current || repositionRafRef.current !== null) {
1340
+ return;
1341
+ }
1342
+ const view = viewRef.current;
1343
+ const latestHover = hoverRef.current;
1344
+ if (!view || !latestHover || view.state.doc.length === 0) {
1345
+ closeHover();
1346
+ return;
1347
+ }
1348
+ repositionRafRef.current = window.requestAnimationFrame(() => {
1349
+ repositionRafRef.current = null;
1350
+ if (destroyedRef.current) {
1351
+ return;
1352
+ }
1353
+ const view2 = viewRef.current;
1354
+ const latestHover2 = hoverRef.current;
1355
+ if (!view2 || !latestHover2) {
1356
+ closeHover();
1357
+ return;
1358
+ }
1359
+ const tokens = getTokensCurrent(view2);
1360
+ const latest = tokens.find(
1361
+ (token) => `${token.from}:${token.to}:${token.name}` === latestHover2.tokenKey
1362
+ );
1363
+ if (!latest) {
1364
+ closeHover();
1365
+ return;
1366
+ }
1367
+ const rect = fullLineTokenRectFromView(view2, latest.from, latest.to);
1368
+ if (!rect) {
1369
+ closeHover();
1370
+ return;
1371
+ }
1372
+ if (!sameRect(latestHover2.rect, rect)) {
1373
+ commitHover({
1374
+ tokenKey: latestHover2.tokenKey,
1375
+ rect,
1376
+ from: latest.from,
1377
+ to: latest.to,
1378
+ name: latest.name,
1379
+ variable: latest.variable
1380
+ });
1381
+ }
1382
+ repositionPopover();
1383
+ });
1384
+ };
1385
+ window.addEventListener("resize", reposition, { passive: true });
1386
+ window.addEventListener("scroll", reposition, {
1387
+ passive: true,
1388
+ capture: true
1389
+ });
1390
+ return () => {
1391
+ window.removeEventListener("resize", reposition);
1392
+ window.removeEventListener("scroll", reposition, true);
1393
+ cancelRepositionFrame();
1394
+ };
1395
+ }, [
1396
+ cancelRepositionFrame,
1397
+ closeHover,
1398
+ commitHover,
1399
+ fullLineTokenRectFromView,
1400
+ getTokensCurrent,
1401
+ hover?.tokenKey,
1402
+ repositionPopover,
1403
+ sameRect
1404
+ ]);
1405
+ const popoverStyle = react.useMemo(() => {
1406
+ if (!popoverPosition) {
1407
+ return {
1408
+ position: "fixed",
1409
+ zIndex: 999999,
1410
+ pointerEvents: "auto",
1411
+ left: 0,
1412
+ top: 0,
1413
+ visibility: "hidden"
1414
+ };
1415
+ }
1416
+ return {
1417
+ position: "fixed",
1418
+ zIndex: 999999,
1419
+ pointerEvents: "auto",
1420
+ left: popoverPosition.left,
1421
+ top: popoverPosition.top,
1422
+ visibility: "visible",
1423
+ "--popover-arrow-left": `${popoverPosition.arrowLeft}px`
1424
+ };
1425
+ }, [popoverPosition]);
1426
+ const popoverNode = hover ? /* @__PURE__ */ jsxRuntime.jsxs(
1427
+ react$1.Box,
1428
+ {
1429
+ ref: tooltipRef,
1430
+ className: VariableTextEditor_default.hoverPopover,
1431
+ style: popoverStyle,
1432
+ "data-placement": popoverPosition?.placement ?? "bottom",
1433
+ onPointerEnter: handleTooltipPointerEnter,
1434
+ onPointerLeave: handleTooltipPointerLeave,
1435
+ onPointerDown: markPopoverPointerDown,
1436
+ children: [
1437
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.Box, { className: VariableTextEditor_default.hoverPopoverArrow }),
1438
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.Box, { className: VariableTextEditor_default.popoverHeader, children: hover.variable?.name ?? hover.name }),
1439
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.Box, { className: VariableTextEditor_default.popoverType, children: hover.variable?.type ?? "Undefined variable" }),
1440
+ hover.variable?.value !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: VariableTextEditor_default.popoverValue, children: hover.variable.value }) : null,
1441
+ hover.variable?.description ? /* @__PURE__ */ jsxRuntime.jsx(react$1.Box, { className: VariableTextEditor_default.popoverDesc, children: hover.variable.description }) : !hover.variable ? /* @__PURE__ */ jsxRuntime.jsx(react$1.Box, { className: VariableTextEditor_default.popoverDesc, children: "This variable is not defined in the current environment." }) : null
1442
+ ]
1443
+ }
1444
+ ) : null;
1445
+ return /* @__PURE__ */ jsxRuntime.jsx(
1446
+ "div",
1447
+ {
1448
+ ref: anchorRef,
1449
+ style: {
1450
+ minWidth: 0,
1451
+ width: "100%",
1452
+ height: expansionMode === "overlay" ? safeMinHeight : void 0
1453
+ },
1454
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1455
+ react$1.Box,
1456
+ {
1457
+ ref: hostRef,
1458
+ className: [VariableTextEditor_default.root, className ?? ""].filter(Boolean).join(" "),
1459
+ style: { ...rootStyle, ...overlayStyle },
1460
+ "data-focused": focused ? "" : void 0,
1461
+ "data-wrapped": focused && wrapped ? "" : void 0,
1462
+ "data-multiline": allowLineBreaks ? "" : void 0,
1463
+ "data-disabled": disabled ? "" : void 0,
1464
+ "data-readonly": readOnly ? "" : void 0,
1465
+ onPointerEnter: handleHostPointerEnter,
1466
+ onPointerMove: handlePointerMove,
1467
+ onPointerLeave: handleHostPointerLeave,
1468
+ children: popoverNode
1469
+ }
1470
+ )
1471
+ }
1472
+ );
1473
+ }
1474
+ );
1475
+ VariableTextEditor.displayName = "VariableTextEditor";
1476
+
1477
+ exports.VariableTextEditor = VariableTextEditor;