@keboola/design 3.2.3 → 4.0.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.
@@ -0,0 +1,1948 @@
1
+ import { createContext, forwardRef, useMemo, useRef, useEffect, useCallback, useState, use, Children, Fragment as Fragment$1 } from 'react';
2
+ import { completeAnyWord, autocompletion } from '@codemirror/autocomplete';
3
+ import { jsonParseLinter, json } from '@codemirror/lang-json';
4
+ import { linter } from '@codemirror/lint';
5
+ import { unifiedMergeView } from '@codemirror/merge';
6
+ import { Decoration, gutter, EditorView, ViewPlugin, GutterMarker, keymap, placeholder, gutterLineClass } from '@codemirror/view';
7
+ import CodeMirror, { EditorState, EditorView as EditorView$1, keymap as keymap$1 } from '@uiw/react-codemirror';
8
+ import { clsx } from 'clsx';
9
+ import { extendTailwindMerge } from 'tailwind-merge';
10
+ import { Root as Root$1, Trigger, Portal, Content } from '@radix-ui/react-tooltip';
11
+ import { cva } from 'class-variance-authority';
12
+ import { keboolaLegacy } from '@keboola/brand-registry';
13
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
14
+ import { Root, Slottable } from '@radix-ui/react-slot';
15
+ import * as lucide_react_star from 'lucide-react';
16
+ import { javascript } from '@codemirror/lang-javascript';
17
+ import { python } from '@codemirror/lang-python';
18
+ import { sql, PLSQL } from '@codemirror/lang-sql';
19
+ import { StreamLanguage } from '@codemirror/language';
20
+ import { r } from '@codemirror/legacy-modes/mode/r';
21
+ import { shell } from '@codemirror/legacy-modes/mode/shell';
22
+ import { githubLightInit } from '@uiw/codemirror-theme-github';
23
+ import { sfsql } from '@keboola/codemirror-lang-sfsql';
24
+ import colors from '@keboola/tailwind-config/colors';
25
+ import { defaultKeymap } from '@codemirror/commands';
26
+ import { installExtensions } from '@keboola/codemirror-lang-sql';
27
+ import { StateEffect, StateField, RangeSet, RangeSetBuilder } from '@codemirror/state';
28
+
29
+ var __defProp = Object.defineProperty;
30
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
31
+ var __getOwnPropNames = Object.getOwnPropertyNames;
32
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
33
+ var __export = (target, all) => {
34
+ for (var name in all)
35
+ __defProp(target, name, { get: all[name], enumerable: true });
36
+ };
37
+ var __copyProps = (to, from, except, desc) => {
38
+ if (from && typeof from === "object" || typeof from === "function") {
39
+ for (let key of __getOwnPropNames(from))
40
+ if (!__hasOwnProp.call(to, key) && key !== except)
41
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
42
+ }
43
+ return to;
44
+ };
45
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget);
46
+
47
+ // src/constants/keyCodes.ts
48
+ var keyCodes = {
49
+ ENTER: "Enter",
50
+ ESCAPE: "Escape",
51
+ SPACE: " "
52
+ };
53
+ var twMerge = extendTailwindMerge({
54
+ prefix: "tw-"
55
+ });
56
+ var cn = (...classes) => twMerge(clsx(...classes));
57
+
58
+ // src/utils/copyToClipboard.ts
59
+ var copyToClipboard = (text) => {
60
+ return navigator.clipboard.writeText(text);
61
+ };
62
+ var ThemeContext = createContext(null);
63
+
64
+ // src/components/internal/useIsLegacyBrand.ts
65
+ var useIsLegacyBrand = () => {
66
+ const context = use(ThemeContext);
67
+ return context === null || context.brand.id === keboolaLegacy.id;
68
+ };
69
+ var tooltipVariants = cva(
70
+ [
71
+ "tailwindcss-preflight",
72
+ "tw-inline-block",
73
+ "tw-break-anywhere",
74
+ "tw-max-h-96",
75
+ "tw-overflow-y-auto",
76
+ "tw-z-[1060]",
77
+ // legacy (dark) chrome — default
78
+ "tw-rounded",
79
+ "tw-bg-neutral-800",
80
+ "tw-text-white",
81
+ // argo chrome overrides — semantic floating-panel tokens
82
+ "data-[argo=true]:tw-rounded-2xl",
83
+ "data-[argo=true]:tw-border",
84
+ "data-[argo=true]:tw-border-solid",
85
+ "data-[argo=true]:tw-border-border",
86
+ "data-[argo=true]:tw-bg-popover",
87
+ "data-[argo=true]:tw-text-popover-foreground",
88
+ "data-[argo=true]:tw-shadow-md",
89
+ // argo open animation
90
+ "data-[argo=true]:data-[state=delayed-open]:tw-animate-in",
91
+ "data-[argo=true]:data-[state=instant-open]:tw-animate-in",
92
+ "data-[argo=true]:data-[state=delayed-open]:tw-fade-in-0",
93
+ "data-[argo=true]:data-[state=instant-open]:tw-fade-in-0",
94
+ "data-[argo=true]:data-[state=delayed-open]:tw-zoom-in-95",
95
+ "data-[argo=true]:data-[state=instant-open]:tw-zoom-in-95",
96
+ // argo closed animation
97
+ "data-[argo=true]:data-[state=closed]:tw-animate-out",
98
+ "data-[argo=true]:data-[state=closed]:tw-fade-out-0",
99
+ "data-[argo=true]:data-[state=closed]:tw-zoom-out-95",
100
+ // argo position animation
101
+ "data-[argo=true]:data-[side=bottom]:tw-slide-in-from-top-2",
102
+ "data-[argo=true]:data-[side=left]:tw-slide-in-from-right-2",
103
+ "data-[argo=true]:data-[side=right]:tw-slide-in-from-left-2",
104
+ "data-[argo=true]:data-[side=top]:tw-slide-in-from-bottom-2"
105
+ ],
106
+ {
107
+ defaultVariants: {
108
+ variant: "action"
109
+ },
110
+ variants: {
111
+ variant: {
112
+ action: [
113
+ "tw-max-w-fit",
114
+ "tw-px-3",
115
+ "tw-py-2",
116
+ "tw-text-center",
117
+ "tw-text-xs",
118
+ "tw-font-medium",
119
+ "tw-uppercase",
120
+ "tw-tracking-wider"
121
+ ],
122
+ explanatory: [
123
+ "tw-max-w-80",
124
+ "tw-px-4",
125
+ "tw-py-3",
126
+ "tw-text-left",
127
+ "tw-text-sm",
128
+ "tw-font-normal"
129
+ ]
130
+ }
131
+ }
132
+ }
133
+ );
134
+ var TooltipContent = ({
135
+ className,
136
+ variant,
137
+ argo,
138
+ keepOpenOnPointerDownOutside = false,
139
+ children,
140
+ onPointerDownOutside,
141
+ sideOffset = 8,
142
+ collisionPadding = 8,
143
+ hideWhenDetached = true,
144
+ placement = "right",
145
+ ...rest
146
+ }) => {
147
+ const isLegacy = useIsLegacyBrand();
148
+ const renderArgo = !isLegacy || argo === true;
149
+ const handlePointerDownOutside = (event) => {
150
+ if (keepOpenOnPointerDownOutside) event.preventDefault();
151
+ onPointerDownOutside?.(event);
152
+ };
153
+ return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(
154
+ Content,
155
+ {
156
+ ...rest,
157
+ "data-tooltip-content": renderArgo ? void 0 : true,
158
+ "data-argo": renderArgo,
159
+ sideOffset,
160
+ collisionPadding,
161
+ onPointerDownOutside: handlePointerDownOutside,
162
+ className: tooltipVariants({ className, variant }),
163
+ hideWhenDetached,
164
+ side: placement,
165
+ children
166
+ }
167
+ ) });
168
+ };
169
+ var DELAY_SHOW_TOOLTIP = 300;
170
+ var TooltipRoot = ({ children, delayDuration = DELAY_SHOW_TOOLTIP, ...rest }) => /* @__PURE__ */ jsx(Root$1, { ...rest, delayDuration, children });
171
+ var TooltipTrigger = ({
172
+ ref,
173
+ children,
174
+ className,
175
+ keepOpenOnClick = false,
176
+ onClick,
177
+ onPointerDown,
178
+ asChild,
179
+ ...rest
180
+ }) => {
181
+ const handleClick = (event) => {
182
+ if (keepOpenOnClick) event.preventDefault();
183
+ onClick?.(event);
184
+ };
185
+ const handlePointerDown = (event) => {
186
+ if (keepOpenOnClick) event.preventDefault();
187
+ onPointerDown?.(event);
188
+ };
189
+ return /* @__PURE__ */ jsx(
190
+ Trigger,
191
+ {
192
+ ...rest,
193
+ asChild: true,
194
+ ref,
195
+ className: cn("tailwindcss-preflight", className),
196
+ onClick: handleClick,
197
+ onPointerDown: handlePointerDown,
198
+ children: asChild ? children : (
199
+ // Default-mode trigger wraps children in a span so Radix has a
200
+ // single DOM element to attach handlers to. `tailwindcss-preflight`
201
+ // (merged in via Slot) activates Tailwind's preflight inside the
202
+ // span, which sets `svg { display: block }` — without an inline-flex
203
+ // container that would stack any bare Lucide icon onto its own
204
+ // line. `tw-inline-flex tw-items-center` keeps icon + text aligned.
205
+ /* @__PURE__ */ jsx("span", { className: "tw-inline-flex tw-items-center", children })
206
+ )
207
+ }
208
+ );
209
+ };
210
+ var ACTION_TOOLTIP_LIMIT = 30;
211
+ var Tooltip = ({
212
+ tooltip,
213
+ children,
214
+ className,
215
+ keepOpenOnTriggerClick = false,
216
+ variant,
217
+ argo,
218
+ placement = "right",
219
+ forceHide = false,
220
+ forceShow = false,
221
+ // trigger props
222
+ triggerAsChild = false
223
+ }) => {
224
+ const [open, setOpen] = useState(false);
225
+ const resolvedVariant = (() => {
226
+ if (!!variant) return variant;
227
+ if (typeof tooltip === "string" && tooltip.length > ACTION_TOOLTIP_LIMIT) return "explanatory";
228
+ return "action";
229
+ })();
230
+ const isActionVariant = resolvedVariant === "action";
231
+ const handleKeyUp = (event) => {
232
+ if (![keyCodes.ENTER, keyCodes.SPACE].includes(event.key)) return;
233
+ event.stopPropagation();
234
+ };
235
+ return /* @__PURE__ */ jsxs(
236
+ TooltipRoot,
237
+ {
238
+ open: !!tooltip && (open || forceShow) && !forceHide,
239
+ onOpenChange: setOpen,
240
+ disableHoverableContent: isActionVariant,
241
+ children: [
242
+ /* @__PURE__ */ jsx(
243
+ TooltipTrigger,
244
+ {
245
+ asChild: triggerAsChild,
246
+ keepOpenOnClick: keepOpenOnTriggerClick,
247
+ onKeyUp: handleKeyUp,
248
+ children
249
+ }
250
+ ),
251
+ /* @__PURE__ */ jsx(
252
+ TooltipContent,
253
+ {
254
+ className,
255
+ variant: resolvedVariant,
256
+ argo,
257
+ placement,
258
+ keepOpenOnPointerDownOutside: keepOpenOnTriggerClick,
259
+ children: tooltip
260
+ }
261
+ )
262
+ ]
263
+ }
264
+ );
265
+ };
266
+ Tooltip.Root = TooltipRoot;
267
+ Tooltip.Content = TooltipContent;
268
+ Tooltip.Trigger = TooltipTrigger;
269
+
270
+ // src/utils/escapeStringRegexp.ts
271
+ var escapeStringRegexp = (string) => string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
272
+ var helpVariants = cva(["tw-m-0", "tw-text-xs"], {
273
+ defaultVariants: {
274
+ state: "default"
275
+ },
276
+ variants: {
277
+ state: {
278
+ default: ["tw-text-muted-foreground"],
279
+ error: ["tw-text-destructive"],
280
+ warning: ["tw-text-warning-500"]
281
+ }
282
+ }
283
+ });
284
+ var HelpBlock = ({ children, className, state = "default", testId }) => {
285
+ if (!children) return null;
286
+ return /* @__PURE__ */ jsx("p", { "data-testid": testId, className: helpVariants({ state, className }), children });
287
+ };
288
+
289
+ // src/icons/index.ts
290
+ var icons_exports = {};
291
+ __export(icons_exports, {
292
+ Keboola: () => Keboola
293
+ });
294
+ __reExport(icons_exports, lucide_react_star);
295
+ var Keboola = forwardRef(
296
+ ({ size = 24, color = "currentColor", className, children, ...rest }, ref) => /* @__PURE__ */ jsxs(
297
+ "svg",
298
+ {
299
+ ref,
300
+ xmlns: "http://www.w3.org/2000/svg",
301
+ width: size,
302
+ height: size,
303
+ viewBox: "0 0 300 512",
304
+ fill: color,
305
+ className: cn("lucide", className),
306
+ ...rest,
307
+ children: [
308
+ /* @__PURE__ */ jsx("path", { d: "M152 320C79.7 320 24.5 233.9 24.5 124.7C24.5 15.6 70.5 0 152 0s123.6 15.6 123.6 124.7C275.5 233.9 217.7 320 152 320zm-8.7-50.5c0-11.2-9.5-20.3-21.2-20.3s-21.2 9.1-21.2 20.3c0 11.2 9.5 20.3 21.2 20.3s21.2-9.1 21.2-20.3zm55.7 0c0-11.2-9.5-20.3-21.2-20.3s-21.2 9.1-21.2 20.3c0 11.2 9.5 20.3 21.2 20.3s21.2-9.1 21.2-20.3zm68.9 115.1c10.2 9.3 20.2 20.5 29 35c5.9 9.7 2.6 22.1-7.5 27.8c-3.4 1.9-7.1 2.8-10.7 2.8c-7.2 0-14.3-3.6-18.3-10c-6.8-11.1-13.8-18.9-21.7-26.1c-7.3-6.7-15.6-12.7-24.9-19.5c-.7-.5-1.4-1-2.1-1.5c-5-3.6-10-6.8-14.9-9.4c.6 1 1.2 2.1 1.8 3.2c14.4 26.4 29.2 63.1 29.2 104.9c0 11.2-9.5 20.3-21.2 20.3c-11.7 0-21.2-9.1-21.2-20.3c.1-31.8-11.6-62.3-23.8-84.9c-4-7.4-8-13.9-11.6-19.3c-3.4 5.2-7.2 11.3-11 18.3c-12.5 22.7-24.5 53.8-24.4 86c0 11.2-9.5 20.3-21.2 20.3s-21.2-9.1-21.2-20.3c.1-41.8 14.9-78.4 29.2-104.9c.6-1.1 1.2-2.1 1.8-3.2c-5 2.7-9.9 5.8-14.9 9.4c-.6 .5-1.3 .9-1.9 1.4c-9.5 6.9-17.8 12.9-25.1 19.7c-7.9 7.2-14.9 15.1-21.7 26.1c-5.9 9.7-18.9 12.9-29 7.2C.5 441.8-2.9 429.3 3.1 419.7c8.9-14.4 18.8-25.7 29-35c9.2-8.4 18.5-15.1 27.6-21.7c1-.7 2-1.4 3-2.2c4.7-3.5 9.6-6.7 14.6-9.6c-5-2.9-9.8-6.1-14.6-9.6C39.8 325 19.9 302.5 3.1 275.1c-5.9-9.7-2.6-22.1 7.5-27.8c10.1-5.7 23.1-2.5 29 7.2c14.6 23.7 31.1 42 48.7 54.9c18.9 13.7 37.4 20.5 56.5 21.5c1.7-.1 3.5-.1 5.2-.1c1.8 0 3.5 .1 5.2 .1c0 0 0 0 0 0c19.1-1.1 37.6-7.9 56.5-21.5c17.6-12.8 34.2-31.2 48.7-54.9c6-9.7 18.9-12.9 29-7.2c10.1 5.7 13.4 18.1 7.5 27.8c-16.8 27.4-36.7 49.9-59.6 66.6c-4.7 3.5-9.6 6.7-14.5 9.6c4.9 2.9 9.8 6.1 14.5 9.6c.9 .7 1.8 1.3 2.7 2c9.2 6.7 18.5 13.5 27.9 22z" }),
309
+ children
310
+ ]
311
+ }
312
+ )
313
+ );
314
+ Keboola.displayName = "Keboola";
315
+ var variants = cva(
316
+ [
317
+ "tailwindcss-preflight",
318
+ "tw-group/button",
319
+ "tw-border-box",
320
+ // layout
321
+ "tw-relative",
322
+ "tw-flex",
323
+ "tw-items-center",
324
+ "tw-justify-center",
325
+ "tw-gap-2",
326
+ // text
327
+ "tw-text-xs",
328
+ "tw-leading-5",
329
+ "tw-font-medium",
330
+ "tw-tracking-[1px]",
331
+ "tw-uppercase",
332
+ // border
333
+ "tw-rounded",
334
+ "tw-border",
335
+ "tw-border-transparent",
336
+ // styling
337
+ "tw-shadow-none",
338
+ "[a]:tw-cursor-pointer",
339
+ // explicitly set for anchor
340
+ "focus-visible:tw-outline",
341
+ "focus-visible:tw-outline-1",
342
+ "focus-visible:-tw-outline-offset-1",
343
+ "focus-visible:tw-outline-secondary-500",
344
+ "focus-visible:tw-ring-4",
345
+ "focus-visible:tw-ring-secondary-200",
346
+ // disabled
347
+ "disabled:tw-opacity-40",
348
+ "disabled:tw-cursor-not-allowed",
349
+ // anchor support
350
+ "!tw-no-underline",
351
+ "aria-disabled:tw-opacity-40",
352
+ "aria-disabled:tw-cursor-not-allowed",
353
+ "[&_svg]:tw-shrink-0"
354
+ ],
355
+ {
356
+ defaultVariants: {
357
+ size: "medium",
358
+ variant: "primary",
359
+ block: false
360
+ },
361
+ variants: {
362
+ block: {
363
+ true: ["tw-w-full"]
364
+ },
365
+ variant: {
366
+ primary: [
367
+ "tw-text-white",
368
+ "tw-bg-primary-500",
369
+ "focus:tw-text-white",
370
+ "hover:tw-text-white",
371
+ "hover:not-disabled:tw-bg-primary-600",
372
+ "active:not-disabled:tw-bg-primary-800",
373
+ // anchor disabled override
374
+ "aria-disabled:!tw-bg-primary-500"
375
+ ],
376
+ secondary: [
377
+ "tw-text-white",
378
+ "tw-bg-secondary-500",
379
+ "focus:tw-text-white",
380
+ "hover:tw-text-white",
381
+ "hover:not-disabled:tw-bg-secondary-700",
382
+ "active:not-disabled:tw-bg-secondary-800",
383
+ // anchor disabled override
384
+ "aria-disabled:!tw-bg-secondary-500"
385
+ ],
386
+ danger: [
387
+ "tw-text-white",
388
+ "tw-bg-error-500",
389
+ "focus:tw-text-white",
390
+ "hover:tw-text-white",
391
+ "hover:not-disabled:tw-bg-error-600",
392
+ "active:not-disabled:tw-bg-error-700",
393
+ // anchor disabled override
394
+ "aria-disabled:!tw-bg-error-500"
395
+ ],
396
+ invisible: [
397
+ "tw-text-neutral-800",
398
+ "tw-bg-transparent",
399
+ "focus:tw-text-neutral-800",
400
+ "hover:not-disabled:tw-bg-neutral-100",
401
+ "hover:tw-text-neutral-800",
402
+ "active:not-disabled:tw-bg-neutral-150",
403
+ // contrasting icon on hover/active
404
+ "[&_svg]:tw-text-neutral-400",
405
+ "[&_svg]:hover:not-disabled:tw-text-secondary-600",
406
+ "[&_svg]:active:not-disabled:tw-text-secondary-600",
407
+ // anchor disabled override
408
+ "aria-disabled:!tw-bg-transparent"
409
+ ],
410
+ outline: [
411
+ "tw-text-neutral-800",
412
+ "tw-bg-white",
413
+ // border
414
+ "!tw-border-neutral-200",
415
+ "hover:tw-text-neutral-800",
416
+ "focus:tw-text-neutral-800",
417
+ "hover:not-disabled:!tw-border-neutral-300",
418
+ "hover:not-disabled:tw-bg-neutral-100",
419
+ "active:not-disabled:tw-bg-neutral-200",
420
+ // contrasting icon hover, same as invisible
421
+ "[&_svg]:tw-text-neutral-400",
422
+ "[&_svg]:not-disabled:hover:tw-text-secondary-600",
423
+ "[&_svg]:active:not-disabled:tw-text-secondary-600",
424
+ // anchor disabled override
425
+ "aria-disabled:!tw-bg-white",
426
+ "aria-disabled:!tw-border-neutral-200"
427
+ ],
428
+ inline: [
429
+ "tw-text-neutral-800",
430
+ "tw-bg-transparent",
431
+ "tw-rounded-full",
432
+ "[&_svg]:tw-text-neutral-400",
433
+ "[&_svg]:not-disabled:hover:tw-text-secondary-600",
434
+ "[&_svg]:not-disabled:focus:tw-text-secondary-600"
435
+ ]
436
+ },
437
+ size: {
438
+ medium: [
439
+ "tw-max-h-10",
440
+ "tw-min-h-10",
441
+ "tw-px-4",
442
+ "tw-py-2.5",
443
+ '[&_svg:not([class*="tw-size-"])]:tw-size-4'
444
+ ],
445
+ small: [
446
+ "tw-max-h-8",
447
+ "tw-min-h-8",
448
+ "tw-px-4",
449
+ "tw-py-1.5",
450
+ '[&_svg:not([class*="tw-size-"])]:tw-size-4'
451
+ ],
452
+ large: [
453
+ "tw-max-h-12",
454
+ "tw-min-h-12",
455
+ "tw-px-4",
456
+ "tw-py-3.5",
457
+ '[&_svg:not([class*="tw-size-"])]:tw-size-4'
458
+ ],
459
+ "icon-lg": ["tw-size-12", "tw-p-0", '[&_svg:not([class*="tw-size-"])]:tw-size-6'],
460
+ icon: ["tw-size-10", "tw-p-0", '[&_svg:not([class*="tw-size-"])]:tw-size-4'],
461
+ "icon-sm": ["tw-size-8", "tw-p-0", '[&_svg:not([class*="tw-size-"])]:tw-size-4'],
462
+ "icon-xs": ["tw-size-6", "tw-p-0", '[&_svg:not([class*="tw-size-"])]:tw-size-4'],
463
+ "icon-2xs": [
464
+ "!tw-inline-flex",
465
+ "tw-size-5",
466
+ "tw-max-h-5",
467
+ '[&_svg:not([class*="tw-size-"])]:tw-size-3'
468
+ ],
469
+ "icon-3xs": ["tw-h-fit", "tw-w-fit", '[&_svg:not([class*="tw-size-"])]:tw-size-4']
470
+ }
471
+ }
472
+ }
473
+ );
474
+ var argoVariants = cva(
475
+ [
476
+ "tailwindcss-preflight",
477
+ // layout
478
+ "tw-relative",
479
+ "tw-inline-flex",
480
+ "tw-items-center",
481
+ "tw-justify-center",
482
+ "tw-whitespace-nowrap",
483
+ "tw-gap-2",
484
+ // border
485
+ "tw-border",
486
+ "tw-border-transparent",
487
+ "tw-rounded-lg",
488
+ // text
489
+ "tw-font-medium",
490
+ "tw-select-none",
491
+ // focus visible
492
+ "!tw-outline-none",
493
+ "focus-visible:tw-ring-2",
494
+ // disabled
495
+ "disabled:tw-cursor-not-allowed",
496
+ "disabled:tw-opacity-50",
497
+ "active:tw-opacity-60",
498
+ "tw-transition-all",
499
+ "tw-bg-clip-padding",
500
+ // anchor support
501
+ "!tw-no-underline",
502
+ "aria-disabled:tw-cursor-not-allowed",
503
+ "aria-disabled:tw-opacity-50",
504
+ // icon
505
+ "tw-shrink-0",
506
+ "[&_svg]:tw-pointer-events-none",
507
+ "[&_svg]:tw-shrink-0",
508
+ "[&_svg:not([class*='tw-size-'])]:tw-size-4"
509
+ ],
510
+ {
511
+ defaultVariants: {
512
+ variant: "primary",
513
+ size: "medium"
514
+ },
515
+ variants: {
516
+ block: {
517
+ true: ["tw-w-full"]
518
+ },
519
+ variant: {
520
+ primary: [
521
+ "tw-bg-primary",
522
+ "tw-text-primary-foreground",
523
+ "[a]:hover:tw-bg-primary/80",
524
+ "hover:not-disabled:tw-bg-primary/90",
525
+ "hover:tw-text-primary-foreground",
526
+ "focus:tw-text-primary-foreground",
527
+ "focus-visible:tw-border-primary",
528
+ "focus-visible:tw-ring-primary/50"
529
+ ],
530
+ secondary: [
531
+ "tw-bg-primary/10",
532
+ "tw-text-primary",
533
+ "hover:not-disabled:tw-bg-primary/20",
534
+ "focus-visible:tw-border-primary",
535
+ "focus-visible:tw-ring-primary/50"
536
+ ],
537
+ // should be called "destructive" by Figma
538
+ danger: [
539
+ "tw-bg-destructive",
540
+ "tw-text-destructive-foreground",
541
+ "hover:tw-text-destructive-foreground",
542
+ "focus:tw-text-destructive-foreground",
543
+ "focus-visible:tw-border-destructive",
544
+ "focus-visible:tw-ring-destructive/20"
545
+ ],
546
+ outline: [
547
+ "!tw-border-input",
548
+ "tw-bg-background",
549
+ "hover:not-disabled:tw-bg-accent",
550
+ "hover:not-disabled:tw-text-accent-foreground",
551
+ "hover:active:tw-bg-background",
552
+ "focus-visible:!tw-border-primary",
553
+ "focus-visible:tw-ring-primary/50"
554
+ ],
555
+ // should be called "ghost" by Figma
556
+ invisible: [
557
+ "tw-bg-transparent",
558
+ "tw-text-foreground",
559
+ "hover:not-disabled:tw-bg-accent",
560
+ "hover:not-disabled:tw-text-accent-foreground",
561
+ "hover:not-disabled:tw-border-accent",
562
+ "focus-visible:tw-ring-primary/50"
563
+ ],
564
+ // should be called "link" by Figma
565
+ inline: [
566
+ "tw-bg-transparent",
567
+ "tw-text-primary",
568
+ "hover:tw-underline",
569
+ "hover:active:tw-bg-transparent",
570
+ "focus-visible:tw-ring-primary/50"
571
+ ]
572
+ },
573
+ size: {
574
+ // should be called "default" by Figma
575
+ medium: ["tw-max-h-9", "tw-py-2", "tw-px-4", "tw-text-sm"],
576
+ // should be called "small" by Figma
577
+ small: ["tw-max-h-8", "tw-py-2", "tw-px-3", "tw-text-xs"],
578
+ // should be called "large" by Figma
579
+ large: ["tw-max-h-10", "tw-py-2.5", "tw-px-6", "tw-text-sm"],
580
+ "icon-lg": ["tw-size-10"],
581
+ icon: ["tw-size-9"],
582
+ "icon-sm": ["tw-size-8"],
583
+ // unsupported in ARGO, remove when old design is gone
584
+ "icon-xs": [],
585
+ "icon-2xs": [],
586
+ "icon-3xs": []
587
+ }
588
+ }
589
+ }
590
+ );
591
+ var Button = ({
592
+ ref,
593
+ children,
594
+ disabled = false,
595
+ className,
596
+ type = "button",
597
+ isLoading = false,
598
+ asChild = false,
599
+ onClick,
600
+ argo = false,
601
+ variant = "primary",
602
+ size = "medium",
603
+ block = false,
604
+ ...buttonProps
605
+ }) => {
606
+ const isLegacy = useIsLegacyBrand();
607
+ const renderArgo = !isLegacy || argo;
608
+ const Comp = asChild ? Root : "button";
609
+ const isIconOnly = String(size).startsWith("icon");
610
+ const classNames = renderArgo ? argoVariants({ variant, size, block, className }) : variants({ size, variant, block, className });
611
+ const handleClick = (event) => {
612
+ const isAnchor = event.currentTarget.tagName === "A";
613
+ if (isAnchor && disabled) {
614
+ event.preventDefault();
615
+ return;
616
+ }
617
+ onClick?.(event);
618
+ };
619
+ return /* @__PURE__ */ jsxs(
620
+ Comp,
621
+ {
622
+ ...buttonProps,
623
+ ref,
624
+ disabled,
625
+ "aria-disabled": disabled,
626
+ "data-variant": variant,
627
+ "data-icon-only": isIconOnly,
628
+ type,
629
+ onClick: handleClick,
630
+ className: cn(classNames),
631
+ children: [
632
+ isLoading && /* @__PURE__ */ jsx(icons_exports.Loader2, { className: "tw-size-4 tw-shrink-0 tw-animate-spin" }),
633
+ /* @__PURE__ */ jsx(Slottable, { children: isLoading && isIconOnly ? null : children })
634
+ ]
635
+ }
636
+ );
637
+ };
638
+ var Clipboard = ({
639
+ ref,
640
+ text: textProp,
641
+ children,
642
+ tooltip = "Copy to Clipboard",
643
+ tooltipPlacement = "top",
644
+ tooltipVariant: tooltipVariantProp = "action",
645
+ asChild = false,
646
+ onClick,
647
+ className,
648
+ ...restButtonProps
649
+ }) => {
650
+ const [isTooltipOpen, setIsTooltipOpen] = useState(false);
651
+ const [state, setState] = useState("ready");
652
+ const text = typeof textProp === "function" ? textProp() : textProp;
653
+ const copy = async (text2) => {
654
+ try {
655
+ if (!document.hasFocus()) window.focus();
656
+ await copyToClipboard(text2);
657
+ setState("copied");
658
+ } catch {
659
+ setState("error");
660
+ }
661
+ };
662
+ const handleOnClick = (event) => {
663
+ if (text && state === "ready") void copy(text);
664
+ onClick?.(event);
665
+ };
666
+ const handleOnOpenChange = (open) => {
667
+ if (!open && state !== "ready") setState("ready");
668
+ setIsTooltipOpen(open);
669
+ };
670
+ const tooltipContent = (() => {
671
+ if (!text) return "Nothing to copy";
672
+ if (state === "error") return "Failed to copy";
673
+ if (state === "copied") return "Copied to Clipboard";
674
+ return tooltip;
675
+ })();
676
+ const tooltipVariant = state === "ready" && !!text ? tooltipVariantProp : "action";
677
+ return /* @__PURE__ */ jsxs(Tooltip.Root, { open: isTooltipOpen, onOpenChange: handleOnOpenChange, children: [
678
+ /* @__PURE__ */ jsx(
679
+ Tooltip.Trigger,
680
+ {
681
+ ...restButtonProps,
682
+ asChild,
683
+ keepOpenOnClick: true,
684
+ onClick: handleOnClick,
685
+ className: cn("tw-cursor-pointer", className),
686
+ ref,
687
+ children: children ?? text
688
+ }
689
+ ),
690
+ /* @__PURE__ */ jsx(
691
+ Tooltip.Content,
692
+ {
693
+ keepOpenOnPointerDownOutside: true,
694
+ placement: tooltipPlacement,
695
+ variant: tooltipVariant,
696
+ children: tooltipContent
697
+ }
698
+ )
699
+ ] });
700
+ };
701
+ var DEFAULT_ICON = /* @__PURE__ */ jsx(icons_exports.Copy, {});
702
+ var ClipboardButton = ({
703
+ // clipboard props
704
+ text,
705
+ tooltip,
706
+ tooltipPlacement,
707
+ tooltipVariant,
708
+ // button props
709
+ icon = DEFAULT_ICON,
710
+ variant = "outline",
711
+ children,
712
+ ...rest
713
+ }) => /* @__PURE__ */ jsx(
714
+ Clipboard,
715
+ {
716
+ asChild: true,
717
+ tooltip,
718
+ tooltipPlacement,
719
+ tooltipVariant,
720
+ text,
721
+ children: /* @__PURE__ */ jsxs(Button, { ...rest, variant, disabled: !text, children: [
722
+ icon,
723
+ children
724
+ ] })
725
+ }
726
+ );
727
+ var ButtonToolbar = ({ value, children }) => {
728
+ if (!value && !children) return null;
729
+ return /* @__PURE__ */ jsxs("div", { className: "tw-pointer-events-auto tw-ml-auto tw-mr-4 tw-flex tw-w-fit tw-gap-1 tw-overflow-visible tw-rounded-lg tw-border tw-border-solid tw-border-border !tw-bg-background tw-p-[3px] tw-shadow", children: [
730
+ !!value && /* @__PURE__ */ jsx(ClipboardButton, { size: "icon-sm", variant: "invisible", text: value }),
731
+ children
732
+ ] });
733
+ };
734
+ var baseThemeStyles = {
735
+ "*": { lineHeight: "20px" },
736
+ "*::selection": {
737
+ backgroundColor: colors.secondary[500],
738
+ color: `${colors.white} !important`
739
+ },
740
+ '&.cm-editor:has(.cm-content[contenteditable="false"])': { backgroundColor: colors.neutral[150] },
741
+ '&.cm-editor:has(.cm-content[contenteditable="false"]) .cm-gutters': {
742
+ backgroundColor: colors.neutral[200]
743
+ },
744
+ "&.cm-editor .cm-scroller": { overflowAnchor: "none" },
745
+ "&.cm-editor, &.cm-editor .cm-scroller": {
746
+ minHeight: "100%",
747
+ flexGrow: 1,
748
+ alignItems: "stretch !important",
749
+ outline: "none"
750
+ },
751
+ ".cm-gutter.cm-foldGutter": { display: "none !important" },
752
+ ".cm-gutter.cm-lineNumbers": { paddingLeft: "20px", paddingRight: "6px" },
753
+ ".cm-gutters": { height: "auto" },
754
+ // tokens overrides
755
+ ".cm-line .tok-string": { color: colors.warning[700] },
756
+ // merge (diff) view
757
+ '&[class*="cm-merge-"] .cm-deletedLine': { backgroundColor: colors.error[100] },
758
+ '&[class*="cm-merge-"] .cm-changedLine': { backgroundColor: colors.primary[100] },
759
+ '&[class*="cm-merge-"] .cm-deletedLineGutter': { backgroundColor: colors.error[200] },
760
+ '&[class*="cm-merge-"] .cm-changedLineGutter': { backgroundColor: colors.primary[200] },
761
+ '&[class*="cm-merge-"] .cm-deletedText': { background: colors.error[200] },
762
+ '&[class*="cm-merge-"] .cm-changedText': { background: colors.primary[200] },
763
+ '&[class*="cm-merge-"]': {
764
+ backgroundColor: `${colors.white} !important`
765
+ },
766
+ '&[class*="cm-merge-"] .cm-gutters': {
767
+ backgroundColor: `${colors.white} !important`
768
+ },
769
+ ".cm-changeGutter": { position: "absolute", zIndex: -1, width: "100%", paddingLeft: 0 },
770
+ '&[class*="cm-merge-"] .cm-changedLine,&[class*="cm-merge-"] .cm-line, &[class*="cm-merge-"] .cm-deletedChunk': { paddingLeft: 0 }
771
+ };
772
+ var BASIS_SETUP = { drawSelection: false };
773
+ var customTheme = githubLightInit({
774
+ settings: {
775
+ fontFamily: `'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New'`,
776
+ background: colors.neutral[50],
777
+ gutterBackground: colors.neutral[100],
778
+ gutterBorder: "transparent",
779
+ lineHighlight: "transparent",
780
+ selection: colors.secondary[500]
781
+ }
782
+ });
783
+ var getLanguageMode = (mode) => {
784
+ switch (mode) {
785
+ case "text/x-python":
786
+ return python();
787
+ case "text/x-sql":
788
+ return sql({ upperCaseKeywords: true });
789
+ case "text/x-sfsql":
790
+ return StreamLanguage.define(sfsql);
791
+ case "text/x-plsql":
792
+ return sql({ upperCaseKeywords: true, dialect: PLSQL });
793
+ case "text/x-rsrc":
794
+ return StreamLanguage.define(r);
795
+ case "text/x-sh":
796
+ return StreamLanguage.define(shell);
797
+ case "text/javascript":
798
+ return javascript({ jsx: true });
799
+ case "text/typescript":
800
+ return javascript({ jsx: true, typescript: true });
801
+ default:
802
+ return json();
803
+ }
804
+ };
805
+ var KbdSeparator = ({ className, ...props }) => /* @__PURE__ */ jsx("span", { ...props, className: cn("tw-text-xs tw-text-muted-foreground", className) });
806
+ var KbdGroup = ({
807
+ ref,
808
+ className,
809
+ children,
810
+ separator,
811
+ ...props
812
+ }) => {
813
+ return /* @__PURE__ */ jsx(
814
+ "kbd",
815
+ {
816
+ ...props,
817
+ ref,
818
+ className: cn("tw-inline-flex", "tw-items-center", "tw-gap-1", className),
819
+ children: separator ? (
820
+ // oxlint-disable-next-line react-x/no-children-to-array
821
+ Children.toArray(children).map((child, index) => (
822
+ // oxlint-disable-next-line
823
+ /* @__PURE__ */ jsxs(Fragment$1, { children: [
824
+ index > 0 && /* @__PURE__ */ jsx(KbdSeparator, { children: separator }),
825
+ child
826
+ ] }, index)
827
+ ))
828
+ ) : children
829
+ }
830
+ );
831
+ };
832
+ var kbdVariants = cva(
833
+ [
834
+ "tailwindcss-preflight",
835
+ // style
836
+ "tw-pointer-events-none",
837
+ "tw-w-fit",
838
+ "tw-h-5",
839
+ "tw-min-w-5",
840
+ // layout
841
+ "tw-inline-flex",
842
+ "tw-items-center",
843
+ "tw-justify-center",
844
+ "tw-gap-1",
845
+ "tw-shrink-0",
846
+ // spacing
847
+ "tw-px-1",
848
+ '[&_svg:not([class*="size-"])]:tw-size-2.5',
849
+ "tw-text-xs",
850
+ "tw-font-medium",
851
+ "tw-rounded"
852
+ ],
853
+ {
854
+ defaultVariants: {
855
+ variant: "default"
856
+ },
857
+ variants: {
858
+ variant: {
859
+ default: "tw-bg-muted tw-text-muted-foreground",
860
+ primary: "tw-bg-white/20 tw-text-white"
861
+ }
862
+ }
863
+ }
864
+ );
865
+ var Kbd = ({ children, className, variant, ...rest }) => /* @__PURE__ */ jsx("kbd", { ...rest, className: kbdVariants({ className, variant }), children });
866
+ Kbd.Group = KbdGroup;
867
+ Kbd.Separator = KbdSeparator;
868
+ var ToggleComponentHelp = () => /* @__PURE__ */ jsxs("div", { children: [
869
+ "Use ",
870
+ /* @__PURE__ */ jsx(Kbd, { children: "Ctrl+/" }),
871
+ " or ",
872
+ /* @__PURE__ */ jsx(Kbd, { children: "Command+/" }),
873
+ " to toggle comments."
874
+ ] });
875
+ var emptyArray = [];
876
+ var emptyObject = {};
877
+ var CodeEditor = ({
878
+ value,
879
+ previousValue,
880
+ onChange,
881
+ mode = "application/json",
882
+ placeholder: placeholder$1 = "",
883
+ readOnly = false,
884
+ autocompletions = emptyArray,
885
+ extraKeys = emptyObject,
886
+ withToggleCommentHint = false,
887
+ withAutofocus = false,
888
+ withLineNumbers = true,
889
+ withLineWrapping = true,
890
+ withCollapseUnchanged = false,
891
+ withCopyButton = true,
892
+ completeAny = false,
893
+ help = null,
894
+ helpPostfix = null,
895
+ renderAdditionalButtons,
896
+ className
897
+ }) => {
898
+ const commonExtensions = useMemo(() => {
899
+ return [
900
+ getLanguageMode(mode),
901
+ mode === "application/json" && linter(jsonParseLinter()),
902
+ withLineWrapping ? EditorView.lineWrapping : [],
903
+ EditorState.languageData.of(() => [
904
+ { autocomplete: completeAny ? completeAnyWord : autocompletions }
905
+ ]),
906
+ keymap.of(
907
+ Object.entries(extraKeys).map(([key, run]) => ({
908
+ key,
909
+ run: () => {
910
+ if (typeof run === "string") return run;
911
+ run();
912
+ return true;
913
+ }
914
+ }))
915
+ ),
916
+ autocompletion({ activateOnTyping: completeAny }),
917
+ EditorView.theme(baseThemeStyles)
918
+ ].filter(Boolean);
919
+ }, [autocompletions, completeAny, extraKeys, mode, withLineWrapping]);
920
+ const extensions = useMemo(() => {
921
+ return [
922
+ ...commonExtensions,
923
+ placeholder(placeholder$1),
924
+ EditorView.editable.of(!readOnly),
925
+ EditorState.readOnly.of(readOnly),
926
+ previousValue ? unifiedMergeView({
927
+ original: previousValue,
928
+ mergeControls: false,
929
+ highlightChanges: false,
930
+ collapseUnchanged: withCollapseUnchanged ? {} : void 0
931
+ }) : []
932
+ ];
933
+ }, [commonExtensions, placeholder$1, readOnly, previousValue, withCollapseUnchanged]);
934
+ const config = useMemo(() => {
935
+ return {
936
+ ...BASIS_SETUP,
937
+ lineNumbers: withLineNumbers
938
+ };
939
+ }, [withLineNumbers]);
940
+ return (
941
+ // oxlint-disable-next-line jsx-a11y/no-static-element-interactions
942
+ /* @__PURE__ */ jsxs(
943
+ "div",
944
+ {
945
+ className: cn(
946
+ "tw-relative tw-flex tw-min-h-0 tw-flex-col [&_.cm-mergeViewEditor]:tw-overflow-visible [&_.cm-mergeViewEditors]:tw-h-full [&_.cm-mergeView]:tw-h-full [&_>div]:tw-h-full [&_>div]:tw-overflow-auto [&_>div]:tw-bg-background",
947
+ { "tw-mt-5": !!renderAdditionalButtons },
948
+ className
949
+ ),
950
+ onKeyDown: (event) => {
951
+ if (event.key === keyCodes.ESCAPE) {
952
+ event.stopPropagation();
953
+ }
954
+ },
955
+ children: [
956
+ (withCopyButton || renderAdditionalButtons) && /* @__PURE__ */ jsx("div", { className: "tw-pointer-events-none tw-absolute tw-z-10 tw-flex !tw-h-auto tw-w-full tw-translate-y-[calc(-100%_+_8px)] !tw-overflow-visible !tw-bg-transparent", children: /* @__PURE__ */ jsx("div", { className: "tw-flex-1", children: /* @__PURE__ */ jsx(ButtonToolbar, { value: withCopyButton ? value : void 0, children: renderAdditionalButtons?.(value) }) }) }),
957
+ /* @__PURE__ */ jsx(
958
+ CodeMirror,
959
+ {
960
+ theme: customTheme,
961
+ value,
962
+ onChange,
963
+ extensions,
964
+ autoFocus: withAutofocus,
965
+ basicSetup: config
966
+ }
967
+ ),
968
+ !readOnly && (withToggleCommentHint || help || helpPostfix) && /* @__PURE__ */ jsxs(HelpBlock, { className: "tw-mt-2 tw-flex tw-flex-wrap tw-gap-1", children: [
969
+ help,
970
+ withToggleCommentHint ? /* @__PURE__ */ jsx(ToggleComponentHelp, {}) : null,
971
+ helpPostfix
972
+ ] })
973
+ ]
974
+ }
975
+ )
976
+ );
977
+ };
978
+ var activeQueryFirstLine = Decoration.line({ class: "cm-active-query cm-active-query-first" });
979
+ var activeQueryMiddleLine = Decoration.line({ class: "cm-active-query" });
980
+ var activeQueryLastLine = Decoration.line({ class: "cm-active-query cm-active-query-last" });
981
+ var activeQuerySingleLine = Decoration.line({
982
+ class: "cm-active-query cm-active-query-first cm-active-query-last"
983
+ });
984
+ var findActiveQueryRange = (doc, cursorPos, boundaries) => {
985
+ if (boundaries.length === 0) return null;
986
+ let match = boundaries[boundaries.length - 1];
987
+ for (const boundary of boundaries) {
988
+ if (cursorPos <= boundary.to) {
989
+ match = boundary;
990
+ break;
991
+ }
992
+ }
993
+ if (!match) return null;
994
+ const queryText = doc.slice(match.from, match.to);
995
+ const leadingWhitespace = queryText.length - queryText.trimStart().length;
996
+ const trailingWhitespace = queryText.length - queryText.trimEnd().length;
997
+ const trimmedStart = match.from + leadingWhitespace;
998
+ const trimmedEnd = match.to - trailingWhitespace;
999
+ if (trimmedStart >= trimmedEnd) return null;
1000
+ return { from: trimmedStart, to: trimmedEnd };
1001
+ };
1002
+ var computeBoundaries = (queries) => {
1003
+ const boundaries = [];
1004
+ let offset = 0;
1005
+ for (const query of queries) {
1006
+ boundaries.push({ from: offset, to: offset + query.length });
1007
+ offset += query.length;
1008
+ }
1009
+ return boundaries;
1010
+ };
1011
+ var mapBoundariesThroughChanges = (boundaries, changes) => {
1012
+ const prevLen = changes.length;
1013
+ const mapped = [];
1014
+ for (const b of boundaries) {
1015
+ const from = changes.mapPos(Math.max(0, Math.min(b.from, prevLen)), -1);
1016
+ const to = changes.mapPos(Math.max(0, Math.min(b.to, prevLen)), 1);
1017
+ if (from < to) mapped.push({ from, to });
1018
+ }
1019
+ return mapped;
1020
+ };
1021
+ var buildDecorations = (view, range) => {
1022
+ const startLine = view.state.doc.lineAt(range.from).number;
1023
+ const endLine = view.state.doc.lineAt(range.to).number;
1024
+ const decorations = [];
1025
+ for (let lineNum = startLine; lineNum <= endLine; lineNum++) {
1026
+ const lineStart = view.state.doc.line(lineNum).from;
1027
+ if (startLine === endLine) {
1028
+ decorations.push(activeQuerySingleLine.range(lineStart));
1029
+ } else if (lineNum === startLine) {
1030
+ decorations.push(activeQueryFirstLine.range(lineStart));
1031
+ } else if (lineNum === endLine) {
1032
+ decorations.push(activeQueryLastLine.range(lineStart));
1033
+ } else {
1034
+ decorations.push(activeQueryMiddleLine.range(lineStart));
1035
+ }
1036
+ }
1037
+ return Decoration.set(decorations);
1038
+ };
1039
+ var activeQueryHighlight = (splitQueries) => {
1040
+ return [
1041
+ ViewPlugin.fromClass(
1042
+ class {
1043
+ decorations = Decoration.none;
1044
+ debounceTimer = null;
1045
+ seq = 0;
1046
+ cachedDoc = "";
1047
+ cachedBoundaries = [];
1048
+ destroyed = false;
1049
+ constructor(view) {
1050
+ this.scheduleDocParse(view);
1051
+ }
1052
+ update(update) {
1053
+ if (update.focusChanged && !update.view.hasFocus) {
1054
+ this.decorations = Decoration.none;
1055
+ return;
1056
+ }
1057
+ if (update.docChanged) {
1058
+ if (this.cachedBoundaries.length > 0) {
1059
+ this.cachedBoundaries = mapBoundariesThroughChanges(
1060
+ this.cachedBoundaries,
1061
+ update.changes
1062
+ );
1063
+ this.cachedDoc = update.state.doc.toString();
1064
+ this.updateFromCache(update.view);
1065
+ }
1066
+ this.scheduleDocParse(update.view);
1067
+ } else if (update.selectionSet || update.focusChanged && update.view.hasFocus) {
1068
+ this.updateFromCache(update.view);
1069
+ }
1070
+ }
1071
+ destroy() {
1072
+ this.destroyed = true;
1073
+ if (this.debounceTimer) clearTimeout(this.debounceTimer);
1074
+ }
1075
+ /**
1076
+ * Update decorations using cached query boundaries.
1077
+ * Only mutates this.decorations — does NOT call view.dispatch().
1078
+ * When called from update() (sync), CodeMirror picks up the new
1079
+ * decorations via the accessor. When called from the async
1080
+ * scheduleDocParse callback, the caller must dispatch separately.
1081
+ */
1082
+ updateFromCache(view) {
1083
+ if (!view.hasFocus) {
1084
+ this.decorations = Decoration.none;
1085
+ return;
1086
+ }
1087
+ const { main } = view.state.selection;
1088
+ if (main.from !== main.to) {
1089
+ this.decorations = Decoration.none;
1090
+ return;
1091
+ }
1092
+ const doc = view.state.doc.toString();
1093
+ if (doc !== this.cachedDoc) return;
1094
+ if (this.cachedBoundaries.length === 0) {
1095
+ this.decorations = Decoration.none;
1096
+ return;
1097
+ }
1098
+ const range = findActiveQueryRange(doc, main.head, this.cachedBoundaries);
1099
+ this.decorations = range ? buildDecorations(view, range) : Decoration.none;
1100
+ }
1101
+ /** Parse queries async (debounced) and update decorations. */
1102
+ scheduleDocParse(view) {
1103
+ if (this.debounceTimer) clearTimeout(this.debounceTimer);
1104
+ this.debounceTimer = setTimeout(async () => {
1105
+ const seq = ++this.seq;
1106
+ const doc = view.state.doc.toString();
1107
+ if (!doc.trim()) {
1108
+ this.cachedDoc = doc;
1109
+ this.cachedBoundaries = [];
1110
+ if (this.decorations !== Decoration.none) {
1111
+ this.decorations = Decoration.none;
1112
+ if (!this.destroyed) view.dispatch();
1113
+ }
1114
+ return;
1115
+ }
1116
+ let queries;
1117
+ try {
1118
+ queries = await splitQueries(doc);
1119
+ } catch {
1120
+ return;
1121
+ }
1122
+ if (this.destroyed || seq !== this.seq) return;
1123
+ this.cachedDoc = doc;
1124
+ this.cachedBoundaries = computeBoundaries(queries);
1125
+ this.updateFromCache(view);
1126
+ if (!this.destroyed) view.dispatch();
1127
+ }, 100);
1128
+ }
1129
+ },
1130
+ { decorations: (v) => v.decorations }
1131
+ ),
1132
+ EditorView.baseTheme({
1133
+ ".cm-active-query": {
1134
+ boxShadow: `inset -1px 0 0 0 ${colors.secondary[300]}, inset 1px 0 0 0 ${colors.secondary[300]}`,
1135
+ marginRight: "8px"
1136
+ },
1137
+ ".cm-active-query-first": {
1138
+ boxShadow: `inset -1px 0 0 0 ${colors.secondary[300]}, inset 1px 0 0 0 ${colors.secondary[300]}, inset 0 1px 0 0 ${colors.secondary[300]}`,
1139
+ borderRadius: "4px 4px 0 0"
1140
+ },
1141
+ ".cm-active-query-last": {
1142
+ boxShadow: `inset -1px 0 0 0 ${colors.secondary[300]}, inset 1px 0 0 0 ${colors.secondary[300]}, inset 0 -1px 0 0 ${colors.secondary[300]}`,
1143
+ borderRadius: "0 0 4px 4px"
1144
+ },
1145
+ ".cm-active-query-first.cm-active-query-last": {
1146
+ boxShadow: `inset 0 0 0 1px ${colors.secondary[300]}`,
1147
+ borderRadius: "4px"
1148
+ }
1149
+ })
1150
+ ];
1151
+ };
1152
+
1153
+ // src/components/CodeEditor/highlighting.ts
1154
+ var HighlightMarker = class extends GutterMarker {
1155
+ toDOM() {
1156
+ const marker = document.createElement("div");
1157
+ marker.className = "cm-highlight-marker";
1158
+ return marker;
1159
+ }
1160
+ };
1161
+ var highlightMarker = new HighlightMarker();
1162
+ var forEachLineInRange = (doc, from, to, callback) => {
1163
+ const results = [];
1164
+ const fromLine = Math.max(1, from + 1);
1165
+ const toLine = Math.min(doc.lines, to + 1);
1166
+ for (let i = fromLine; i <= toLine; i++) {
1167
+ const line = doc.line(i);
1168
+ results.push(callback(line.from));
1169
+ }
1170
+ return results;
1171
+ };
1172
+ var setHighlightedLinesEffect = StateEffect.define();
1173
+ var highlightedLinesField = StateField.define({
1174
+ create() {
1175
+ return null;
1176
+ },
1177
+ update(value, transaction) {
1178
+ for (const effect of transaction.effects) {
1179
+ if (effect.is(setHighlightedLinesEffect)) {
1180
+ return effect.value;
1181
+ }
1182
+ }
1183
+ return value;
1184
+ }
1185
+ });
1186
+ var highlightGutter = gutter({
1187
+ class: "cm-highlight-gutter",
1188
+ markers: (view) => {
1189
+ const highlightInfo = view.state.field(highlightedLinesField, false);
1190
+ if (!highlightInfo) {
1191
+ return RangeSet.empty;
1192
+ }
1193
+ const markers = forEachLineInRange(
1194
+ view.state.doc,
1195
+ highlightInfo.from,
1196
+ highlightInfo.to,
1197
+ (lineFrom) => highlightMarker.range(lineFrom)
1198
+ );
1199
+ return RangeSet.of(markers);
1200
+ }
1201
+ });
1202
+ var errorLineDecorations = StateField.define({
1203
+ create() {
1204
+ return Decoration.none;
1205
+ },
1206
+ update(decorations, transaction) {
1207
+ decorations = decorations.map(transaction.changes);
1208
+ for (const effect of transaction.effects) {
1209
+ if (!effect.is(setHighlightedLinesEffect)) {
1210
+ continue;
1211
+ }
1212
+ if (!effect.value || !effect.value.error) {
1213
+ return Decoration.none;
1214
+ }
1215
+ const decorationArray = forEachLineInRange(
1216
+ transaction.state.doc,
1217
+ effect.value.error.from,
1218
+ effect.value.error.to,
1219
+ (lineFrom) => Decoration.line({ class: "cm-error-line" }).range(lineFrom)
1220
+ );
1221
+ return Decoration.set(decorationArray);
1222
+ }
1223
+ return decorations;
1224
+ },
1225
+ provide: (f) => EditorView.decorations.from(f)
1226
+ });
1227
+ var processingLineDecorations = StateField.define({
1228
+ create() {
1229
+ return Decoration.none;
1230
+ },
1231
+ update(decorations, transaction) {
1232
+ decorations = decorations.map(transaction.changes);
1233
+ for (const effect of transaction.effects) {
1234
+ if (!effect.is(setHighlightedLinesEffect)) {
1235
+ continue;
1236
+ }
1237
+ if (!effect.value || !effect.value.processing) {
1238
+ return Decoration.none;
1239
+ }
1240
+ const decorationArray = forEachLineInRange(
1241
+ transaction.state.doc,
1242
+ effect.value.processing.from,
1243
+ effect.value.processing.to,
1244
+ (lineFrom) => Decoration.line({ class: "cm-processing-line" }).range(lineFrom)
1245
+ );
1246
+ return Decoration.set(decorationArray);
1247
+ }
1248
+ return decorations;
1249
+ },
1250
+ provide: (f) => EditorView.decorations.from(f)
1251
+ });
1252
+ var highlightedLinesTheme = EditorView.baseTheme({
1253
+ ".cm-highlight-gutter": {
1254
+ width: "2px",
1255
+ marginRight: "2px"
1256
+ },
1257
+ ".cm-highlight-marker": {
1258
+ width: "2px",
1259
+ height: "100%",
1260
+ backgroundColor: colors.secondary[500]
1261
+ },
1262
+ ".cm-error-line": {
1263
+ backgroundColor: `${colors.error[100]} !important`
1264
+ },
1265
+ ".cm-processing-line": {
1266
+ backgroundColor: `${colors.secondary[100]} !important`
1267
+ }
1268
+ });
1269
+ function highlightingExtension(queryParser) {
1270
+ return [
1271
+ highlightedLinesField,
1272
+ highlightGutter,
1273
+ errorLineDecorations,
1274
+ processingLineDecorations,
1275
+ highlightedLinesTheme,
1276
+ ...queryParser ? activeQueryHighlight(queryParser) : []
1277
+ ];
1278
+ }
1279
+ function updateHighlighting(view, lines) {
1280
+ view.dispatch({ effects: setHighlightedLinesEffect.of(lines ?? null) });
1281
+ }
1282
+ var setSearchEffect = StateEffect.define();
1283
+ function findMatches(doc, query) {
1284
+ if (!query) return [];
1285
+ const text = doc.toString();
1286
+ try {
1287
+ const regex = new RegExp(escapeStringRegexp(query), "gi");
1288
+ return Array.from(text.matchAll(regex)).map((match, index) => {
1289
+ const from = match.index;
1290
+ const to = from + match[0].length;
1291
+ return { from, to, text: match[0], localIndex: index };
1292
+ });
1293
+ } catch (e) {
1294
+ console.warn("Invalid search regex:", e);
1295
+ return [];
1296
+ }
1297
+ }
1298
+ function createDecorations(matches, selectedLocalIndex) {
1299
+ const decorations = matches.map((match) => {
1300
+ const isSelected = match.localIndex === selectedLocalIndex;
1301
+ const decoration = Decoration.mark({
1302
+ class: isSelected ? "cm-searchMatch-selected" : "cm-searchMatch"
1303
+ });
1304
+ return decoration.range(match.from, match.to);
1305
+ });
1306
+ return Decoration.set(decorations, true);
1307
+ }
1308
+ var searchField = StateField.define({
1309
+ create() {
1310
+ return {
1311
+ query: "",
1312
+ selectedMatchIndex: void 0,
1313
+ matches: [],
1314
+ decorations: Decoration.none
1315
+ };
1316
+ },
1317
+ update(state, tr) {
1318
+ let newState = state;
1319
+ for (const effect of tr.effects) {
1320
+ if (!effect.is(setSearchEffect)) {
1321
+ continue;
1322
+ }
1323
+ const { query, selectedMatchIndex } = effect.value;
1324
+ const matches = findMatches(tr.state.doc, query);
1325
+ const decorations = createDecorations(matches, selectedMatchIndex);
1326
+ newState = {
1327
+ query,
1328
+ selectedMatchIndex,
1329
+ matches,
1330
+ decorations
1331
+ };
1332
+ }
1333
+ if (tr.docChanged && newState.query) {
1334
+ const matches = findMatches(tr.state.doc, newState.query);
1335
+ const decorations = createDecorations(matches, newState.selectedMatchIndex);
1336
+ newState = {
1337
+ ...newState,
1338
+ matches,
1339
+ decorations
1340
+ };
1341
+ }
1342
+ return newState;
1343
+ },
1344
+ provide: (field) => EditorView.decorations.from(field, (state) => state.decorations)
1345
+ });
1346
+ var searchViewPlugin = ViewPlugin.fromClass(
1347
+ class {
1348
+ lastSelectedIndex;
1349
+ update(update) {
1350
+ const state = update.state.field(searchField);
1351
+ if (state.selectedMatchIndex !== void 0 && state.selectedMatchIndex !== this.lastSelectedIndex) {
1352
+ const match = state.matches[state.selectedMatchIndex];
1353
+ if (match) {
1354
+ requestAnimationFrame(() => {
1355
+ update.view.dispatch({
1356
+ effects: EditorView.scrollIntoView(match.from, { y: "center" })
1357
+ });
1358
+ });
1359
+ }
1360
+ this.lastSelectedIndex = state.selectedMatchIndex;
1361
+ }
1362
+ if (state.selectedMatchIndex === void 0) {
1363
+ this.lastSelectedIndex = void 0;
1364
+ }
1365
+ }
1366
+ }
1367
+ );
1368
+ var searchTheme = EditorView.baseTheme({
1369
+ ".cm-searchMatch": {
1370
+ backgroundColor: colors.secondary[100]
1371
+ },
1372
+ ".cm-searchMatch > span": {
1373
+ color: `${colors.secondary[600]} !important`
1374
+ },
1375
+ ".cm-searchMatch-selected": {
1376
+ backgroundColor: colors.secondary[600]
1377
+ },
1378
+ ".cm-searchMatch-selected > span": {
1379
+ color: `${colors.white} !important`
1380
+ }
1381
+ });
1382
+ function searchExtension() {
1383
+ return [searchField, searchViewPlugin, searchTheme];
1384
+ }
1385
+ function updateSearch(view, query, selectedMatchIndex) {
1386
+ view.dispatch({ effects: setSearchEffect.of({ query, selectedMatchIndex }) });
1387
+ }
1388
+ var BASIS_SETUP2 = {
1389
+ drawSelection: false,
1390
+ defaultKeymap: false,
1391
+ completionKeymap: false,
1392
+ searchKeymap: false
1393
+ };
1394
+ var CUSTOM_KEYMAP = [
1395
+ {
1396
+ key: "Escape",
1397
+ stopPropagation: true,
1398
+ run: (view) => {
1399
+ view.contentDOM.blur();
1400
+ return true;
1401
+ }
1402
+ }
1403
+ ];
1404
+ var theme = {
1405
+ ...baseThemeStyles,
1406
+ "&.cm-editor": {
1407
+ border: "solid 1px transparent",
1408
+ background: colors.white,
1409
+ borderRadius: "8px",
1410
+ paddingTop: "8px",
1411
+ paddingBottom: "8px"
1412
+ },
1413
+ '&.cm-editor:has(.cm-content[contenteditable="true"]):hover': {
1414
+ borderColor: colors.secondary[500]
1415
+ },
1416
+ '&.cm-editor:has(.cm-content[contenteditable="true"]):focus-within': {
1417
+ borderColor: colors.secondary[500],
1418
+ boxShadow: `0 0 0 4px ${colors.secondary[200]}`
1419
+ },
1420
+ "&.cm-editor .cm-scroller": { overflowAnchor: "none" },
1421
+ "&.cm-editor :is(.cm-gutters,.cm-scroller)": { background: colors.white },
1422
+ '&.cm-editor:has(.cm-content[contenteditable="false"])': { background: colors.neutral[100] },
1423
+ '&.cm-editor:has(.cm-content[contenteditable="false"]) :is(.cm-scroller,.cm-gutters)': {
1424
+ background: colors.neutral[100]
1425
+ }
1426
+ };
1427
+ var SqlEditor = ({
1428
+ value,
1429
+ onChange,
1430
+ onSelectionChange,
1431
+ onCreateEditor,
1432
+ onDestroyEditor,
1433
+ onBlurEditor,
1434
+ onFocusEditor,
1435
+ placeholder = "",
1436
+ searchQuery = "",
1437
+ searchMatchIndex,
1438
+ readOnly = false,
1439
+ extraKeys,
1440
+ queryParser,
1441
+ autoFocus = false,
1442
+ lineNumbers = true,
1443
+ className,
1444
+ schema,
1445
+ variables,
1446
+ defaultDatabase,
1447
+ defaultSchema,
1448
+ highlightLines,
1449
+ dialect
1450
+ }) => {
1451
+ const editorRef = useRef(null);
1452
+ const extensions = useMemo(() => {
1453
+ const baseKeymap = [...defaultKeymap, ...CUSTOM_KEYMAP];
1454
+ return [
1455
+ EditorView$1.lineWrapping,
1456
+ keymap$1.of(extraKeys ? [...extraKeys, ...baseKeymap] : baseKeymap),
1457
+ ...installExtensions({ schema, defaultDatabase, defaultSchema, variables, dialect }),
1458
+ searchExtension(),
1459
+ highlightingExtension(queryParser),
1460
+ EditorView$1.theme(theme),
1461
+ onBlurEditor ? EditorView$1.domEventHandlers({ blur: (_, view) => onBlurEditor(view) }) : [],
1462
+ onFocusEditor ? EditorView$1.domEventHandlers({ focus: (_, view) => onFocusEditor(view) }) : []
1463
+ ];
1464
+ }, [
1465
+ extraKeys,
1466
+ queryParser,
1467
+ schema,
1468
+ defaultDatabase,
1469
+ defaultSchema,
1470
+ variables,
1471
+ dialect,
1472
+ onBlurEditor,
1473
+ onFocusEditor
1474
+ ]);
1475
+ const defaultSetup = useMemo(() => {
1476
+ return { ...BASIS_SETUP2, lineNumbers };
1477
+ }, [lineNumbers]);
1478
+ useEffect(() => {
1479
+ if (editorRef.current?.view) {
1480
+ updateHighlighting(editorRef.current.view, highlightLines);
1481
+ }
1482
+ }, [highlightLines]);
1483
+ useEffect(() => {
1484
+ if (editorRef.current?.view) {
1485
+ updateSearch(editorRef.current.view, searchQuery, searchMatchIndex);
1486
+ }
1487
+ }, [searchQuery, searchMatchIndex]);
1488
+ useEffect(() => {
1489
+ if (!onDestroyEditor) return;
1490
+ return () => {
1491
+ onDestroyEditor();
1492
+ };
1493
+ }, [onDestroyEditor]);
1494
+ const handleOnCreate = useCallback(
1495
+ (view, state) => {
1496
+ onCreateEditor?.(view, state);
1497
+ if (highlightLines) {
1498
+ updateHighlighting(view, highlightLines);
1499
+ }
1500
+ if (searchQuery) {
1501
+ updateSearch(view, searchQuery, searchMatchIndex);
1502
+ }
1503
+ },
1504
+ [onCreateEditor, highlightLines, searchQuery, searchMatchIndex]
1505
+ );
1506
+ const handleOnUpdate = useCallback(
1507
+ (update) => {
1508
+ if (update.selectionSet) {
1509
+ const { main } = update.state.selection;
1510
+ const text = update.state.sliceDoc(main.from, main.to);
1511
+ onSelectionChange?.(text);
1512
+ }
1513
+ },
1514
+ [onSelectionChange]
1515
+ );
1516
+ return /* @__PURE__ */ jsx(
1517
+ CodeMirror,
1518
+ {
1519
+ ref: editorRef,
1520
+ theme: customTheme,
1521
+ extensions,
1522
+ value,
1523
+ onChange,
1524
+ onUpdate: handleOnUpdate,
1525
+ onCreateEditor: handleOnCreate,
1526
+ autoFocus,
1527
+ placeholder,
1528
+ className,
1529
+ readOnly,
1530
+ editable: !readOnly,
1531
+ basicSetup: defaultSetup
1532
+ }
1533
+ );
1534
+ };
1535
+
1536
+ // src/components/MergeEditor/constants.ts
1537
+ var CHANGE_CLASS = {
1538
+ SAFE: "safe"};
1539
+ var LINE_HEIGHT_PX = 20;
1540
+ var PANE_HEADER_HEIGHT_PX = 58;
1541
+ var AcceptButton = ({ side, onAccept, argo }) => {
1542
+ const label = `Accept ${side === "left" ? "production" : "branch"} version`;
1543
+ const Chevron = side === "left" ? icons_exports.ChevronsRight : icons_exports.ChevronsLeft;
1544
+ return /* @__PURE__ */ jsx(
1545
+ Button,
1546
+ {
1547
+ onClick: onAccept,
1548
+ variant: "outline",
1549
+ size: "icon-sm",
1550
+ title: label,
1551
+ "aria-label": label,
1552
+ argo,
1553
+ children: /* @__PURE__ */ jsx(Chevron, { className: "tw-size-5" })
1554
+ }
1555
+ );
1556
+ };
1557
+ var AcceptControls = ({
1558
+ conflicts,
1559
+ side,
1560
+ onAccept,
1561
+ onDismiss,
1562
+ contentRef,
1563
+ argo
1564
+ }) => /* @__PURE__ */ jsx(
1565
+ "div",
1566
+ {
1567
+ className: cn(
1568
+ "tw-z-10 tw-flex tw-shrink-0 tw-flex-col tw-items-center",
1569
+ conflicts.length > 0 ? "tw-w-7" : "tw-w-0"
1570
+ ),
1571
+ children: conflicts.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1572
+ /* @__PURE__ */ jsx("div", { className: "tw-shrink-0", style: { height: `${PANE_HEADER_HEIGHT_PX}px` } }),
1573
+ /* @__PURE__ */ jsx("div", { className: "tw-relative tw-w-full tw-flex-1 tw-overflow-y-clip tw-overflow-x-visible", children: /* @__PURE__ */ jsx("div", { ref: contentRef, className: "tw-relative tw-size-full", children: conflicts.map((conflict) => {
1574
+ const topLine = side === "left" ? conflict.oldStartLine : conflict.newStartLine;
1575
+ const topOffset = (topLine - 1) * LINE_HEIGHT_PX - 2;
1576
+ return /* @__PURE__ */ jsxs(
1577
+ "div",
1578
+ {
1579
+ className: "tw-absolute tw-inset-x-0 tw-flex tw-flex-col tw-items-center tw-gap-0.5",
1580
+ style: { top: `${topOffset}px` },
1581
+ children: [
1582
+ /* @__PURE__ */ jsx(AcceptButton, { side, onAccept: () => onAccept(conflict), argo }),
1583
+ onDismiss && /* @__PURE__ */ jsx(
1584
+ Button,
1585
+ {
1586
+ onClick: () => onDismiss(conflict),
1587
+ variant: "outline",
1588
+ size: "icon-sm",
1589
+ title: "Dismiss",
1590
+ "aria-label": `Dismiss ${side === "left" ? "production" : "branch"} change`,
1591
+ argo,
1592
+ children: /* @__PURE__ */ jsx(icons_exports.X, { className: "tw-size-4" })
1593
+ }
1594
+ )
1595
+ ]
1596
+ },
1597
+ conflict.id
1598
+ );
1599
+ }) }) })
1600
+ ] })
1601
+ }
1602
+ );
1603
+ var setHighlightedLines = StateEffect.define();
1604
+ var safeDecoration = Decoration.line({ class: "cm-merge-safe-line" });
1605
+ var conflictDecoration = Decoration.line({ class: "cm-merge-conflict-line" });
1606
+ var SafeGutterMarker = class extends GutterMarker {
1607
+ elementClass = "cm-merge-safe-gutter";
1608
+ };
1609
+ var ConflictGutterMarker = class extends GutterMarker {
1610
+ elementClass = "cm-merge-conflict-gutter";
1611
+ };
1612
+ var safeGutterMarker = new SafeGutterMarker();
1613
+ var conflictGutterMarker = new ConflictGutterMarker();
1614
+ var createDiffHighlightExtension = () => {
1615
+ const field = StateField.define({
1616
+ create: () => ({ decorations: Decoration.none, gutterMarkers: RangeSet.empty }),
1617
+ update(value, tr) {
1618
+ let payload = null;
1619
+ for (const effect of tr.effects) {
1620
+ if (effect.is(setHighlightedLines)) {
1621
+ payload = effect.value;
1622
+ }
1623
+ }
1624
+ if (!payload) {
1625
+ return {
1626
+ decorations: value.decorations.map(tr.changes),
1627
+ gutterMarkers: value.gutterMarkers.map(tr.changes)
1628
+ };
1629
+ }
1630
+ const decoBuilder = new RangeSetBuilder();
1631
+ const gutterBuilder = new RangeSetBuilder();
1632
+ const doc = tr.state.doc;
1633
+ const { lines, classification } = payload;
1634
+ const sorted = [...lines].filter((l) => l >= 1 && l <= doc.lines).sort((a, b) => a - b);
1635
+ for (const i of sorted) {
1636
+ const cls = classification.get(i);
1637
+ if (!cls) continue;
1638
+ const isSafe = cls === CHANGE_CLASS.SAFE;
1639
+ const line = doc.line(i);
1640
+ decoBuilder.add(line.from, line.from, isSafe ? safeDecoration : conflictDecoration);
1641
+ gutterBuilder.add(line.from, line.from, isSafe ? safeGutterMarker : conflictGutterMarker);
1642
+ }
1643
+ return {
1644
+ decorations: decoBuilder.finish(),
1645
+ gutterMarkers: gutterBuilder.finish()
1646
+ };
1647
+ },
1648
+ provide: (f) => [
1649
+ EditorView.decorations.from(f, (val) => val.decorations),
1650
+ gutterLineClass.from(f, (val) => val.gutterMarkers)
1651
+ ]
1652
+ });
1653
+ const theme2 = EditorView.theme({
1654
+ ".cm-merge-safe-line": {
1655
+ backgroundColor: `${colors.primary[100]} !important`,
1656
+ boxShadow: `inset 3px 0 0 ${colors.primary[500]}`
1657
+ },
1658
+ ".cm-merge-conflict-line": {
1659
+ backgroundColor: `${colors.warning[100]} !important`,
1660
+ boxShadow: `inset 3px 0 0 ${colors.warning[500]}`
1661
+ },
1662
+ ".cm-merge-safe-gutter": {
1663
+ backgroundColor: `${colors.primary[200]} !important`
1664
+ },
1665
+ ".cm-merge-conflict-gutter": {
1666
+ backgroundColor: `${colors.warning[200]} !important`
1667
+ }
1668
+ });
1669
+ return [field, theme2];
1670
+ };
1671
+ var updateHighlightedLines = (view, lines, classification) => {
1672
+ view.dispatch({ effects: setHighlightedLines.of({ lines, classification }) });
1673
+ };
1674
+ var EMPTY_LINES = /* @__PURE__ */ new Set();
1675
+ var EMPTY_CLASSIFICATION = /* @__PURE__ */ new Map();
1676
+ var MergePane = ({
1677
+ value,
1678
+ highlightedLines,
1679
+ lineClassification,
1680
+ readOnly = false,
1681
+ onChange,
1682
+ header,
1683
+ headerClassName,
1684
+ className,
1685
+ onScrollDOMReady,
1686
+ deleted = false
1687
+ }) => {
1688
+ const editorRef = useRef(null);
1689
+ const extensions = useMemo(
1690
+ () => [
1691
+ createDiffHighlightExtension(),
1692
+ EditorView.theme({
1693
+ "&.cm-editor": {
1694
+ height: "100%",
1695
+ backgroundColor: deleted ? colors.error[100] : colors.neutral[50],
1696
+ outline: "none"
1697
+ },
1698
+ ".cm-gutters": {
1699
+ backgroundColor: deleted ? colors.error[200] : colors.neutral[100]
1700
+ },
1701
+ "*": { lineHeight: `${LINE_HEIGHT_PX}px` },
1702
+ ".cm-lineNumbers .cm-gutterElement": { padding: "0 0 0 25px" }
1703
+ }),
1704
+ // Recalc viewport after every doc change so late-settling layouts (alerts
1705
+ // appearing above the editor) don't leave trailing lines blank.
1706
+ EditorView.updateListener.of((update) => {
1707
+ if (update.docChanged) {
1708
+ requestAnimationFrame(() => update.view.dispatch({}));
1709
+ }
1710
+ })
1711
+ ],
1712
+ [deleted]
1713
+ );
1714
+ useEffect(() => {
1715
+ const view = editorRef.current?.view;
1716
+ if (!view) return;
1717
+ updateHighlightedLines(
1718
+ view,
1719
+ deleted ? EMPTY_LINES : highlightedLines,
1720
+ deleted ? EMPTY_CLASSIFICATION : lineClassification
1721
+ );
1722
+ }, [highlightedLines, lineClassification, deleted]);
1723
+ const handleCreateEditor = useCallback(
1724
+ (view) => {
1725
+ updateHighlightedLines(
1726
+ view,
1727
+ deleted ? EMPTY_LINES : highlightedLines,
1728
+ deleted ? EMPTY_CLASSIFICATION : lineClassification
1729
+ );
1730
+ onScrollDOMReady?.(view.scrollDOM);
1731
+ },
1732
+ [highlightedLines, lineClassification, onScrollDOMReady, deleted]
1733
+ );
1734
+ useEffect(() => {
1735
+ return () => onScrollDOMReady?.(null);
1736
+ }, [onScrollDOMReady]);
1737
+ useEffect(() => {
1738
+ const view = editorRef.current?.view;
1739
+ const wrapper = view?.dom.parentElement;
1740
+ if (!view || !wrapper) return;
1741
+ const observer = new ResizeObserver(() => view.dispatch({}));
1742
+ observer.observe(wrapper);
1743
+ return () => observer.disconnect();
1744
+ }, []);
1745
+ return /* @__PURE__ */ jsxs(
1746
+ "div",
1747
+ {
1748
+ className: cn(
1749
+ "tw-flex tw-min-w-0 tw-flex-1 tw-flex-col tw-overflow-hidden",
1750
+ className,
1751
+ deleted && "tw-border-error-300"
1752
+ ),
1753
+ children: [
1754
+ header && /* @__PURE__ */ jsx(
1755
+ "div",
1756
+ {
1757
+ className: cn(
1758
+ "tw-px-4 tw-py-3",
1759
+ deleted ? "tw-border-b tw-border-error-200 tw-bg-error-100" : "tw-bg-background",
1760
+ headerClassName
1761
+ ),
1762
+ children: header
1763
+ }
1764
+ ),
1765
+ /* @__PURE__ */ jsx("div", { className: "tw-flex tw-h-0 tw-flex-1 tw-flex-col [&_>div]:tw-h-full", children: /* @__PURE__ */ jsx(
1766
+ CodeMirror,
1767
+ {
1768
+ ref: editorRef,
1769
+ height: "100%",
1770
+ value,
1771
+ onChange,
1772
+ extensions,
1773
+ readOnly,
1774
+ onCreateEditor: handleCreateEditor,
1775
+ basicSetup: { lineNumbers: true, drawSelection: false }
1776
+ }
1777
+ ) })
1778
+ ]
1779
+ }
1780
+ );
1781
+ };
1782
+ var useScrollSync = () => {
1783
+ const scrollersRef = useRef([]);
1784
+ const followersRef = useRef(/* @__PURE__ */ new Map());
1785
+ const isSyncingRef = useRef(false);
1786
+ const scrollerCallbacksRef = useRef(/* @__PURE__ */ new Map());
1787
+ const followerCallbacksRef = useRef(/* @__PURE__ */ new Map());
1788
+ const updateFollowers = useCallback(() => {
1789
+ for (const [, { paneIndex, el }] of followersRef.current) {
1790
+ const scroller = scrollersRef.current[paneIndex];
1791
+ if (!scroller) continue;
1792
+ el.style.transform = `translateY(-${scroller.scrollTop}px)`;
1793
+ }
1794
+ }, []);
1795
+ const handleScroll = useCallback(
1796
+ (e) => {
1797
+ if (isSyncingRef.current) return;
1798
+ isSyncingRef.current = true;
1799
+ const sourceScrollTop = e.target.scrollTop;
1800
+ for (const scroller of scrollersRef.current) {
1801
+ if (!scroller || scroller === e.target) continue;
1802
+ const targetMax = Math.max(0, scroller.scrollHeight - scroller.clientHeight);
1803
+ scroller.scrollTop = Math.min(sourceScrollTop, targetMax);
1804
+ }
1805
+ updateFollowers();
1806
+ isSyncingRef.current = false;
1807
+ },
1808
+ [updateFollowers]
1809
+ );
1810
+ const registerScroller = useCallback(
1811
+ (index) => {
1812
+ const existing = scrollerCallbacksRef.current.get(index);
1813
+ if (existing) return existing;
1814
+ const callback = (el) => {
1815
+ const prev = scrollersRef.current[index];
1816
+ if (prev === el) return;
1817
+ prev?.removeEventListener("scroll", handleScroll);
1818
+ scrollersRef.current[index] = el;
1819
+ el?.addEventListener("scroll", handleScroll, { passive: true });
1820
+ };
1821
+ scrollerCallbacksRef.current.set(index, callback);
1822
+ return callback;
1823
+ },
1824
+ [handleScroll]
1825
+ );
1826
+ const registerFollower = useCallback((paneIndex, key) => {
1827
+ const existing = followerCallbacksRef.current.get(key);
1828
+ if (existing) return existing;
1829
+ const callback = (el) => {
1830
+ if (el) {
1831
+ followersRef.current.set(key, { paneIndex, el });
1832
+ } else {
1833
+ followersRef.current.delete(key);
1834
+ }
1835
+ };
1836
+ followerCallbacksRef.current.set(key, callback);
1837
+ return callback;
1838
+ }, []);
1839
+ return { registerScroller, registerFollower };
1840
+ };
1841
+ var EMPTY_LINES2 = /* @__PURE__ */ new Set();
1842
+ var EMPTY_CLASSIFICATION2 = /* @__PURE__ */ new Map();
1843
+ var MergeEditor = ({
1844
+ mergeValue,
1845
+ handleMergeChange,
1846
+ leftText,
1847
+ rightText,
1848
+ leftConflicts,
1849
+ rightConflicts,
1850
+ leftHighlightedLines,
1851
+ rightHighlightedLines,
1852
+ leftClassification,
1853
+ rightClassification,
1854
+ mergeHighlightedLines,
1855
+ mergeClassification,
1856
+ acceptLeft,
1857
+ acceptRight,
1858
+ dismissLeft,
1859
+ dismissRight,
1860
+ leftHeader,
1861
+ middleHeader,
1862
+ middleHeaderClassName,
1863
+ middleClassName,
1864
+ rightHeader,
1865
+ className,
1866
+ argo,
1867
+ leftDeleted = false,
1868
+ rightDeleted = false
1869
+ }) => {
1870
+ const { registerScroller, registerFollower } = useScrollSync();
1871
+ const anySideDeleted = leftDeleted || rightDeleted;
1872
+ return /* @__PURE__ */ jsxs(
1873
+ "div",
1874
+ {
1875
+ className: cn(
1876
+ "tw-flex tw-h-full tw-min-h-0 tw-overflow-hidden tw-bg-background tw-gap-3",
1877
+ className
1878
+ ),
1879
+ children: [
1880
+ /* @__PURE__ */ jsx(
1881
+ MergePane,
1882
+ {
1883
+ value: leftText,
1884
+ highlightedLines: leftHighlightedLines,
1885
+ lineClassification: leftClassification,
1886
+ readOnly: true,
1887
+ header: leftHeader,
1888
+ className: "tw-rounded-r-lg tw-border tw-border-border",
1889
+ onScrollDOMReady: registerScroller(0),
1890
+ deleted: leftDeleted
1891
+ }
1892
+ ),
1893
+ /* @__PURE__ */ jsx(
1894
+ AcceptControls,
1895
+ {
1896
+ conflicts: leftDeleted ? [] : leftConflicts,
1897
+ side: "left",
1898
+ onAccept: acceptLeft,
1899
+ onDismiss: dismissLeft,
1900
+ contentRef: registerFollower(0, "left-controls"),
1901
+ argo
1902
+ }
1903
+ ),
1904
+ /* @__PURE__ */ jsx(
1905
+ MergePane,
1906
+ {
1907
+ value: mergeValue,
1908
+ highlightedLines: anySideDeleted ? EMPTY_LINES2 : mergeHighlightedLines,
1909
+ lineClassification: anySideDeleted ? EMPTY_CLASSIFICATION2 : mergeClassification,
1910
+ onChange: handleMergeChange,
1911
+ header: middleHeader,
1912
+ headerClassName: middleHeaderClassName,
1913
+ className: cn("tw-border tw-border-border tw-rounded-lg", middleClassName),
1914
+ onScrollDOMReady: registerScroller(1)
1915
+ }
1916
+ ),
1917
+ /* @__PURE__ */ jsx(
1918
+ AcceptControls,
1919
+ {
1920
+ conflicts: rightDeleted ? [] : rightConflicts,
1921
+ side: "right",
1922
+ onAccept: acceptRight,
1923
+ onDismiss: dismissRight,
1924
+ contentRef: registerFollower(2, "right-controls"),
1925
+ argo
1926
+ }
1927
+ ),
1928
+ /* @__PURE__ */ jsx(
1929
+ MergePane,
1930
+ {
1931
+ value: rightText,
1932
+ highlightedLines: rightHighlightedLines,
1933
+ lineClassification: rightClassification,
1934
+ readOnly: true,
1935
+ header: rightHeader,
1936
+ className: "tw-rounded-l-lg tw-border tw-border-border",
1937
+ onScrollDOMReady: registerScroller(2),
1938
+ deleted: rightDeleted
1939
+ }
1940
+ )
1941
+ ]
1942
+ }
1943
+ );
1944
+ };
1945
+
1946
+ export { CodeEditor, MergeEditor, SqlEditor };
1947
+ //# sourceMappingURL=editors.js.map
1948
+ //# sourceMappingURL=editors.js.map