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