@keboola/design 3.2.3 → 4.1.1

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