@keboola/design 9.0.0 → 10.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/AGENTS.md +117 -40
  2. package/COMPONENT-API.md +31 -9
  3. package/README.md +3 -3
  4. package/dist/MermaidDiagram-EOKJHQQV.js +10 -0
  5. package/dist/MermaidDiagram-EOKJHQQV.js.map +1 -0
  6. package/dist/charts.d.ts +31 -2
  7. package/dist/charts.js +6 -9
  8. package/dist/charts.js.map +1 -1
  9. package/dist/chunk-63NSN2VL.js +274 -0
  10. package/dist/chunk-63NSN2VL.js.map +1 -0
  11. package/dist/{rjsf.cjs → chunk-6FPEI4EM.js} +1560 -5712
  12. package/dist/chunk-6FPEI4EM.js.map +1 -0
  13. package/dist/chunk-7PUUHEJQ.js +1313 -0
  14. package/dist/chunk-7PUUHEJQ.js.map +1 -0
  15. package/dist/chunk-BOHNXTMM.js +606 -0
  16. package/dist/chunk-BOHNXTMM.js.map +1 -0
  17. package/dist/{testing.cjs → chunk-C3L3TBBT.js} +33 -164
  18. package/dist/chunk-C3L3TBBT.js.map +1 -0
  19. package/dist/chunk-CTCFYWJC.js +407 -0
  20. package/dist/chunk-CTCFYWJC.js.map +1 -0
  21. package/dist/chunk-ESBL3IPF.js +23 -0
  22. package/dist/chunk-ESBL3IPF.js.map +1 -0
  23. package/dist/chunk-IJTHFNNJ.js +261 -0
  24. package/dist/chunk-IJTHFNNJ.js.map +1 -0
  25. package/dist/chunk-JP7PNHLH.js +40 -0
  26. package/dist/chunk-JP7PNHLH.js.map +1 -0
  27. package/dist/chunk-KPNAW5MU.js +229 -0
  28. package/dist/chunk-KPNAW5MU.js.map +1 -0
  29. package/dist/chunk-L37JJ6MR.js +152 -0
  30. package/dist/chunk-L37JJ6MR.js.map +1 -0
  31. package/dist/chunk-Q7NWXLCT.js +90 -0
  32. package/dist/chunk-Q7NWXLCT.js.map +1 -0
  33. package/dist/chunk-SYIEF644.js +1016 -0
  34. package/dist/chunk-SYIEF644.js.map +1 -0
  35. package/dist/chunk-VMFSRV5H.js +16 -0
  36. package/dist/chunk-VMFSRV5H.js.map +1 -0
  37. package/dist/chunk-VPPM7UUQ.js +47 -0
  38. package/dist/chunk-VPPM7UUQ.js.map +1 -0
  39. package/dist/chunk-XV3UUOYF.js +845 -0
  40. package/dist/chunk-XV3UUOYF.js.map +1 -0
  41. package/dist/editors.d.ts +53 -5
  42. package/dist/editors.js +85 -2097
  43. package/dist/editors.js.map +1 -1
  44. package/dist/icons.d.ts +29 -8
  45. package/dist/icons.js +2 -361
  46. package/dist/icons.js.map +1 -1
  47. package/dist/index.d.ts +735 -426
  48. package/dist/index.js +5029 -13796
  49. package/dist/index.js.map +1 -1
  50. package/dist/markdown-editor.js +41 -3426
  51. package/dist/markdown-editor.js.map +1 -1
  52. package/dist/mermaid.js +8 -1129
  53. package/dist/mermaid.js.map +1 -1
  54. package/dist/rjsf.js +97 -9240
  55. package/dist/rjsf.js.map +1 -1
  56. package/dist/styles.css +1 -1
  57. package/dist/testing.js +5 -357
  58. package/dist/testing.js.map +1 -1
  59. package/package.json +29 -74
  60. package/src/styles.css +60 -3
  61. package/src/theme.css +1 -0
  62. package/dist/charts.cjs +0 -268
  63. package/dist/charts.cjs.map +0 -1
  64. package/dist/charts.d.cts +0 -181
  65. package/dist/constants-D3gaMY-W.d.cts +0 -39
  66. package/dist/editors.cjs +0 -2456
  67. package/dist/editors.cjs.map +0 -1
  68. package/dist/editors.d.cts +0 -141
  69. package/dist/icons.cjs +0 -23888
  70. package/dist/icons.cjs.map +0 -1
  71. package/dist/icons.d.cts +0 -20
  72. package/dist/index.cjs +0 -24817
  73. package/dist/index.cjs.map +0 -1
  74. package/dist/index.d.cts +0 -10413
  75. package/dist/markdown-editor.cjs +0 -4636
  76. package/dist/markdown-editor.cjs.map +0 -1
  77. package/dist/markdown-editor.d.cts +0 -75
  78. package/dist/mermaid.cjs +0 -1138
  79. package/dist/mermaid.cjs.map +0 -1
  80. package/dist/mermaid.d.cts +0 -15
  81. package/dist/rjsf.cjs.map +0 -1
  82. package/dist/rjsf.d.cts +0 -55
  83. package/dist/testing.cjs.map +0 -1
  84. package/dist/testing.d.cts +0 -25
package/dist/editors.js CHANGED
@@ -1,2047 +1,20 @@
1
- import { createContext, useRef, useEffect, useLayoutEffect, useMemo, useCallback, useSyncExternalStore, useState, use, Children, Fragment as Fragment$1 } from 'react';
2
- import { completeFromList, 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 { EditorView, Decoration, ViewPlugin, gutter, GutterMarker, keymap, placeholder, tooltips, 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 { keboolaLegacySidebar, keboolaLegacyTopnav } from '@keboola/brand-registry';
1
+ import { LINE_HEIGHT_PX, PANE_HEADER_HEIGHT_PX, CHANGE_CLASS } from './chunk-VMFSRV5H.js';
2
+ import { useThemedExtension, isDarkScheme, resolveToken, buildBasicSetup } from './chunk-7PUUHEJQ.js';
3
+ export { CodeEditor, LANGUAGE_MODES, SqlEditor, isLanguageMode } from './chunk-7PUUHEJQ.js';
4
+ import { useStableCallback } from './chunk-Q7NWXLCT.js';
5
+ import './chunk-L37JJ6MR.js';
6
+ import './chunk-ESBL3IPF.js';
7
+ import { Button } from './chunk-CTCFYWJC.js';
8
+ import { X, ChevronsRight, ChevronsLeft } from './chunk-BOHNXTMM.js';
9
+ import './chunk-63NSN2VL.js';
10
+ import { cn } from './chunk-JP7PNHLH.js';
13
11
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
14
- import { Root, Slottable } from '@radix-ui/react-slot';
15
- import { X, ChevronsRight, ChevronsLeft, Loader2, Copy } from 'lucide-react';
16
- import { javascript } from '@codemirror/lang-javascript';
17
- import { python } from '@codemirror/lang-python';
18
- import { sql, PLSQL, MSSQL, PostgreSQL, MySQL } 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 { toml } from '@codemirror/legacy-modes/mode/toml';
23
- import { githubLightInit } from '@uiw/codemirror-theme-github';
24
- import { modeSpec, sfsql } from '@keboola/codemirror-lang-sfsql';
12
+ import { useRef, useCallback, useMemo, useEffect } from 'react';
13
+ import { Decoration, GutterMarker, EditorView, gutterLineClass } from '@codemirror/view';
14
+ import CodeMirror from '@uiw/react-codemirror';
25
15
  import colors from '@keboola/tailwind-config/colors';
26
- import { simpleMode } from '@codemirror/legacy-modes/mode/simple-mode';
27
- import { StateEffect, StateField, RangeSet, Compartment, RangeSetBuilder } from '@codemirror/state';
28
- import { defaultKeymap } from '@codemirror/commands';
29
- import { installExtensions } from '@keboola/codemirror-lang-sql';
16
+ import { StateEffect, StateField, RangeSet, RangeSetBuilder } from '@codemirror/state';
30
17
 
31
- // src/components/CodeEditor/CodeEditor.tsx
32
-
33
- // src/constants/keyCodes.ts
34
- var keyCodes = {
35
- ENTER: "Enter",
36
- ESCAPE: "Escape",
37
- SPACE: " "
38
- };
39
- var useStableCallback = (callback) => {
40
- const latestRef = useRef(callback);
41
- useLayoutEffect(() => {
42
- latestRef.current = callback;
43
- }, [callback]);
44
- return useCallback((...args) => latestRef.current(...args), []);
45
- };
46
- var twMerge = extendTailwindMerge({
47
- prefix: "tw"
48
- });
49
- var cn = (...classes) => twMerge(clsx(...classes));
50
-
51
- // src/utils/copyToClipboard.ts
52
- var copyToClipboard = (text) => {
53
- return navigator.clipboard.writeText(text);
54
- };
55
-
56
- // src/components/ThemeProvider/utils.ts
57
- var createTheme = (brand) => ({
58
- id: brand.id,
59
- name: brand.name,
60
- shell: brand.shell,
61
- logo: brand.logo
62
- });
63
-
64
- // src/components/ThemeProvider/defaults.ts
65
- [keboolaLegacySidebar.id, keboolaLegacyTopnav.id];
66
- var DEFAULT_COLOR_SCHEME = "light";
67
- var DEFAULT_BRAND_ID = "design-system";
68
- var defaultBrand = {
69
- id: DEFAULT_BRAND_ID,
70
- name: "Design System",
71
- shell: "sidebar"};
72
- var defaultTheme = createTheme(defaultBrand);
73
-
74
- // src/components/ThemeProvider/context.tsx
75
- var noop = () => void 0;
76
- var defaultContext = {
77
- scheme: DEFAULT_COLOR_SCHEME,
78
- resolvedScheme: DEFAULT_COLOR_SCHEME,
79
- setScheme: noop,
80
- brandId: defaultTheme.id,
81
- setBrand: noop,
82
- themes: [defaultTheme],
83
- currentTheme: defaultTheme
84
- };
85
- createContext(defaultContext);
86
- var ArgoDesignContext = createContext(true);
87
- var useArgoDesign = () => use(ArgoDesignContext);
88
- var tooltipVariants = cva(
89
- [
90
- "tailwindcss-preflight",
91
- "tw:inline-block",
92
- "tw:break-anywhere",
93
- "tw:max-h-96",
94
- "tw:overflow-y-auto",
95
- "tw:z-[1060]",
96
- // legacy (dark) chrome — default
97
- "tw:rounded",
98
- "tw:bg-neutral-800",
99
- "tw:text-white",
100
- // argo chrome overrides — semantic floating-panel tokens
101
- "tw:data-[argo=true]:rounded-2xl",
102
- "tw:data-[argo=true]:border",
103
- "tw:data-[argo=true]:border-solid",
104
- "tw:data-[argo=true]:border-border",
105
- "tw:data-[argo=true]:bg-popover",
106
- "tw:data-[argo=true]:text-popover-foreground",
107
- "tw:data-[argo=true]:shadow-md",
108
- // argo open animation
109
- "tw:data-[argo=true]:data-[state=delayed-open]:animate-in",
110
- "tw:data-[argo=true]:data-[state=instant-open]:animate-in",
111
- "tw:data-[argo=true]:data-[state=delayed-open]:fade-in-0",
112
- "tw:data-[argo=true]:data-[state=instant-open]:fade-in-0",
113
- "tw:data-[argo=true]:data-[state=delayed-open]:zoom-in-95",
114
- "tw:data-[argo=true]:data-[state=instant-open]:zoom-in-95",
115
- // argo closed animation
116
- "tw:data-[argo=true]:data-[state=closed]:animate-out",
117
- "tw:data-[argo=true]:data-[state=closed]:fade-out-0",
118
- "tw:data-[argo=true]:data-[state=closed]:zoom-out-95",
119
- // argo position animation
120
- "tw:data-[argo=true]:data-[side=bottom]:slide-in-from-top-2",
121
- "tw:data-[argo=true]:data-[side=left]:slide-in-from-right-2",
122
- "tw:data-[argo=true]:data-[side=right]:slide-in-from-left-2",
123
- "tw:data-[argo=true]:data-[side=top]:slide-in-from-bottom-2"
124
- ],
125
- {
126
- defaultVariants: {
127
- variant: "action"
128
- },
129
- variants: {
130
- variant: {
131
- action: [
132
- "tw:max-w-fit",
133
- "tw:px-3",
134
- "tw:py-2",
135
- "tw:text-center",
136
- "tw:text-xs",
137
- "tw:font-medium",
138
- // Legacy chrome uppercases the action tooltip; the Keboola V2 brand
139
- // (`data-brand="keboola"`) renders it in standard case instead.
140
- "tw:uppercase",
141
- "tw:tracking-wider",
142
- "tw:[[data-brand=keboola]_&]:normal-case",
143
- "tw:[[data-brand=keboola]_&]:tracking-normal"
144
- ],
145
- explanatory: [
146
- "tw:max-w-80",
147
- "tw:px-4",
148
- "tw:py-3",
149
- "tw:text-left",
150
- "tw:text-sm",
151
- "tw:font-normal"
152
- ]
153
- }
154
- }
155
- }
156
- );
157
- var TooltipContent = ({
158
- className,
159
- variant,
160
- keepOpenOnPointerDownOutside = false,
161
- children,
162
- onPointerDownOutside,
163
- sideOffset = 8,
164
- collisionPadding = 8,
165
- hideWhenDetached = true,
166
- placement = "right",
167
- ...rest
168
- }) => {
169
- const renderArgo = useArgoDesign();
170
- const handlePointerDownOutside = (event) => {
171
- if (keepOpenOnPointerDownOutside) event.preventDefault();
172
- onPointerDownOutside?.(event);
173
- };
174
- return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(
175
- Content,
176
- {
177
- ...rest,
178
- "data-tooltip-content": renderArgo ? void 0 : true,
179
- "data-argo": renderArgo,
180
- sideOffset,
181
- collisionPadding,
182
- onPointerDownOutside: handlePointerDownOutside,
183
- className: tooltipVariants({ className, variant }),
184
- hideWhenDetached,
185
- side: placement,
186
- children
187
- }
188
- ) });
189
- };
190
- var DELAY_SHOW_TOOLTIP = 300;
191
- var TooltipRoot = ({ children, delayDuration = DELAY_SHOW_TOOLTIP, ...rest }) => /* @__PURE__ */ jsx(Root$1, { ...rest, delayDuration, children });
192
- var TooltipTrigger = ({
193
- ref,
194
- children,
195
- className,
196
- keepOpenOnClick = false,
197
- onClick,
198
- onPointerDown,
199
- asChild,
200
- ...rest
201
- }) => {
202
- const handleClick = (event) => {
203
- if (keepOpenOnClick) event.preventDefault();
204
- onClick?.(event);
205
- };
206
- const handlePointerDown = (event) => {
207
- if (keepOpenOnClick) event.preventDefault();
208
- onPointerDown?.(event);
209
- };
210
- return /* @__PURE__ */ jsx(
211
- Trigger,
212
- {
213
- ...rest,
214
- asChild: true,
215
- ref,
216
- className: cn("tailwindcss-preflight", className),
217
- onClick: handleClick,
218
- onPointerDown: handlePointerDown,
219
- children: asChild ? children : (
220
- // Default-mode trigger wraps children in a span so Radix has a
221
- // single DOM element to attach handlers to. `tailwindcss-preflight`
222
- // (merged in via Slot) activates Tailwind's preflight inside the
223
- // span, which sets `svg { display: block }` — without an inline-flex
224
- // container that would stack any bare Lucide icon onto its own
225
- // line. `tw:inline-flex tw:items-center` keeps icon + text aligned.
226
- /* @__PURE__ */ jsx("span", { className: "tw:inline-flex tw:items-center", children })
227
- )
228
- }
229
- );
230
- };
231
- var ACTION_TOOLTIP_LIMIT = 30;
232
- var Tooltip = ({
233
- tooltip,
234
- children,
235
- className,
236
- keepOpenOnTriggerClick = false,
237
- variant,
238
- placement = "right",
239
- forceHide = false,
240
- forceShow = false,
241
- delayDuration,
242
- // trigger props
243
- triggerAsChild = false
244
- }) => {
245
- const [open, setOpen] = useState(false);
246
- const resolvedVariant = (() => {
247
- if (!!variant) return variant;
248
- if (typeof tooltip === "string" && tooltip.length > ACTION_TOOLTIP_LIMIT) return "explanatory";
249
- return "action";
250
- })();
251
- const isActionVariant = resolvedVariant === "action";
252
- const handleKeyUp = (event) => {
253
- if (![keyCodes.ENTER, keyCodes.SPACE].includes(event.key)) return;
254
- event.stopPropagation();
255
- };
256
- return /* @__PURE__ */ jsxs(
257
- TooltipRoot,
258
- {
259
- open: !!tooltip && (open || forceShow) && !forceHide,
260
- onOpenChange: setOpen,
261
- delayDuration,
262
- disableHoverableContent: isActionVariant,
263
- children: [
264
- /* @__PURE__ */ jsx(
265
- TooltipTrigger,
266
- {
267
- asChild: triggerAsChild,
268
- keepOpenOnClick: keepOpenOnTriggerClick,
269
- onKeyUp: handleKeyUp,
270
- children
271
- }
272
- ),
273
- /* @__PURE__ */ jsx(
274
- TooltipContent,
275
- {
276
- className,
277
- variant: resolvedVariant,
278
- placement,
279
- keepOpenOnPointerDownOutside: keepOpenOnTriggerClick,
280
- children: tooltip
281
- }
282
- )
283
- ]
284
- }
285
- );
286
- };
287
- Tooltip.Root = TooltipRoot;
288
- Tooltip.Content = TooltipContent;
289
- Tooltip.Trigger = TooltipTrigger;
290
-
291
- // src/utils/escapeStringRegexp.ts
292
- var escapeStringRegexp = (string) => string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
293
-
294
- // src/utils/isMac.ts
295
- var getIsMac = () => {
296
- if (typeof navigator !== "undefined" && "userAgentData" in navigator) {
297
- const platform = navigator.userAgentData.platform;
298
- if (typeof platform === "string") {
299
- return platform.toLowerCase() === "macos";
300
- }
301
- }
302
- if (typeof navigator !== "undefined" && typeof navigator.platform === "string") {
303
- return navigator.platform.toUpperCase().indexOf("MAC") >= 0;
304
- }
305
- return false;
306
- };
307
- var isMac = getIsMac();
308
- var helpVariants = cva(["tw:m-0", "tw:text-xs"], {
309
- defaultVariants: {
310
- state: "default"
311
- },
312
- variants: {
313
- state: {
314
- default: ["tw:text-muted-foreground"],
315
- warning: ["tw:text-warning"]
316
- }
317
- }
318
- });
319
- var HelpBlock = ({ children, className, state = "default", ...rest }) => {
320
- if (!children) return null;
321
- return /* @__PURE__ */ jsx("p", { ...rest, className: helpVariants({ state, className }), children });
322
- };
323
- var variants = cva(
324
- [
325
- "tailwindcss-preflight",
326
- "tw:group/button",
327
- "tw:border-box",
328
- // layout
329
- "tw:relative",
330
- "tw:flex",
331
- "tw:items-center",
332
- "tw:justify-center",
333
- "tw:gap-2",
334
- // text — chrome weight/tracking are brand-overridable tokens
335
- // (`--font-weight-medium` / `--letter-spacing-chrome`). Casing: standard case is
336
- // the default; only legacy brands (`keboola-legacy-*`) uppercase the chrome, so
337
- // modern brands (incl. Keboola V2) read naturally. Mirrors the V2 standard-case
338
- // treatment shipped for Tooltip/Badge (PR 7629).
339
- "tw:text-xs",
340
- "tw:leading-5",
341
- "tw:font-medium",
342
- "tw:[[data-brand^=keboola-legacy]_&]:tracking-chrome",
343
- "tw:[[data-brand^=keboola-legacy]_&]:uppercase",
344
- // border — legacy (non-argo) chrome uses a fixed radius, not the brand token.
345
- "tw:rounded",
346
- "tw:border",
347
- "tw:border-transparent",
348
- // styling
349
- "tw:shadow-none",
350
- "tw:[a]:cursor-pointer",
351
- // explicitly set for anchor
352
- "tw:focus-visible:outline",
353
- "tw:focus-visible:outline-1",
354
- "tw:focus-visible:-outline-offset-1",
355
- "tw:focus-visible:outline-ring",
356
- "tw:focus-visible:ring-4",
357
- "tw:focus-visible:ring-ring/30",
358
- // disabled
359
- "tw:disabled:opacity-40",
360
- "tw:disabled:cursor-not-allowed",
361
- // anchor support
362
- "tw:!no-underline",
363
- "tw:aria-disabled:opacity-40",
364
- "tw:aria-disabled:cursor-not-allowed",
365
- "tw:[&_svg]:shrink-0"
366
- ],
367
- {
368
- defaultVariants: {
369
- size: "medium",
370
- variant: "primary",
371
- block: false
372
- },
373
- variants: {
374
- block: {
375
- true: ["tw:w-full"]
376
- },
377
- variant: {
378
- primary: [
379
- "tw:text-white",
380
- "tw:bg-primary-500",
381
- "tw:focus:text-white",
382
- "tw:hover:text-white",
383
- "tw:hover:not-disabled:bg-primary-600",
384
- "tw:active:not-disabled:bg-primary-800",
385
- // anchor disabled override
386
- "tw:aria-disabled:!bg-primary-500"
387
- ],
388
- secondary: [
389
- "tw:text-white",
390
- "tw:bg-secondary-500",
391
- "tw:focus:text-white",
392
- "tw:hover:text-white",
393
- "tw:hover:not-disabled:bg-secondary-700",
394
- "tw:active:not-disabled:bg-secondary-800",
395
- // anchor disabled override
396
- "tw:aria-disabled:!bg-secondary-500"
397
- ],
398
- danger: [
399
- "tw:text-white",
400
- "tw:bg-error-500",
401
- "tw:focus:text-white",
402
- "tw:hover:text-white",
403
- "tw:hover:not-disabled:bg-error-600",
404
- "tw:active:not-disabled:bg-error-700",
405
- // anchor disabled override
406
- "tw:aria-disabled:!bg-error-500"
407
- ],
408
- invisible: [
409
- "tw:text-neutral-800",
410
- "tw:bg-transparent",
411
- "tw:focus:text-neutral-800",
412
- "tw:hover:not-disabled:bg-neutral-100",
413
- "tw:hover:text-neutral-800",
414
- "tw:active:not-disabled:bg-neutral-150",
415
- // contrasting icon on hover/active
416
- "tw:[&_svg]:text-neutral-400",
417
- "tw:hover:not-disabled:[&_svg]:text-secondary-600",
418
- "tw:active:not-disabled:[&_svg]:text-secondary-600",
419
- // anchor disabled override
420
- "tw:aria-disabled:!bg-transparent"
421
- ],
422
- outline: [
423
- "tw:text-neutral-800",
424
- "tw:bg-white",
425
- // border
426
- "tw:!border-neutral-200",
427
- "tw:hover:text-neutral-800",
428
- "tw:focus:text-neutral-800",
429
- "tw:hover:not-disabled:!border-neutral-300",
430
- "tw:hover:not-disabled:bg-neutral-100",
431
- "tw:active:not-disabled:bg-neutral-200",
432
- // contrasting icon hover, same as invisible
433
- "tw:[&_svg]:text-neutral-400",
434
- "tw:not-disabled:hover:[&_svg]:text-secondary-600",
435
- "tw:active:not-disabled:[&_svg]:text-secondary-600",
436
- // anchor disabled override
437
- "tw:aria-disabled:!bg-white",
438
- "tw:aria-disabled:!border-neutral-200"
439
- ],
440
- inline: [
441
- "tw:text-neutral-800",
442
- "tw:bg-transparent",
443
- "tw:rounded-full",
444
- "tw:[&_svg]:text-neutral-400",
445
- "tw:not-disabled:hover:[&_svg]:text-secondary-600",
446
- "tw:not-disabled:focus:[&_svg]:text-secondary-600"
447
- ]
448
- },
449
- size: {
450
- medium: [
451
- "tw:max-h-10",
452
- "tw:min-h-10",
453
- "tw:px-4",
454
- "tw:py-2.5",
455
- 'tw:[&_svg:not([class*="tw:size-"])]:size-4'
456
- ],
457
- small: [
458
- "tw:max-h-8",
459
- "tw:min-h-8",
460
- "tw:px-4",
461
- "tw:py-1.5",
462
- 'tw:[&_svg:not([class*="tw:size-"])]:size-4'
463
- ],
464
- large: [
465
- "tw:max-h-12",
466
- "tw:min-h-12",
467
- "tw:px-4",
468
- "tw:py-3.5",
469
- 'tw:[&_svg:not([class*="tw:size-"])]:size-4'
470
- ],
471
- "icon-lg": ["tw:size-12", "tw:p-0", 'tw:[&_svg:not([class*="tw:size-"])]:size-6'],
472
- icon: ["tw:size-10", "tw:p-0", 'tw:[&_svg:not([class*="tw:size-"])]:size-4'],
473
- "icon-sm": ["tw:size-8", "tw:p-0", 'tw:[&_svg:not([class*="tw:size-"])]:size-4'],
474
- "icon-xs": ["tw:size-6", "tw:p-0", 'tw:[&_svg:not([class*="tw:size-"])]:size-4'],
475
- "icon-2xs": [
476
- "tw:!inline-flex",
477
- "tw:size-5",
478
- "tw:max-h-5",
479
- 'tw:[&_svg:not([class*="tw:size-"])]:size-3'
480
- ],
481
- "icon-3xs": ["tw:h-fit", "tw:w-fit", 'tw:[&_svg:not([class*="tw:size-"])]:size-4']
482
- }
483
- }
484
- }
485
- );
486
- var argoVariants = cva(
487
- [
488
- "tailwindcss-preflight",
489
- // layout
490
- "tw:relative",
491
- "tw:inline-flex",
492
- "tw:items-center",
493
- "tw:justify-center",
494
- "tw:whitespace-nowrap",
495
- "tw:gap-2",
496
- // border
497
- "tw:border",
498
- "tw:border-transparent",
499
- "tw:rounded-[var(--radius-lg,0.25rem)]",
500
- // text
501
- "tw:font-medium",
502
- "tw:select-none",
503
- // focus visible
504
- "tw:!outline-hidden",
505
- "tw:focus-visible:ring-2",
506
- // disabled
507
- "tw:disabled:cursor-not-allowed",
508
- "tw:disabled:opacity-50",
509
- "tw:active:opacity-60",
510
- "tw:transition-all",
511
- "tw:bg-clip-padding",
512
- // anchor support
513
- "tw:!no-underline",
514
- "tw:aria-disabled:cursor-not-allowed",
515
- "tw:aria-disabled:opacity-50",
516
- // icon
517
- "tw:shrink-0",
518
- "tw:[&_svg]:pointer-events-none",
519
- "tw:[&_svg]:shrink-0",
520
- "tw:[&_svg:not([class*='tw:size-'])]:size-4"
521
- ],
522
- {
523
- defaultVariants: {
524
- variant: "primary",
525
- size: "medium"
526
- },
527
- variants: {
528
- block: {
529
- true: ["tw:w-full"]
530
- },
531
- variant: {
532
- primary: [
533
- "tw:bg-primary",
534
- "tw:text-primary-foreground",
535
- "tw:[a]:hover:bg-primary/80",
536
- "tw:hover:not-disabled:bg-primary/90",
537
- "tw:hover:text-primary-foreground",
538
- "tw:focus:text-primary-foreground",
539
- "tw:focus-visible:border-primary",
540
- "tw:focus-visible:ring-ring/50"
541
- ],
542
- secondary: [
543
- "tw:bg-primary/10",
544
- "tw:text-primary",
545
- "tw:hover:not-disabled:bg-primary/20",
546
- "tw:focus-visible:border-primary",
547
- "tw:focus-visible:ring-ring/50"
548
- ],
549
- // should be called "destructive" by Figma
550
- danger: [
551
- "tw:bg-destructive",
552
- "tw:text-destructive-foreground",
553
- "tw:hover:text-destructive-foreground",
554
- "tw:focus:text-destructive-foreground",
555
- "tw:focus-visible:border-destructive",
556
- "tw:focus-visible:ring-destructive/20"
557
- ],
558
- outline: [
559
- "tw:!border-input",
560
- "tw:bg-background",
561
- // Semantic base text color so the label/icon flips in dark mode
562
- // (matches `invisible`); previously unset → inherited a fixed dark color.
563
- "tw:text-foreground",
564
- // Hover follows the brand primary (translucent tint), matching the
565
- // `secondary` variant — not the fixed `accent` blue.
566
- "tw:hover:not-disabled:bg-primary/10",
567
- "tw:hover:not-disabled:text-primary",
568
- "tw:hover:active:bg-background",
569
- "tw:focus-visible:!border-primary",
570
- "tw:focus-visible:ring-ring/50"
571
- ],
572
- // should be called "ghost" by Figma
573
- invisible: [
574
- "tw:bg-transparent",
575
- "tw:text-foreground",
576
- "tw:hover:not-disabled:bg-primary/10",
577
- "tw:hover:not-disabled:text-primary",
578
- "tw:hover:not-disabled:border-primary/10",
579
- "tw:focus-visible:ring-ring/50"
580
- ],
581
- // should be called "link" by Figma
582
- inline: [
583
- "tw:bg-transparent",
584
- "tw:text-primary",
585
- "tw:hover:underline",
586
- "tw:hover:active:bg-transparent",
587
- "tw:focus-visible:ring-ring/50"
588
- ]
589
- },
590
- size: {
591
- // should be called "default" by Figma
592
- medium: ["tw:max-h-9", "tw:py-2", "tw:px-4", "tw:text-sm"],
593
- // should be called "small" by Figma
594
- small: ["tw:max-h-8", "tw:py-2", "tw:px-3", "tw:text-xs"],
595
- // should be called "large" by Figma
596
- large: ["tw:max-h-10", "tw:py-2.5", "tw:px-6", "tw:text-sm"],
597
- "icon-lg": ["tw:size-10"],
598
- icon: ["tw:size-9"],
599
- "icon-sm": ["tw:size-8"],
600
- // unsupported in ARGO, remove when old design is gone
601
- "icon-xs": [],
602
- "icon-2xs": [],
603
- "icon-3xs": []
604
- }
605
- }
606
- }
607
- );
608
- var Button = ({
609
- ref,
610
- children,
611
- disabled = false,
612
- className,
613
- type = "button",
614
- isLoading = false,
615
- asChild = false,
616
- onClick,
617
- variant = "primary",
618
- size = "medium",
619
- block = false,
620
- ...buttonProps
621
- }) => {
622
- const renderArgo = useArgoDesign();
623
- const Comp = asChild ? Root : "button";
624
- const isIconOnly = String(size).startsWith("icon");
625
- const classNames = renderArgo ? argoVariants({ variant, size, block, className }) : variants({ size, variant, block, className });
626
- const handleClick = (event) => {
627
- const isAnchor = event.currentTarget.tagName === "A";
628
- if (isAnchor && disabled) {
629
- event.preventDefault();
630
- return;
631
- }
632
- onClick?.(event);
633
- };
634
- return /* @__PURE__ */ jsxs(
635
- Comp,
636
- {
637
- ...buttonProps,
638
- ref,
639
- disabled,
640
- "aria-disabled": disabled,
641
- "data-variant": variant,
642
- "data-icon-only": isIconOnly,
643
- type,
644
- onClick: handleClick,
645
- className: cn(classNames),
646
- children: [
647
- isLoading && /* @__PURE__ */ jsx(Loader2, { className: "tw:size-4 tw:shrink-0 tw:animate-spin" }),
648
- /* @__PURE__ */ jsx(Slottable, { children: isLoading && isIconOnly ? null : children })
649
- ]
650
- }
651
- );
652
- };
653
- var Clipboard2 = ({
654
- ref,
655
- text: textProp,
656
- children,
657
- tooltip = "Copy to Clipboard",
658
- tooltipPlacement = "top",
659
- tooltipVariant: tooltipVariantProp = "action",
660
- asChild = false,
661
- onClick,
662
- className,
663
- ...restButtonProps
664
- }) => {
665
- const [isTooltipOpen, setIsTooltipOpen] = useState(false);
666
- const [state, setState] = useState("ready");
667
- const text = typeof textProp === "function" ? textProp() : textProp;
668
- const copy = async (text2) => {
669
- try {
670
- if (!document.hasFocus()) window.focus();
671
- await copyToClipboard(text2);
672
- setState("copied");
673
- } catch {
674
- setState("error");
675
- }
676
- };
677
- const handleOnClick = (event) => {
678
- setIsTooltipOpen(true);
679
- if (text && state === "ready") void copy(text);
680
- onClick?.(event);
681
- };
682
- const handleOnOpenChange = (open) => {
683
- if (!open && state !== "ready") setState("ready");
684
- setIsTooltipOpen(open);
685
- };
686
- const tooltipContent = (() => {
687
- if (!text) return "Nothing to copy";
688
- if (state === "error") return "Failed to copy";
689
- if (state === "copied") return "Copied to Clipboard";
690
- return tooltip;
691
- })();
692
- const tooltipVariant = state === "ready" && !!text ? tooltipVariantProp : "action";
693
- const hasTooltipContent = tooltipContent !== null && tooltipContent !== void 0;
694
- return /* @__PURE__ */ jsxs(Tooltip.Root, { open: isTooltipOpen, onOpenChange: handleOnOpenChange, children: [
695
- /* @__PURE__ */ jsx(
696
- Tooltip.Trigger,
697
- {
698
- ...restButtonProps,
699
- asChild,
700
- keepOpenOnClick: true,
701
- onClick: handleOnClick,
702
- className: cn("tw:cursor-pointer", className),
703
- ref,
704
- children: children ?? text
705
- }
706
- ),
707
- hasTooltipContent && /* @__PURE__ */ jsx(
708
- Tooltip.Content,
709
- {
710
- keepOpenOnPointerDownOutside: true,
711
- placement: tooltipPlacement,
712
- variant: tooltipVariant,
713
- children: tooltipContent
714
- }
715
- )
716
- ] });
717
- };
718
- var DEFAULT_ICON = /* @__PURE__ */ jsx(Copy, {});
719
- var DEFAULT_ARIA_LABEL = "Copy";
720
- var ClipboardButton = ({
721
- // clipboard props
722
- text,
723
- tooltip,
724
- tooltipPlacement,
725
- tooltipVariant,
726
- // button props
727
- icon = DEFAULT_ICON,
728
- variant = "outline",
729
- children,
730
- ...rest
731
- }) => {
732
- const defaultAriaLabel = typeof tooltip === "string" && tooltip.trim() ? tooltip : DEFAULT_ARIA_LABEL;
733
- const ariaLabel = rest["aria-label"] ?? (children == null ? defaultAriaLabel : void 0);
734
- return /* @__PURE__ */ jsx(
735
- Clipboard2,
736
- {
737
- asChild: true,
738
- tooltip,
739
- tooltipPlacement,
740
- tooltipVariant,
741
- text,
742
- children: /* @__PURE__ */ jsxs(Button, { ...rest, "aria-label": ariaLabel, variant, disabled: !text, children: [
743
- icon,
744
- children
745
- ] })
746
- }
747
- );
748
- };
749
- var ButtonToolbar = ({ value, children }) => {
750
- if (!value && !children) return null;
751
- 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: [
752
- !!value && /* @__PURE__ */ jsx(ClipboardButton, { size: "icon-sm", variant: "invisible", text: value }),
753
- children
754
- ] });
755
- };
756
- var COMMANDS = [
757
- "run-operation",
758
- "run",
759
- "test",
760
- "seed",
761
- "snapshot",
762
- "list",
763
- "ls",
764
- "compile",
765
- "build",
766
- "deps",
767
- "docs",
768
- "source"
769
- ];
770
- var SUBCOMMANDS = { docs: ["generate"], source: ["freshness"] };
771
- var ARGUMENTS = ["--select", "--exclude", "--selector", "--defer", "--resource-type", "-s"];
772
- var SELECTORS = ["--select", "--exclude", "-s"];
773
- var METHODS = [
774
- "path:",
775
- "source:",
776
- "tag:",
777
- "package:",
778
- "config:",
779
- "test_type:",
780
- "test_name:",
781
- "state:",
782
- "exposure:",
783
- "metric:",
784
- "result:",
785
- "source_status:",
786
- "column_name:"
787
- ];
788
- var FLAGS = [
789
- "--fail-fast",
790
- "--warn-error",
791
- "--favor-state",
792
- "--vars",
793
- "--models",
794
- "--threads",
795
- "--profiles-dir",
796
- "--profile",
797
- "--full-refresh"
798
- ];
799
- var COMMAND_PHRASES = COMMANDS.flatMap((command) => {
800
- const subcommands = SUBCOMMANDS[command];
801
- return subcommands ? subcommands.map((subcommand) => `${command} ${subcommand}`) : [command];
802
- });
803
- var alternation = (list) => [...list].sort((a, b) => b.length - a.length).join("|");
804
- var word = (list) => new RegExp(`^\\s+(?:${alternation(list)})\\b`, "i");
805
- var prefix = (list) => new RegExp(`^\\s+(?:${alternation(list)})`, "i");
806
- var WORD = /[\w:-]*$/;
807
- var asOptions = (list, type) => list.map((label) => ({ label, type }));
808
- var DBT = [{ label: "dbt", type: "keyword" }];
809
- var COMMAND_OPTIONS = asOptions(COMMANDS, "keyword");
810
- var SUBCOMMAND_OPTIONS = Object.fromEntries(
811
- Object.entries(SUBCOMMANDS).map(([command, subcommands]) => [
812
- command,
813
- asOptions(subcommands, "keyword")
814
- ])
815
- );
816
- var ARGUMENT_OPTIONS = asOptions(ARGUMENTS, "variable");
817
- var FLAG_OPTIONS = asOptions(FLAGS, "constant");
818
- var METHOD_OPTIONS = asOptions(METHODS, "property");
819
- var optionsAfter = (words) => {
820
- const [step, command, ...rest] = words;
821
- if (step === void 0) return DBT;
822
- if (step.toLowerCase() !== "dbt") return [];
823
- if (command === void 0) return COMMAND_OPTIONS;
824
- const subcommands = SUBCOMMAND_OPTIONS[command.toLowerCase()];
825
- if (subcommands && rest.length === 0) return subcommands;
826
- const lastArgument = rest.filter((it) => it.startsWith("-")).at(-1);
827
- const selecting = lastArgument !== void 0 && SELECTORS.includes(lastArgument.toLowerCase());
828
- return selecting ? [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS, ...METHOD_OPTIONS] : [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS];
829
- };
830
- var complete = (context) => {
831
- const typed = context.matchBefore(WORD);
832
- if (!typed?.text && !context.explicit) return null;
833
- const from = typed?.from ?? context.pos;
834
- const line = context.state.doc.lineAt(from);
835
- const options = optionsAfter(
836
- line.text.slice(0, from - line.from).split(/\s+/).filter(Boolean)
837
- );
838
- return options.length > 0 ? { from, options, validFor: WORD } : null;
839
- };
840
- var dbt = simpleMode({
841
- languageData: {
842
- // `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
843
- commentTokens: { line: "--", block: { open: "/*", close: "*/" } },
844
- autocomplete: complete
845
- },
846
- start: [
847
- { regex: /"(?:[^\\]|\\.)*?(?:"|$)/, token: "string" },
848
- // Word-bounded, so `dbtX` is not a dbt step whose first word happens to
849
- // colour — the same thing the completion source asks of it.
850
- { regex: /dbt\b/, token: "keyword", sol: true },
851
- { regex: word(COMMAND_PHRASES), token: "keyword" },
852
- { regex: word(ARGUMENTS), token: "variableName" },
853
- { regex: prefix(METHODS), token: "propertyName" },
854
- { regex: prefix(FLAGS), token: "attributeName" },
855
- { regex: /(?:@|\*|,|\+\d+|\d+\+|\+)/, token: "operator" },
856
- { regex: /'.*'/, token: "string" },
857
- { regex: /true|false/, token: "atom" }
858
- ]
859
- });
860
-
861
- // src/components/CodeEditor/modes/jsonnet.ts
862
- var COMMENT_END = /^\*\//;
863
- var COMMENT_START = /^\/\/|^#/;
864
- var C_COMMENT_START = /^\/\*/;
865
- var TEXT_BLOCK = /^\|\|\|/;
866
- var TEXT_BLOCK_END = /^\s*\|\|\|/;
867
- var RAW_DOUBLE = /^""/;
868
- var RAW_SINGLE = /^''/;
869
- var CLOSE_DOUBLE = /^"/;
870
- var CLOSE_SINGLE = /^'/;
871
- var ESCAPE = /^\\[\\"'/bfnrt0]/;
872
- var UNICODE_ESCAPE = /^\\u[0-9a-fA-F]{4}/;
873
- var BACKSLASH = /^\\/;
874
- var IMPORT = /^import(?:str)?\s*(@?)(["'])/;
875
- var QUOTE = /^(@?)(["'])/;
876
- var ROOT = /^\$/;
877
- var NUMBER = /^(?:\.\d+|\d+\.?\d*)(?:e[-+]?\d+)?/i;
878
- var OPERATOR = /^[-+/*=<>!&~^|$%]+/;
879
- var IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_]*/;
880
- var KEYWORDS = {
881
- local: "keyword",
882
- self: "keyword",
883
- super: "keyword",
884
- assert: "keyword",
885
- function: "keyword",
886
- if: "keyword",
887
- then: "keyword",
888
- else: "keyword",
889
- for: "keyword",
890
- in: "keyword",
891
- tailstrict: "keyword",
892
- error: "keyword",
893
- true: "atom",
894
- false: "atom",
895
- null: "atom"
896
- };
897
- var jsonnet = {
898
- name: "jsonnet",
899
- // `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
900
- languageData: { commentTokens: { line: "//", block: { open: "/*", close: "*/" } } },
901
- startState: () => ({
902
- cComment: false,
903
- textBlock: false,
904
- textBlockIndent: null,
905
- string: false,
906
- importString: false,
907
- stringSingle: false,
908
- stringRaw: false
909
- }),
910
- token: (stream, state) => {
911
- if (state.cComment) {
912
- if (stream.match(COMMENT_END)) {
913
- state.cComment = false;
914
- return "comment";
915
- }
916
- stream.next();
917
- return "comment";
918
- }
919
- if (state.textBlock) {
920
- if (state.textBlockIndent == null) {
921
- if (stream.match(TEXT_BLOCK_END)) {
922
- state.textBlock = false;
923
- return "string";
924
- }
925
- state.textBlockIndent = stream.indentation();
926
- }
927
- if (stream.indentation() >= state.textBlockIndent) {
928
- stream.skipToEnd();
929
- return "string";
930
- }
931
- if (stream.match(TEXT_BLOCK_END)) {
932
- state.textBlock = false;
933
- return "string";
934
- }
935
- stream.next();
936
- return "invalid";
937
- }
938
- if (state.string || state.importString) {
939
- const style = state.string ? "string" : "meta";
940
- if (state.stringRaw) {
941
- if (stream.match(state.stringSingle ? RAW_SINGLE : RAW_DOUBLE)) return "escape";
942
- } else {
943
- if (stream.match(ESCAPE)) return "escape";
944
- if (stream.match(UNICODE_ESCAPE)) return "escape";
945
- if (stream.match(BACKSLASH)) return "invalid";
946
- }
947
- if (stream.match(state.stringSingle ? CLOSE_SINGLE : CLOSE_DOUBLE)) {
948
- state.string = false;
949
- state.importString = false;
950
- return style;
951
- }
952
- stream.next();
953
- return style;
954
- }
955
- if (stream.match(COMMENT_START)) {
956
- stream.skipToEnd();
957
- return "comment";
958
- }
959
- if (stream.match(C_COMMENT_START)) {
960
- state.cComment = true;
961
- return "comment";
962
- }
963
- const imported = stream.match(IMPORT);
964
- if (Array.isArray(imported)) {
965
- state.importString = true;
966
- state.stringRaw = imported[1] === "@";
967
- state.stringSingle = imported[2] === "'";
968
- return "meta";
969
- }
970
- const quoted = stream.match(QUOTE);
971
- if (Array.isArray(quoted)) {
972
- state.string = true;
973
- state.stringRaw = quoted[1] === "@";
974
- state.stringSingle = quoted[2] === "'";
975
- return "string";
976
- }
977
- if (stream.match(TEXT_BLOCK)) {
978
- state.textBlock = true;
979
- state.textBlockIndent = null;
980
- return "string";
981
- }
982
- if (stream.match(ROOT)) return "keyword";
983
- if (stream.match(NUMBER)) return "number";
984
- if (stream.match(OPERATOR)) return "operator";
985
- const identifier = stream.match(IDENTIFIER);
986
- if (Array.isArray(identifier)) return KEYWORDS[identifier[0]] ?? null;
987
- stream.next();
988
- return null;
989
- }
990
- };
991
- var resolveToken = (token, fallbackChannels, alpha) => {
992
- const channels = typeof document === "undefined" ? fallbackChannels : getComputedStyle(document.documentElement).getPropertyValue(`--${token}`).trim() || fallbackChannels;
993
- return alpha === void 0 ? `rgb(${channels})` : `rgb(${channels} / ${alpha})`;
994
- };
995
- var SSR_SIGNAL = "ssr";
996
- var readThemeSignal = () => {
997
- if (typeof document === "undefined") return SSR_SIGNAL;
998
- const root = document.documentElement;
999
- return `${root.getAttribute("data-theme") ?? ""}:${root.getAttribute("data-brand") ?? ""}`;
1000
- };
1001
- var subscribeThemeSignal = (onChange) => {
1002
- if (typeof document === "undefined") return () => {
1003
- };
1004
- const observer = new MutationObserver(onChange);
1005
- observer.observe(document.documentElement, {
1006
- attributes: true,
1007
- attributeFilter: ["data-theme", "data-brand"]
1008
- });
1009
- return () => observer.disconnect();
1010
- };
1011
- var useThemeSignal = () => useSyncExternalStore(subscribeThemeSignal, readThemeSignal, () => SSR_SIGNAL);
1012
- var themeCache = /* @__PURE__ */ new Map();
1013
- var useThemedExtension = (cacheKey, build) => {
1014
- const themeSignal = useThemeSignal();
1015
- const key = `${themeSignal} ${cacheKey}`;
1016
- let cached = themeCache.get(key);
1017
- if (!cached) {
1018
- cached = build();
1019
- themeCache.set(key, cached);
1020
- }
1021
- return cached;
1022
- };
1023
-
1024
- // src/components/CodeEditor/helpers.ts
1025
- var LANGUAGE_MODES = [
1026
- "application/json",
1027
- "text/plain",
1028
- "text/x-python",
1029
- "text/x-sql",
1030
- "text/x-mysql",
1031
- "text/x-pgsql",
1032
- "text/x-mssql",
1033
- "text/x-sfsql",
1034
- "text/x-plsql",
1035
- "text/x-rsrc",
1036
- "text/x-sh",
1037
- "text/x-toml",
1038
- "text/jsonnet",
1039
- "text/x-dbt",
1040
- "text/javascript",
1041
- "text/typescript"
1042
- ];
1043
- var isLanguageMode = (mode) => LANGUAGE_MODES.includes(mode);
1044
- var buildBaseThemeStyles = () => ({
1045
- "*": { lineHeight: "20px" },
1046
- "*::selection": {
1047
- backgroundColor: resolveToken("primary", "31 143 255"),
1048
- color: `${resolveToken("primary-foreground", "255 255 255")} !important`
1049
- },
1050
- '&.cm-editor:has(.cm-content[contenteditable="false"])': {
1051
- backgroundColor: resolveToken("secondary", "226 232 240")
1052
- },
1053
- '&.cm-editor:has(.cm-content[contenteditable="false"]) .cm-gutters': {
1054
- backgroundColor: resolveToken("border", "229 231 235")
1055
- },
1056
- "&.cm-editor .cm-scroller": { overflowAnchor: "none" },
1057
- "&.cm-editor, &.cm-editor .cm-scroller": {
1058
- minHeight: "100%",
1059
- flexGrow: 1,
1060
- alignItems: "stretch !important",
1061
- outline: "none"
1062
- },
1063
- ".cm-gutter.cm-foldGutter": { display: "none !important" },
1064
- ".cm-gutter.cm-lineNumbers": { paddingLeft: "20px", paddingRight: "6px" },
1065
- ".cm-gutters": { height: "auto" },
1066
- // tokens overrides
1067
- ".cm-line .tok-string": { color: colors.warning[700] },
1068
- // merge (diff) view
1069
- '&[class*="cm-merge-"] .cm-deletedLine': { backgroundColor: colors.error[100] },
1070
- '&[class*="cm-merge-"] .cm-changedLine': { backgroundColor: colors.green[100] },
1071
- '&[class*="cm-merge-"] .cm-deletedLineGutter': { backgroundColor: colors.error[200] },
1072
- '&[class*="cm-merge-"] .cm-changedLineGutter': { backgroundColor: colors.green[200] },
1073
- '&[class*="cm-merge-"] .cm-deletedText': { background: colors.error[200] },
1074
- '&[class*="cm-merge-"] .cm-changedText': { background: colors.green[200] },
1075
- '&[class*="cm-merge-"]': {
1076
- backgroundColor: `${colors.white} !important`
1077
- },
1078
- '&[class*="cm-merge-"] .cm-gutters': {
1079
- backgroundColor: `${colors.white} !important`
1080
- },
1081
- ".cm-changeGutter": { position: "absolute", zIndex: -1, width: "100%", paddingLeft: 0 },
1082
- '&[class*="cm-merge-"] .cm-changedLine,&[class*="cm-merge-"] .cm-line, &[class*="cm-merge-"] .cm-deletedChunk': { paddingLeft: 0 }
1083
- });
1084
- var ALWAYS_OFF = {
1085
- drawSelection: false,
1086
- foldGutter: false,
1087
- foldKeymap: false,
1088
- highlightActiveLine: false,
1089
- highlightActiveLineGutter: false
1090
- };
1091
- var buildBasicSetup = (readOnly) => ({
1092
- ...ALWAYS_OFF,
1093
- ...readOnly ? {
1094
- history: false,
1095
- historyKeymap: false,
1096
- closeBrackets: false,
1097
- closeBracketsKeymap: false,
1098
- lintKeymap: false,
1099
- indentOnInput: false,
1100
- rectangularSelection: false,
1101
- dropCursor: false,
1102
- highlightSelectionMatches: false
1103
- } : null
1104
- });
1105
- var buildCustomTheme = () => githubLightInit({
1106
- settings: {
1107
- fontFamily: `'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New'`,
1108
- background: resolveToken("background", "249 250 251"),
1109
- foreground: resolveToken("foreground", "30 41 59"),
1110
- gutterBackground: resolveToken("muted", "241 245 249"),
1111
- gutterForeground: resolveToken("muted-foreground", "100 116 139"),
1112
- gutterBorder: "transparent",
1113
- lineHighlight: "transparent",
1114
- selection: resolveToken("primary", "31 143 255")
1115
- }
1116
- });
1117
- var sfsqlWithLanguageData = {
1118
- ...sfsql,
1119
- languageData: {
1120
- ...sfsql.languageData,
1121
- // `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
1122
- commentTokens: { line: "--", block: { open: "/*", close: "*/" } },
1123
- autocomplete: completeFromList(
1124
- Object.keys(modeSpec.keywords).map((label) => ({
1125
- label: label.toUpperCase(),
1126
- type: "keyword"
1127
- }))
1128
- )
1129
- }
1130
- };
1131
- var getLanguageMode = (mode) => {
1132
- switch (mode) {
1133
- case void 0:
1134
- case "application/json":
1135
- return json();
1136
- case "text/x-python":
1137
- return python();
1138
- case "text/x-sql":
1139
- return sql({ upperCaseKeywords: true });
1140
- case "text/x-mysql":
1141
- return sql({ upperCaseKeywords: true, dialect: MySQL });
1142
- case "text/x-pgsql":
1143
- return sql({ upperCaseKeywords: true, dialect: PostgreSQL });
1144
- case "text/x-mssql":
1145
- return sql({ upperCaseKeywords: true, dialect: MSSQL });
1146
- case "text/x-sfsql":
1147
- return StreamLanguage.define(sfsqlWithLanguageData);
1148
- case "text/x-plsql":
1149
- return sql({ upperCaseKeywords: true, dialect: PLSQL });
1150
- case "text/x-rsrc":
1151
- return StreamLanguage.define(r);
1152
- case "text/x-sh":
1153
- return StreamLanguage.define(shell);
1154
- case "text/x-toml":
1155
- return StreamLanguage.define(toml);
1156
- case "text/jsonnet":
1157
- return StreamLanguage.define(jsonnet);
1158
- case "text/x-dbt":
1159
- return StreamLanguage.define(dbt);
1160
- case "text/javascript":
1161
- return javascript({ jsx: true });
1162
- case "text/typescript":
1163
- return javascript({ jsx: true, typescript: true });
1164
- // No language — `text/plain` lands here, and so does any mode added to
1165
- // LANGUAGE_MODES without an arm above. Unstyled text is the safe degradation;
1166
- // a `json()` default would colour unrelated content as if it were JSON.
1167
- default:
1168
- return [];
1169
- }
1170
- };
1171
- var shouldLintJson = (mode, readOnly) => mode === "application/json" && !readOnly;
1172
- var setSearchEffect = StateEffect.define();
1173
- function findMatches(doc, query) {
1174
- if (!query) return [];
1175
- const text = doc.toString();
1176
- try {
1177
- const regex = new RegExp(escapeStringRegexp(query), "gi");
1178
- return Array.from(text.matchAll(regex)).map((match, index) => {
1179
- const from = match.index;
1180
- const to = from + match[0].length;
1181
- return { from, to, text: match[0], localIndex: index };
1182
- });
1183
- } catch (e) {
1184
- console.warn("Invalid search regex:", e);
1185
- return [];
1186
- }
1187
- }
1188
- function createDecorations(matches, selectedLocalIndex) {
1189
- const decorations = matches.map((match) => {
1190
- const isSelected = match.localIndex === selectedLocalIndex;
1191
- const decoration = Decoration.mark({
1192
- class: isSelected ? "cm-searchMatch-selected" : "cm-searchMatch"
1193
- });
1194
- return decoration.range(match.from, match.to);
1195
- });
1196
- return Decoration.set(decorations, true);
1197
- }
1198
- var searchField = StateField.define({
1199
- create() {
1200
- return {
1201
- query: "",
1202
- selectedMatchIndex: void 0,
1203
- matches: [],
1204
- decorations: Decoration.none
1205
- };
1206
- },
1207
- update(state, tr) {
1208
- let newState = state;
1209
- for (const effect of tr.effects) {
1210
- if (!effect.is(setSearchEffect)) {
1211
- continue;
1212
- }
1213
- const { query, selectedMatchIndex } = effect.value;
1214
- const matches = findMatches(tr.state.doc, query);
1215
- const decorations = createDecorations(matches, selectedMatchIndex);
1216
- newState = {
1217
- query,
1218
- selectedMatchIndex,
1219
- matches,
1220
- decorations
1221
- };
1222
- }
1223
- if (tr.docChanged && newState.query) {
1224
- const matches = findMatches(tr.state.doc, newState.query);
1225
- const decorations = createDecorations(matches, newState.selectedMatchIndex);
1226
- newState = {
1227
- ...newState,
1228
- matches,
1229
- decorations
1230
- };
1231
- }
1232
- return newState;
1233
- },
1234
- provide: (field) => EditorView.decorations.from(field, (state) => state.decorations)
1235
- });
1236
- var searchViewPlugin = ViewPlugin.fromClass(
1237
- class {
1238
- lastSelectedIndex;
1239
- update(update) {
1240
- const state = update.state.field(searchField);
1241
- if (state.selectedMatchIndex !== void 0 && state.selectedMatchIndex !== this.lastSelectedIndex) {
1242
- const match = state.matches[state.selectedMatchIndex];
1243
- if (match) {
1244
- requestAnimationFrame(() => {
1245
- update.view.dispatch({
1246
- effects: EditorView.scrollIntoView(match.from, { y: "center" })
1247
- });
1248
- });
1249
- }
1250
- this.lastSelectedIndex = state.selectedMatchIndex;
1251
- }
1252
- if (state.selectedMatchIndex === void 0) {
1253
- this.lastSelectedIndex = void 0;
1254
- }
1255
- }
1256
- }
1257
- );
1258
- var searchTheme = EditorView.baseTheme({
1259
- ".cm-searchMatch": {
1260
- backgroundColor: colors.blue[100]
1261
- },
1262
- ".cm-searchMatch > span": {
1263
- color: `${colors.blue[600]} !important`
1264
- },
1265
- ".cm-searchMatch-selected": {
1266
- backgroundColor: colors.blue[600]
1267
- },
1268
- ".cm-searchMatch-selected > span": {
1269
- color: `${colors.white} !important`
1270
- }
1271
- });
1272
- function searchExtension() {
1273
- return [searchField, searchViewPlugin, searchTheme];
1274
- }
1275
- function updateSearch(view, query, selectedMatchIndex) {
1276
- view.dispatch({ effects: setSearchEffect.of({ query, selectedMatchIndex }) });
1277
- }
1278
- var KbdSeparator = ({ className, ...props }) => /* @__PURE__ */ jsx("span", { ...props, className: cn("tw:text-xs tw:text-muted-foreground", className) });
1279
- var KbdGroup = ({ ref, className, children, separator, ...props }) => {
1280
- return /* @__PURE__ */ jsx(
1281
- "kbd",
1282
- {
1283
- ...props,
1284
- ref,
1285
- className: cn("tw:inline-flex", "tw:items-center", "tw:gap-1", className),
1286
- children: separator ? (
1287
- // oxlint-disable-next-line react-x/no-children-to-array
1288
- Children.toArray(children).map((child, index) => (
1289
- // oxlint-disable-next-line
1290
- /* @__PURE__ */ jsxs(Fragment$1, { children: [
1291
- index > 0 && /* @__PURE__ */ jsx(KbdSeparator, { children: separator }),
1292
- child
1293
- ] }, index)
1294
- ))
1295
- ) : children
1296
- }
1297
- );
1298
- };
1299
- var kbdVariants = cva(
1300
- [
1301
- "tailwindcss-preflight",
1302
- // style
1303
- "tw:pointer-events-none",
1304
- "tw:w-fit",
1305
- "tw:h-5",
1306
- "tw:min-w-5",
1307
- // layout
1308
- "tw:inline-flex",
1309
- "tw:items-center",
1310
- "tw:justify-center",
1311
- "tw:gap-1",
1312
- "tw:shrink-0",
1313
- // spacing
1314
- "tw:px-1",
1315
- 'tw:[&_svg:not([class*="size-"])]:size-2.5',
1316
- "tw:text-xs",
1317
- "tw:font-medium",
1318
- "tw:rounded"
1319
- ],
1320
- {
1321
- defaultVariants: {
1322
- variant: "default"
1323
- },
1324
- variants: {
1325
- variant: {
1326
- default: "tw:bg-muted tw:text-muted-foreground",
1327
- primary: "tw:bg-white/20 tw:text-white"
1328
- }
1329
- }
1330
- }
1331
- );
1332
- var Kbd = ({ children, className, variant, ...rest }) => /* @__PURE__ */ jsx("kbd", { ...rest, className: kbdVariants({ className, variant }), children });
1333
- Kbd.Group = KbdGroup;
1334
- Kbd.Separator = KbdSeparator;
1335
- var ToggleComponentHelp = () => /* @__PURE__ */ jsxs("div", { children: [
1336
- "Use ",
1337
- /* @__PURE__ */ jsx(Kbd, { children: isMac ? "Command+/" : "Ctrl+/" }),
1338
- " to toggle comments."
1339
- ] });
1340
- var establishesFixedContainingBlock = (style) => style.transform !== "none" || style.translate !== "none" || style.rotate !== "none" || style.scale !== "none" || style.perspective !== "none" || style.filter !== "none" || style.backdropFilter !== "none" || /\b(paint|layout|strict|content)\b/.test(style.contain) || /\b(transform|perspective|filter|contain)\b/.test(style.willChange);
1341
- var crops = (style) => style.overflowX !== "visible" || style.overflowY !== "visible" || style.maskImage !== "none" || style.contentVisibility !== "visible" || /\b(paint|strict|content)\b/.test(style.contain);
1342
- var findTooltipHost = (from) => {
1343
- let outermostCropper = null;
1344
- for (let node = from.parentElement; node && node !== document.body; node = node.parentElement) {
1345
- const style = getComputedStyle(node);
1346
- if (crops(style)) {
1347
- outermostCropper = node;
1348
- } else if (establishesFixedContainingBlock(style)) {
1349
- return outermostCropper?.parentElement ?? node;
1350
- }
1351
- }
1352
- return outermostCropper?.parentElement ?? null;
1353
- };
1354
- var tooltipsExtension = () => {
1355
- const layer = new Compartment();
1356
- return [
1357
- layer.of(tooltips()),
1358
- ViewPlugin.define((view) => {
1359
- const scheduled = setTimeout(() => {
1360
- if (!view.dom.isConnected) return;
1361
- const parent = findTooltipHost(view.dom);
1362
- if (parent) view.dispatch({ effects: layer.reconfigure(tooltips({ parent })) });
1363
- });
1364
- return { destroy: () => clearTimeout(scheduled) };
1365
- })
1366
- ];
1367
- };
1368
- var useTooltipsExtension = () => useMemo(tooltipsExtension, []);
1369
-
1370
- // src/components/CodeEditor/variableCompletion.ts
1371
- var BOOST = 2e3;
1372
- var NAME = String.raw`[\w-]*`;
1373
- var AT_CARET = new RegExp(String.raw`(?:\{{1,2} ?)?${NAME}$`);
1374
- var NAME_AT_END = new RegExp(`${NAME}$`);
1375
- var OPENING = /\{{1,2} ?$/;
1376
- var CLOSING = /^ ?\}{1,2}/;
1377
- var completeVariables = (variables = []) => {
1378
- if (variables.length === 0) return () => null;
1379
- const options = variables.map(({ name, value }) => ({
1380
- // The bare name: `SqlEditor` filters prefix-only while `CodeEditor` filters
1381
- // fuzzily, and this is the only spelling both accept whether or not the caret
1382
- // has typed the braces. The braces are `displayLabel`, which is what renders.
1383
- label: name,
1384
- displayLabel: `{{${name}}}`,
1385
- detail: value,
1386
- type: "variable",
1387
- boost: BOOST,
1388
- apply: (view, completion, from, to) => {
1389
- const { doc } = view.state;
1390
- const line = doc.lineAt(from);
1391
- const insert = `{{${completion.label}}}`;
1392
- const opening = OPENING.exec(doc.sliceString(line.from, from));
1393
- const closing = CLOSING.exec(doc.sliceString(to, line.to));
1394
- const start = opening ? from - opening[0].length : from;
1395
- const end = closing ? to + closing[0].length : to;
1396
- view.dispatch({
1397
- changes: { from: start, to: end, insert },
1398
- selection: { anchor: start + insert.length }
1399
- });
1400
- }
1401
- }));
1402
- return (context) => {
1403
- const match = context.matchBefore(AT_CARET);
1404
- if (!match?.text) return null;
1405
- const [name = ""] = NAME_AT_END.exec(match.text) ?? [];
1406
- return { from: match.to - name.length, options };
1407
- };
1408
- };
1409
- var emptyArray = [];
1410
- var emptyObject = {};
1411
- var CodeEditor = ({
1412
- value,
1413
- previousValue,
1414
- onChange,
1415
- mode = "application/json",
1416
- placeholder: placeholder$1 = "",
1417
- ariaLabel,
1418
- searchQuery,
1419
- searchMatchIndex,
1420
- readOnly = false,
1421
- autocompletions = emptyArray,
1422
- completionSource,
1423
- variables,
1424
- extraKeys = emptyObject,
1425
- withToggleCommentHint = false,
1426
- withAutofocus = false,
1427
- withLineNumbers = true,
1428
- withLineWrapping = true,
1429
- withCollapseUnchanged = false,
1430
- withCopyButton = false,
1431
- completeAny = false,
1432
- help = null,
1433
- helpPostfix = null,
1434
- renderAdditionalButtons,
1435
- className
1436
- }) => {
1437
- const handleChange = useStableCallback((next) => onChange?.(next));
1438
- const withSearch = searchQuery !== void 0;
1439
- const editorRef = useRef(null);
1440
- useEffect(() => {
1441
- const view = editorRef.current?.view;
1442
- if (view && withSearch) updateSearch(view, searchQuery, searchMatchIndex);
1443
- }, [withSearch, searchQuery, searchMatchIndex]);
1444
- const handleCreateEditor = useStableCallback((view) => {
1445
- if (searchQuery) updateSearch(view, searchQuery, searchMatchIndex);
1446
- });
1447
- const extraKeysRef = useRef(extraKeys);
1448
- useLayoutEffect(() => {
1449
- extraKeysRef.current = extraKeys;
1450
- });
1451
- const boundKeysSignature = Object.keys(extraKeys).join("\n");
1452
- const boundKeys = useMemo(
1453
- () => boundKeysSignature.split("\n").filter(Boolean),
1454
- [boundKeysSignature]
1455
- );
1456
- const tooltipLayer = useTooltipsExtension();
1457
- const variableCompletion = useMemo(() => completeVariables(variables), [variables]);
1458
- const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
1459
- const baseTheme = useThemedExtension(
1460
- "code-editor:chrome",
1461
- () => EditorView.theme(buildBaseThemeStyles())
1462
- );
1463
- const commonExtensions = useMemo(() => {
1464
- return [
1465
- getLanguageMode(mode),
1466
- shouldLintJson(mode, readOnly) ? linter(jsonParseLinter()) : [],
1467
- withLineWrapping ? EditorView.lineWrapping : [],
1468
- EditorState.languageData.of(() => [
1469
- { autocomplete: completionSource ?? (completeAny ? completeAnyWord : autocompletions) }
1470
- ]),
1471
- EditorState.languageData.of(() => [{ autocomplete: variableCompletion }]),
1472
- keymap.of(
1473
- boundKeys.map((key) => ({
1474
- key,
1475
- run: () => {
1476
- extraKeysRef.current[key]?.();
1477
- return true;
1478
- }
1479
- }))
1480
- ),
1481
- readOnly ? [] : [
1482
- // CodeMirror's own default. Gating it on the props hid completions the
1483
- // *language* supplies — dbt's vocabulary, Snowflake's keywords — behind
1484
- // a shortcut, and macOS leaves no usable one. With nothing to offer, no
1485
- // popup opens anyway.
1486
- autocompletion()
1487
- ],
1488
- ariaLabel ? EditorView.contentAttributes.of({ "aria-label": ariaLabel }) : [],
1489
- withSearch ? searchExtension() : [],
1490
- tooltipLayer,
1491
- baseTheme
1492
- ];
1493
- }, [
1494
- autocompletions,
1495
- completionSource,
1496
- variableCompletion,
1497
- completeAny,
1498
- boundKeys,
1499
- mode,
1500
- readOnly,
1501
- withLineWrapping,
1502
- baseTheme,
1503
- ariaLabel,
1504
- withSearch,
1505
- tooltipLayer
1506
- ]);
1507
- const extensions = useMemo(() => {
1508
- return [
1509
- ...commonExtensions,
1510
- placeholder(placeholder$1),
1511
- EditorView.editable.of(!readOnly),
1512
- EditorState.readOnly.of(readOnly),
1513
- previousValue ? unifiedMergeView({
1514
- original: previousValue,
1515
- mergeControls: false,
1516
- highlightChanges: false,
1517
- collapseUnchanged: withCollapseUnchanged ? {} : void 0
1518
- }) : []
1519
- ];
1520
- }, [commonExtensions, placeholder$1, readOnly, previousValue, withCollapseUnchanged]);
1521
- const config = useMemo(() => {
1522
- return {
1523
- ...buildBasicSetup(readOnly),
1524
- lineNumbers: withLineNumbers,
1525
- // Mod-f opens CodeMirror's own panel, which would run a second query and a
1526
- // second match count over the same document beside the caller's input.
1527
- ...withSearch ? { searchKeymap: false } : null
1528
- };
1529
- }, [withLineNumbers, readOnly, withSearch]);
1530
- const additionalButtons = renderAdditionalButtons?.(value);
1531
- const hasToolbar = withCopyButton && !!value || !!additionalButtons;
1532
- return (
1533
- // oxlint-disable-next-line jsx-a11y/no-static-element-interactions
1534
- /* @__PURE__ */ jsxs(
1535
- "div",
1536
- {
1537
- className: cn(
1538
- "tw:relative tw:flex tw:min-h-0 tw:flex-col tw:[&_.cm-mergeViewEditor]:overflow-visible tw:[&_.cm-mergeViewEditors]:h-full tw:[&_.cm-mergeView]:h-full tw:[&_>div]:h-full tw:[&_>div]:overflow-auto tw:[&_>div]:bg-background",
1539
- { "tw:mt-8": hasToolbar },
1540
- className
1541
- ),
1542
- onKeyDown: (event) => {
1543
- if (event.key === keyCodes.ESCAPE) {
1544
- event.stopPropagation();
1545
- }
1546
- },
1547
- children: [
1548
- hasToolbar && /* @__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: additionalButtons }) }) }),
1549
- /* @__PURE__ */ jsx(
1550
- CodeMirror,
1551
- {
1552
- ref: editorRef,
1553
- onCreateEditor: handleCreateEditor,
1554
- theme: customTheme,
1555
- value,
1556
- onChange: handleChange,
1557
- extensions,
1558
- autoFocus: withAutofocus,
1559
- basicSetup: config
1560
- }
1561
- ),
1562
- !readOnly && (withToggleCommentHint || help || helpPostfix) && /* @__PURE__ */ jsxs(HelpBlock, { className: "tw:mt-2 tw:flex tw:flex-wrap tw:gap-1", children: [
1563
- help,
1564
- withToggleCommentHint ? /* @__PURE__ */ jsx(ToggleComponentHelp, {}) : null,
1565
- helpPostfix
1566
- ] })
1567
- ]
1568
- }
1569
- )
1570
- );
1571
- };
1572
- var activeQueryFirstLine = Decoration.line({ class: "cm-active-query cm-active-query-first" });
1573
- var activeQueryMiddleLine = Decoration.line({ class: "cm-active-query" });
1574
- var activeQueryLastLine = Decoration.line({ class: "cm-active-query cm-active-query-last" });
1575
- var activeQuerySingleLine = Decoration.line({
1576
- class: "cm-active-query cm-active-query-first cm-active-query-last"
1577
- });
1578
- var findActiveQueryRange = (doc, cursorPos, boundaries) => {
1579
- if (boundaries.length === 0) return null;
1580
- let match = boundaries[boundaries.length - 1];
1581
- for (const boundary of boundaries) {
1582
- if (cursorPos <= boundary.to) {
1583
- match = boundary;
1584
- break;
1585
- }
1586
- }
1587
- if (!match) return null;
1588
- const queryText = doc.slice(match.from, match.to);
1589
- const leadingWhitespace = queryText.length - queryText.trimStart().length;
1590
- const trailingWhitespace = queryText.length - queryText.trimEnd().length;
1591
- const trimmedStart = match.from + leadingWhitespace;
1592
- const trimmedEnd = match.to - trailingWhitespace;
1593
- if (trimmedStart >= trimmedEnd) return null;
1594
- return { from: trimmedStart, to: trimmedEnd };
1595
- };
1596
- var computeBoundaries = (queries) => {
1597
- const boundaries = [];
1598
- let offset = 0;
1599
- for (const query of queries) {
1600
- boundaries.push({ from: offset, to: offset + query.length });
1601
- offset += query.length;
1602
- }
1603
- return boundaries;
1604
- };
1605
- var mapBoundariesThroughChanges = (boundaries, changes) => {
1606
- const prevLen = changes.length;
1607
- const mapped = [];
1608
- for (const b of boundaries) {
1609
- const from = changes.mapPos(Math.max(0, Math.min(b.from, prevLen)), -1);
1610
- const to = changes.mapPos(Math.max(0, Math.min(b.to, prevLen)), 1);
1611
- if (from < to) mapped.push({ from, to });
1612
- }
1613
- return mapped;
1614
- };
1615
- var buildDecorations = (view, range) => {
1616
- const startLine = view.state.doc.lineAt(range.from).number;
1617
- const endLine = view.state.doc.lineAt(range.to).number;
1618
- const decorations = [];
1619
- for (let lineNum = startLine; lineNum <= endLine; lineNum++) {
1620
- const lineStart = view.state.doc.line(lineNum).from;
1621
- if (startLine === endLine) {
1622
- decorations.push(activeQuerySingleLine.range(lineStart));
1623
- } else if (lineNum === startLine) {
1624
- decorations.push(activeQueryFirstLine.range(lineStart));
1625
- } else if (lineNum === endLine) {
1626
- decorations.push(activeQueryLastLine.range(lineStart));
1627
- } else {
1628
- decorations.push(activeQueryMiddleLine.range(lineStart));
1629
- }
1630
- }
1631
- return Decoration.set(decorations);
1632
- };
1633
- var activeQueryHighlight = (splitQueries) => {
1634
- return [
1635
- ViewPlugin.fromClass(
1636
- class {
1637
- decorations = Decoration.none;
1638
- debounceTimer = null;
1639
- seq = 0;
1640
- cachedDoc = "";
1641
- cachedBoundaries = [];
1642
- destroyed = false;
1643
- constructor(view) {
1644
- this.scheduleDocParse(view);
1645
- }
1646
- update(update) {
1647
- if (update.focusChanged && !update.view.hasFocus) {
1648
- this.decorations = Decoration.none;
1649
- return;
1650
- }
1651
- if (update.docChanged) {
1652
- if (this.cachedBoundaries.length > 0) {
1653
- this.cachedBoundaries = mapBoundariesThroughChanges(
1654
- this.cachedBoundaries,
1655
- update.changes
1656
- );
1657
- this.cachedDoc = update.state.doc.toString();
1658
- this.updateFromCache(update.view);
1659
- }
1660
- this.scheduleDocParse(update.view);
1661
- } else if (update.selectionSet || update.focusChanged && update.view.hasFocus) {
1662
- this.updateFromCache(update.view);
1663
- }
1664
- }
1665
- destroy() {
1666
- this.destroyed = true;
1667
- if (this.debounceTimer) clearTimeout(this.debounceTimer);
1668
- }
1669
- /**
1670
- * Update decorations using cached query boundaries.
1671
- * Only mutates this.decorations — does NOT call view.dispatch().
1672
- * When called from update() (sync), CodeMirror picks up the new
1673
- * decorations via the accessor. When called from the async
1674
- * scheduleDocParse callback, the caller must dispatch separately.
1675
- */
1676
- updateFromCache(view) {
1677
- if (!view.hasFocus) {
1678
- this.decorations = Decoration.none;
1679
- return;
1680
- }
1681
- const { main } = view.state.selection;
1682
- if (main.from !== main.to) {
1683
- this.decorations = Decoration.none;
1684
- return;
1685
- }
1686
- const doc = view.state.doc.toString();
1687
- if (doc !== this.cachedDoc) return;
1688
- if (this.cachedBoundaries.length === 0) {
1689
- this.decorations = Decoration.none;
1690
- return;
1691
- }
1692
- const range = findActiveQueryRange(doc, main.head, this.cachedBoundaries);
1693
- this.decorations = range ? buildDecorations(view, range) : Decoration.none;
1694
- }
1695
- /** Parse queries async (debounced) and update decorations. */
1696
- scheduleDocParse(view) {
1697
- if (this.debounceTimer) clearTimeout(this.debounceTimer);
1698
- this.debounceTimer = setTimeout(async () => {
1699
- const seq = ++this.seq;
1700
- const doc = view.state.doc.toString();
1701
- if (!doc.trim()) {
1702
- this.cachedDoc = doc;
1703
- this.cachedBoundaries = [];
1704
- if (this.decorations !== Decoration.none) {
1705
- this.decorations = Decoration.none;
1706
- if (!this.destroyed) view.dispatch();
1707
- }
1708
- return;
1709
- }
1710
- let queries;
1711
- try {
1712
- queries = await splitQueries(doc);
1713
- } catch {
1714
- return;
1715
- }
1716
- if (this.destroyed || seq !== this.seq) return;
1717
- this.cachedDoc = doc;
1718
- this.cachedBoundaries = computeBoundaries(queries);
1719
- this.updateFromCache(view);
1720
- if (!this.destroyed) view.dispatch();
1721
- }, 100);
1722
- }
1723
- },
1724
- { decorations: (v) => v.decorations }
1725
- ),
1726
- EditorView.baseTheme({
1727
- ".cm-active-query": {
1728
- boxShadow: `inset -1px 0 0 0 ${colors.blue[300]}, inset 1px 0 0 0 ${colors.blue[300]}`,
1729
- marginRight: "8px"
1730
- },
1731
- ".cm-active-query-first": {
1732
- boxShadow: `inset -1px 0 0 0 ${colors.blue[300]}, inset 1px 0 0 0 ${colors.blue[300]}, inset 0 1px 0 0 ${colors.blue[300]}`,
1733
- borderRadius: "4px 4px 0 0"
1734
- },
1735
- ".cm-active-query-last": {
1736
- boxShadow: `inset -1px 0 0 0 ${colors.blue[300]}, inset 1px 0 0 0 ${colors.blue[300]}, inset 0 -1px 0 0 ${colors.blue[300]}`,
1737
- borderRadius: "0 0 4px 4px"
1738
- },
1739
- ".cm-active-query-first.cm-active-query-last": {
1740
- boxShadow: `inset 0 0 0 1px ${colors.blue[300]}`,
1741
- borderRadius: "4px"
1742
- }
1743
- })
1744
- ];
1745
- };
1746
-
1747
- // src/components/CodeEditor/highlighting.ts
1748
- var HighlightMarker = class extends GutterMarker {
1749
- toDOM() {
1750
- const marker = document.createElement("div");
1751
- marker.className = "cm-highlight-marker";
1752
- return marker;
1753
- }
1754
- };
1755
- var highlightMarker = new HighlightMarker();
1756
- var forEachLineInRange = (doc, from, to, callback) => {
1757
- const results = [];
1758
- const fromLine = Math.max(1, from + 1);
1759
- const toLine = Math.min(doc.lines, to + 1);
1760
- for (let i = fromLine; i <= toLine; i++) {
1761
- const line = doc.line(i);
1762
- results.push(callback(line.from));
1763
- }
1764
- return results;
1765
- };
1766
- var setHighlightedLinesEffect = StateEffect.define();
1767
- var highlightedLinesField = StateField.define({
1768
- create() {
1769
- return null;
1770
- },
1771
- update(value, transaction) {
1772
- for (const effect of transaction.effects) {
1773
- if (effect.is(setHighlightedLinesEffect)) {
1774
- return effect.value;
1775
- }
1776
- }
1777
- return value;
1778
- }
1779
- });
1780
- var highlightGutter = gutter({
1781
- class: "cm-highlight-gutter",
1782
- markers: (view) => {
1783
- const highlightInfo = view.state.field(highlightedLinesField, false);
1784
- if (!highlightInfo) {
1785
- return RangeSet.empty;
1786
- }
1787
- const markers = forEachLineInRange(
1788
- view.state.doc,
1789
- highlightInfo.from,
1790
- highlightInfo.to,
1791
- (lineFrom) => highlightMarker.range(lineFrom)
1792
- );
1793
- return RangeSet.of(markers);
1794
- }
1795
- });
1796
- var errorLineDecorations = StateField.define({
1797
- create() {
1798
- return Decoration.none;
1799
- },
1800
- update(decorations, transaction) {
1801
- decorations = decorations.map(transaction.changes);
1802
- for (const effect of transaction.effects) {
1803
- if (!effect.is(setHighlightedLinesEffect)) {
1804
- continue;
1805
- }
1806
- if (!effect.value || !effect.value.error) {
1807
- return Decoration.none;
1808
- }
1809
- const decorationArray = forEachLineInRange(
1810
- transaction.state.doc,
1811
- effect.value.error.from,
1812
- effect.value.error.to,
1813
- (lineFrom) => Decoration.line({ class: "cm-error-line" }).range(lineFrom)
1814
- );
1815
- return Decoration.set(decorationArray);
1816
- }
1817
- return decorations;
1818
- },
1819
- provide: (f) => EditorView.decorations.from(f)
1820
- });
1821
- var processingLineDecorations = StateField.define({
1822
- create() {
1823
- return Decoration.none;
1824
- },
1825
- update(decorations, transaction) {
1826
- decorations = decorations.map(transaction.changes);
1827
- for (const effect of transaction.effects) {
1828
- if (!effect.is(setHighlightedLinesEffect)) {
1829
- continue;
1830
- }
1831
- if (!effect.value || !effect.value.processing) {
1832
- return Decoration.none;
1833
- }
1834
- const decorationArray = forEachLineInRange(
1835
- transaction.state.doc,
1836
- effect.value.processing.from,
1837
- effect.value.processing.to,
1838
- (lineFrom) => Decoration.line({ class: "cm-processing-line" }).range(lineFrom)
1839
- );
1840
- return Decoration.set(decorationArray);
1841
- }
1842
- return decorations;
1843
- },
1844
- provide: (f) => EditorView.decorations.from(f)
1845
- });
1846
- var highlightedLinesTheme = EditorView.baseTheme({
1847
- ".cm-highlight-gutter": {
1848
- width: "2px",
1849
- marginRight: "2px"
1850
- },
1851
- ".cm-highlight-marker": {
1852
- width: "2px",
1853
- height: "100%",
1854
- backgroundColor: colors.blue[500]
1855
- },
1856
- ".cm-error-line": {
1857
- backgroundColor: `${colors.error[100]} !important`
1858
- },
1859
- ".cm-processing-line": {
1860
- backgroundColor: `${colors.blue[100]} !important`
1861
- }
1862
- });
1863
- function highlightingExtension(queryParser) {
1864
- return [
1865
- highlightedLinesField,
1866
- highlightGutter,
1867
- errorLineDecorations,
1868
- processingLineDecorations,
1869
- highlightedLinesTheme,
1870
- ...queryParser ? activeQueryHighlight(queryParser) : []
1871
- ];
1872
- }
1873
- function updateHighlighting(view, lines) {
1874
- view.dispatch({ effects: setHighlightedLinesEffect.of(lines ?? null) });
1875
- }
1876
- var OWN_KEYMAPS = {
1877
- defaultKeymap: false,
1878
- completionKeymap: false,
1879
- searchKeymap: false
1880
- };
1881
- var CUSTOM_KEYMAP = [
1882
- {
1883
- key: "Escape",
1884
- stopPropagation: true,
1885
- run: (view) => {
1886
- view.contentDOM.blur();
1887
- return true;
1888
- }
1889
- }
1890
- ];
1891
- var buildTheme = () => ({
1892
- ...buildBaseThemeStyles(),
1893
- "&.cm-editor": {
1894
- border: "solid 1px transparent",
1895
- background: resolveToken("card", "255 255 255"),
1896
- borderRadius: "8px",
1897
- paddingTop: "8px",
1898
- paddingBottom: "8px"
1899
- },
1900
- '&.cm-editor:has(.cm-content[contenteditable="true"]):hover': {
1901
- borderColor: resolveToken("ring", "31 143 255")
1902
- },
1903
- '&.cm-editor:has(.cm-content[contenteditable="true"]):focus-within': {
1904
- borderColor: resolveToken("ring", "31 143 255"),
1905
- boxShadow: `0 0 0 4px ${resolveToken("ring", "31 143 255", 0.3)}`
1906
- },
1907
- "&.cm-editor .cm-scroller": { overflowAnchor: "none" },
1908
- "&.cm-editor :is(.cm-gutters,.cm-scroller)": { background: resolveToken("card", "255 255 255") },
1909
- '&.cm-editor:has(.cm-content[contenteditable="false"])': {
1910
- background: resolveToken("muted", "241 245 249")
1911
- },
1912
- '&.cm-editor:has(.cm-content[contenteditable="false"]) :is(.cm-scroller,.cm-gutters)': {
1913
- background: resolveToken("muted", "241 245 249")
1914
- }
1915
- });
1916
- var SqlEditor = ({
1917
- value,
1918
- onChange,
1919
- onSelectionChange,
1920
- onCreateEditor,
1921
- onDestroyEditor,
1922
- onBlurEditor,
1923
- onFocusEditor,
1924
- placeholder = "",
1925
- searchQuery = "",
1926
- searchMatchIndex,
1927
- readOnly = false,
1928
- extraKeys,
1929
- queryParser,
1930
- autoFocus = false,
1931
- lineNumbers = true,
1932
- className,
1933
- schema,
1934
- variables,
1935
- defaultDatabase,
1936
- defaultSchema,
1937
- highlightLines,
1938
- dialect
1939
- }) => {
1940
- const editorRef = useRef(null);
1941
- const tooltipLayer = useTooltipsExtension();
1942
- const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
1943
- const themeExtension = useThemedExtension(
1944
- "sql-editor:chrome",
1945
- () => EditorView$1.theme(buildTheme())
1946
- );
1947
- const extensions = useMemo(() => {
1948
- const baseKeymap = [...defaultKeymap, ...CUSTOM_KEYMAP];
1949
- return [
1950
- EditorView$1.lineWrapping,
1951
- keymap$1.of(extraKeys ? [...extraKeys, ...baseKeymap] : baseKeymap),
1952
- ...installExtensions({
1953
- schema,
1954
- defaultDatabase,
1955
- defaultSchema,
1956
- variableCompletion: completeVariables(variables),
1957
- dialect
1958
- }),
1959
- searchExtension(),
1960
- highlightingExtension(queryParser),
1961
- tooltipLayer,
1962
- themeExtension,
1963
- onBlurEditor ? EditorView$1.domEventHandlers({ blur: (_, view) => onBlurEditor(view) }) : [],
1964
- onFocusEditor ? EditorView$1.domEventHandlers({ focus: (_, view) => onFocusEditor(view) }) : []
1965
- ];
1966
- }, [
1967
- extraKeys,
1968
- queryParser,
1969
- schema,
1970
- defaultDatabase,
1971
- defaultSchema,
1972
- variables,
1973
- dialect,
1974
- onBlurEditor,
1975
- onFocusEditor,
1976
- themeExtension,
1977
- tooltipLayer
1978
- ]);
1979
- const defaultSetup = useMemo(() => {
1980
- return { ...buildBasicSetup(readOnly), ...OWN_KEYMAPS, lineNumbers };
1981
- }, [readOnly, lineNumbers]);
1982
- useEffect(() => {
1983
- if (editorRef.current?.view) {
1984
- updateHighlighting(editorRef.current.view, highlightLines);
1985
- }
1986
- }, [highlightLines]);
1987
- useEffect(() => {
1988
- if (editorRef.current?.view) {
1989
- updateSearch(editorRef.current.view, searchQuery, searchMatchIndex);
1990
- }
1991
- }, [searchQuery, searchMatchIndex]);
1992
- useEffect(() => {
1993
- if (!onDestroyEditor) return;
1994
- return () => {
1995
- onDestroyEditor();
1996
- };
1997
- }, [onDestroyEditor]);
1998
- const handleOnCreate = useCallback(
1999
- (view, state) => {
2000
- onCreateEditor?.(view, state);
2001
- if (highlightLines) {
2002
- updateHighlighting(view, highlightLines);
2003
- }
2004
- if (searchQuery) {
2005
- updateSearch(view, searchQuery, searchMatchIndex);
2006
- }
2007
- },
2008
- [onCreateEditor, highlightLines, searchQuery, searchMatchIndex]
2009
- );
2010
- const handleOnUpdate = useCallback(
2011
- (update) => {
2012
- if (update.selectionSet) {
2013
- const { main } = update.state.selection;
2014
- const text = update.state.sliceDoc(main.from, main.to);
2015
- onSelectionChange?.(text);
2016
- }
2017
- },
2018
- [onSelectionChange]
2019
- );
2020
- return /* @__PURE__ */ jsx(
2021
- CodeMirror,
2022
- {
2023
- ref: editorRef,
2024
- theme: customTheme,
2025
- extensions,
2026
- value,
2027
- onChange,
2028
- onUpdate: handleOnUpdate,
2029
- onCreateEditor: handleOnCreate,
2030
- autoFocus,
2031
- placeholder,
2032
- className,
2033
- readOnly,
2034
- editable: !readOnly,
2035
- basicSetup: defaultSetup
2036
- }
2037
- );
2038
- };
2039
-
2040
- // src/components/MergeEditor/constants.ts
2041
- var CHANGE_CLASS = {
2042
- SAFE: "safe"};
2043
- var LINE_HEIGHT_PX = 20;
2044
- var PANE_HEADER_HEIGHT_PX = 58;
2045
18
  var AcceptButton = ({ side, onAccept }) => {
2046
19
  const label = `Accept ${side === "left" ? "production" : "branch"} version`;
2047
20
  const Chevron = side === "left" ? ChevronsRight : ChevronsLeft;
@@ -2096,62 +69,70 @@ var ConflictGutterMarker = class extends GutterMarker {
2096
69
  };
2097
70
  var safeGutterMarker = new SafeGutterMarker();
2098
71
  var conflictGutterMarker = new ConflictGutterMarker();
2099
- var createDiffHighlightExtension = () => {
2100
- const field = StateField.define({
2101
- create: () => ({ decorations: Decoration.none, gutterMarkers: RangeSet.empty }),
2102
- update(value, tr) {
2103
- let payload = null;
2104
- for (const effect of tr.effects) {
2105
- if (effect.is(setHighlightedLines)) {
2106
- payload = effect.value;
2107
- }
2108
- }
2109
- if (!payload) {
2110
- return {
2111
- decorations: value.decorations.map(tr.changes),
2112
- gutterMarkers: value.gutterMarkers.map(tr.changes)
2113
- };
2114
- }
2115
- const decoBuilder = new RangeSetBuilder();
2116
- const gutterBuilder = new RangeSetBuilder();
2117
- const doc = tr.state.doc;
2118
- const { lines, classification } = payload;
2119
- const sorted = [...lines].filter((l) => l >= 1 && l <= doc.lines).sort((a, b) => a - b);
2120
- for (const i of sorted) {
2121
- const cls = classification.get(i);
2122
- if (!cls) continue;
2123
- const isSafe = cls === CHANGE_CLASS.SAFE;
2124
- const line = doc.line(i);
2125
- decoBuilder.add(line.from, line.from, isSafe ? safeDecoration : conflictDecoration);
2126
- gutterBuilder.add(line.from, line.from, isSafe ? safeGutterMarker : conflictGutterMarker);
72
+ var createDiffHighlightExtension = () => StateField.define({
73
+ create: () => ({ decorations: Decoration.none, gutterMarkers: RangeSet.empty }),
74
+ update(value, tr) {
75
+ let payload = null;
76
+ for (const effect of tr.effects) {
77
+ if (effect.is(setHighlightedLines)) {
78
+ payload = effect.value;
2127
79
  }
80
+ }
81
+ if (!payload) {
2128
82
  return {
2129
- decorations: decoBuilder.finish(),
2130
- gutterMarkers: gutterBuilder.finish()
83
+ decorations: value.decorations.map(tr.changes),
84
+ gutterMarkers: value.gutterMarkers.map(tr.changes)
2131
85
  };
2132
- },
2133
- provide: (f) => [
2134
- EditorView.decorations.from(f, (val) => val.decorations),
2135
- gutterLineClass.from(f, (val) => val.gutterMarkers)
2136
- ]
2137
- });
2138
- const theme = EditorView.theme({
86
+ }
87
+ const decoBuilder = new RangeSetBuilder();
88
+ const gutterBuilder = new RangeSetBuilder();
89
+ const doc = tr.state.doc;
90
+ const { lines, classification } = payload;
91
+ const sorted = [...lines].filter((l) => l >= 1 && l <= doc.lines).sort((a, b) => a - b);
92
+ for (const i of sorted) {
93
+ const cls = classification.get(i);
94
+ if (!cls) continue;
95
+ const isSafe = cls === CHANGE_CLASS.SAFE;
96
+ const line = doc.line(i);
97
+ decoBuilder.add(line.from, line.from, isSafe ? safeDecoration : conflictDecoration);
98
+ gutterBuilder.add(line.from, line.from, isSafe ? safeGutterMarker : conflictGutterMarker);
99
+ }
100
+ return {
101
+ decorations: decoBuilder.finish(),
102
+ gutterMarkers: gutterBuilder.finish()
103
+ };
104
+ },
105
+ provide: (f) => [
106
+ EditorView.decorations.from(f, (val) => val.decorations),
107
+ gutterLineClass.from(f, (val) => val.gutterMarkers)
108
+ ]
109
+ });
110
+ var DARK_LINE_ALPHA = "29";
111
+ var DARK_GUTTER_ALPHA = "47";
112
+ var buildDiffHighlightTheme = () => {
113
+ const dark = isDarkScheme();
114
+ const line = (hue, pastel) => dark ? `${hue}${DARK_LINE_ALPHA}` : pastel;
115
+ const gutter = (hue, pastel) => dark ? `${hue}${DARK_GUTTER_ALPHA}` : pastel;
116
+ const safeNumber = dark ? colors.green[300] : colors.green[900];
117
+ const conflictNumber = dark ? colors.warning[300] : colors.warning[800];
118
+ return EditorView.theme({
2139
119
  ".cm-merge-safe-line": {
2140
- backgroundColor: `${colors.green[100]} !important`,
120
+ backgroundColor: `${line(colors.green[500], colors.green[100])} !important`,
2141
121
  boxShadow: `inset 3px 0 0 ${colors.green[500]}`
2142
122
  },
2143
123
  ".cm-merge-conflict-line": {
2144
- backgroundColor: `${colors.warning[100]} !important`,
124
+ backgroundColor: `${line(colors.warning[500], colors.warning[100])} !important`,
2145
125
  boxShadow: `inset 3px 0 0 ${colors.warning[500]}`
2146
126
  },
2147
127
  ".cm-merge-safe-gutter": {
2148
- backgroundColor: `${colors.green[200]} !important`
128
+ backgroundColor: `${gutter(colors.green[500], colors.green[200])} !important`,
129
+ color: safeNumber
2149
130
  },
2150
131
  ".cm-merge-conflict-gutter": {
2151
- backgroundColor: `${colors.warning[200]} !important`
132
+ backgroundColor: `${gutter(colors.warning[500], colors.warning[200])} !important`,
133
+ color: conflictNumber
2152
134
  }
2153
135
  });
2154
- return [field, theme];
2155
136
  };
2156
137
  var updateHighlightedLines = (view, lines, classification) => {
2157
138
  view.dispatch({ effects: setHighlightedLines.of({ lines, classification }) });
@@ -2172,27 +153,30 @@ var MergePane = ({
2172
153
  }) => {
2173
154
  const editorRef = useRef(null);
2174
155
  const handleChange = useStableCallback((next) => onChange?.(next));
2175
- const themeExtension = useThemedExtension(
2176
- `merge-pane:${deleted}`,
2177
- () => EditorView.theme({
156
+ const themeExtension = useThemedExtension(`merge-pane:${deleted}`, () => {
157
+ const dark = isDarkScheme();
158
+ const deletedSurface = dark ? `${colors.error[500]}1f` : colors.error[100];
159
+ const deletedGutter = dark ? `${colors.error[500]}3d` : colors.error[200];
160
+ const deletedGutterText = dark ? colors.error[300] : colors.error[700];
161
+ return EditorView.theme({
2178
162
  "&.cm-editor": {
2179
163
  height: "100%",
2180
- backgroundColor: deleted ? colors.error[100] : resolveToken("background", "249 250 251"),
164
+ backgroundColor: deleted ? deletedSurface : resolveToken("background", "249 250 251"),
2181
165
  // Pair the token-driven surface with a token-driven text color so line
2182
166
  // content stays readable when the pane's `--background` goes dark.
2183
- // The deleted pane keeps default dark text on its fixed light-red wash.
2184
- ...deleted ? {} : { color: resolveToken("foreground", "30 41 59") },
167
+ color: resolveToken("foreground", "30 41 59"),
2185
168
  outline: "none"
2186
169
  },
2187
170
  ".cm-gutters": {
2188
- backgroundColor: deleted ? colors.error[200] : resolveToken("muted", "241 245 249"),
2189
- ...deleted ? {} : { color: resolveToken("muted-foreground", "100 116 139") }
171
+ backgroundColor: deleted ? deletedGutter : resolveToken("muted", "241 245 249"),
172
+ color: deleted ? deletedGutterText : resolveToken("muted-foreground", "100 116 139")
2190
173
  },
2191
174
  "*": { lineHeight: `${LINE_HEIGHT_PX}px` },
2192
175
  ".cm-lineNumbers .cm-gutterElement": { padding: "0 0 0 25px" }
2193
- })
2194
- );
176
+ });
177
+ });
2195
178
  const diffHighlightExtension = useMemo(() => createDiffHighlightExtension(), []);
179
+ const diffHighlightTheme = useThemedExtension("merge-diff-highlight", buildDiffHighlightTheme);
2196
180
  const basicSetup = useMemo(
2197
181
  () => ({ ...buildBasicSetup(readOnly), lineNumbers: true }),
2198
182
  [readOnly]
@@ -2200,6 +184,7 @@ var MergePane = ({
2200
184
  const extensions = useMemo(
2201
185
  () => [
2202
186
  diffHighlightExtension,
187
+ diffHighlightTheme,
2203
188
  themeExtension,
2204
189
  // Recalc viewport after every doc change so late-settling layouts (alerts
2205
190
  // appearing above the editor) don't leave trailing lines blank.
@@ -2209,7 +194,7 @@ var MergePane = ({
2209
194
  }
2210
195
  })
2211
196
  ],
2212
- [diffHighlightExtension, themeExtension]
197
+ [diffHighlightExtension, diffHighlightTheme, themeExtension]
2213
198
  );
2214
199
  useEffect(() => {
2215
200
  const view = editorRef.current?.view;
@@ -2248,7 +233,7 @@ var MergePane = ({
2248
233
  className: cn(
2249
234
  "tw:flex tw:min-w-0 tw:flex-1 tw:flex-col tw:overflow-hidden",
2250
235
  className,
2251
- deleted && "tw:border-error-300"
236
+ deleted && "tw:border-error-300 tw:[[data-theme=dark]_&]:border-error-500/50"
2252
237
  ),
2253
238
  children: [
2254
239
  header && /* @__PURE__ */ jsx(
@@ -2256,7 +241,10 @@ var MergePane = ({
2256
241
  {
2257
242
  className: cn(
2258
243
  "tw:px-4 tw:py-3",
2259
- deleted ? "tw:border-b tw:border-error-200 tw:bg-error-100" : "tw:bg-background",
244
+ // Same light/dark split as the editor wash below — `PaneHeader` pins
245
+ // `text-foreground`, which goes near-white and vanishes on the
246
+ // opaque light-red band.
247
+ deleted ? "tw:border-b tw:border-error-200 tw:bg-error-100 tw:[[data-theme=dark]_&]:border-error-500/30 tw:[[data-theme=dark]_&]:bg-error-500/15" : "tw:bg-background",
2260
248
  headerClassName
2261
249
  ),
2262
250
  children: header
@@ -2440,6 +428,6 @@ var MergeEditor = ({
2440
428
  );
2441
429
  };
2442
430
 
2443
- export { CodeEditor, LANGUAGE_MODES, MergeEditor, SqlEditor, isLanguageMode };
431
+ export { MergeEditor };
2444
432
  //# sourceMappingURL=editors.js.map
2445
433
  //# sourceMappingURL=editors.js.map