@keboola/design 9.1.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.
- package/AGENTS.md +117 -40
- package/COMPONENT-API.md +31 -9
- package/README.md +3 -3
- package/dist/MermaidDiagram-EOKJHQQV.js +10 -0
- package/dist/MermaidDiagram-EOKJHQQV.js.map +1 -0
- package/dist/charts.d.ts +31 -2
- package/dist/charts.js +6 -9
- package/dist/charts.js.map +1 -1
- package/dist/chunk-63NSN2VL.js +274 -0
- package/dist/chunk-63NSN2VL.js.map +1 -0
- package/dist/{rjsf.cjs → chunk-6FPEI4EM.js} +1491 -5701
- package/dist/chunk-6FPEI4EM.js.map +1 -0
- package/dist/chunk-7PUUHEJQ.js +1313 -0
- package/dist/chunk-7PUUHEJQ.js.map +1 -0
- package/dist/chunk-BOHNXTMM.js +606 -0
- package/dist/chunk-BOHNXTMM.js.map +1 -0
- package/dist/{testing.cjs → chunk-C3L3TBBT.js} +33 -164
- package/dist/chunk-C3L3TBBT.js.map +1 -0
- package/dist/chunk-CTCFYWJC.js +407 -0
- package/dist/chunk-CTCFYWJC.js.map +1 -0
- package/dist/chunk-ESBL3IPF.js +23 -0
- package/dist/chunk-ESBL3IPF.js.map +1 -0
- package/dist/chunk-IJTHFNNJ.js +261 -0
- package/dist/chunk-IJTHFNNJ.js.map +1 -0
- package/dist/chunk-JP7PNHLH.js +40 -0
- package/dist/chunk-JP7PNHLH.js.map +1 -0
- package/dist/chunk-KPNAW5MU.js +229 -0
- package/dist/chunk-KPNAW5MU.js.map +1 -0
- package/dist/chunk-L37JJ6MR.js +152 -0
- package/dist/chunk-L37JJ6MR.js.map +1 -0
- package/dist/chunk-Q7NWXLCT.js +90 -0
- package/dist/chunk-Q7NWXLCT.js.map +1 -0
- package/dist/chunk-SYIEF644.js +1016 -0
- package/dist/chunk-SYIEF644.js.map +1 -0
- package/dist/chunk-VMFSRV5H.js +16 -0
- package/dist/chunk-VMFSRV5H.js.map +1 -0
- package/dist/chunk-VPPM7UUQ.js +47 -0
- package/dist/chunk-VPPM7UUQ.js.map +1 -0
- package/dist/chunk-XV3UUOYF.js +845 -0
- package/dist/chunk-XV3UUOYF.js.map +1 -0
- package/dist/editors.d.ts +27 -3
- package/dist/editors.js +85 -2081
- package/dist/editors.js.map +1 -1
- package/dist/icons.d.ts +29 -8
- package/dist/icons.js +2 -361
- package/dist/icons.js.map +1 -1
- package/dist/index.d.ts +709 -425
- package/dist/index.js +5042 -13885
- package/dist/index.js.map +1 -1
- package/dist/markdown-editor.js +41 -3426
- package/dist/markdown-editor.js.map +1 -1
- package/dist/mermaid.js +8 -1129
- package/dist/mermaid.js.map +1 -1
- package/dist/rjsf.js +180 -9381
- package/dist/rjsf.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/testing.js +5 -357
- package/dist/testing.js.map +1 -1
- package/package.json +28 -73
- package/src/styles.css +60 -3
- package/src/theme.css +1 -0
- package/dist/charts.cjs +0 -268
- package/dist/charts.cjs.map +0 -1
- package/dist/charts.d.cts +0 -181
- package/dist/constants-D3gaMY-W.d.cts +0 -39
- package/dist/editors.cjs +0 -2440
- package/dist/editors.cjs.map +0 -1
- package/dist/editors.d.cts +0 -165
- package/dist/icons.cjs +0 -23888
- package/dist/icons.cjs.map +0 -1
- package/dist/icons.d.cts +0 -20
- package/dist/index.cjs +0 -24894
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -10438
- package/dist/markdown-editor.cjs +0 -4636
- package/dist/markdown-editor.cjs.map +0 -1
- package/dist/markdown-editor.d.cts +0 -75
- package/dist/mermaid.cjs +0 -1138
- package/dist/mermaid.cjs.map +0 -1
- package/dist/mermaid.d.cts +0 -15
- package/dist/rjsf.cjs.map +0 -1
- package/dist/rjsf.d.cts +0 -55
- package/dist/testing.cjs.map +0 -1
- package/dist/testing.d.cts +0 -25
|
@@ -0,0 +1,1313 @@
|
|
|
1
|
+
import { escapeStringRegexp, useStableCallback, Kbd, isMac } from './chunk-Q7NWXLCT.js';
|
|
2
|
+
import { ClipboardButton } from './chunk-L37JJ6MR.js';
|
|
3
|
+
import { HelpBlock } from './chunk-ESBL3IPF.js';
|
|
4
|
+
import { useArgoDesign, keyCodes } from './chunk-63NSN2VL.js';
|
|
5
|
+
import { cn } from './chunk-JP7PNHLH.js';
|
|
6
|
+
import { javascript } from '@codemirror/lang-javascript';
|
|
7
|
+
import { jsonParseLinter, json } from '@codemirror/lang-json';
|
|
8
|
+
import { python } from '@codemirror/lang-python';
|
|
9
|
+
import { PLSQL, MSSQL, PostgreSQL, MySQL, StandardSQL } from '@codemirror/lang-sql';
|
|
10
|
+
import { StreamLanguage } from '@codemirror/language';
|
|
11
|
+
import { r } from '@codemirror/legacy-modes/mode/r';
|
|
12
|
+
import { shell } from '@codemirror/legacy-modes/mode/shell';
|
|
13
|
+
import { toml } from '@codemirror/legacy-modes/mode/toml';
|
|
14
|
+
import { tags } from '@lezer/highlight';
|
|
15
|
+
import { githubLightInit } from '@uiw/codemirror-theme-github';
|
|
16
|
+
import { installExtensions, getSqlLanguageSupport } from '@keboola/codemirror-lang-sql';
|
|
17
|
+
import colors from '@keboola/tailwind-config/colors';
|
|
18
|
+
import { simpleMode } from '@codemirror/legacy-modes/mode/simple-mode';
|
|
19
|
+
import { useRef, useEffect, useLayoutEffect, useMemo, useSyncExternalStore } from 'react';
|
|
20
|
+
import { completeAnyWord, autocompletion } from '@codemirror/autocomplete';
|
|
21
|
+
import { linter } from '@codemirror/lint';
|
|
22
|
+
import { unifiedMergeView } from '@codemirror/merge';
|
|
23
|
+
import { EditorView, Decoration, ViewPlugin, gutter, GutterMarker, keymap as keymap$1, placeholder, tooltips } from '@codemirror/view';
|
|
24
|
+
import CodeMirror, { keymap, EditorState, EditorView as EditorView$1 } from '@uiw/react-codemirror';
|
|
25
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
26
|
+
import { StateEffect, StateField, RangeSet, Compartment } from '@codemirror/state';
|
|
27
|
+
import { defaultKeymap } from '@codemirror/commands';
|
|
28
|
+
|
|
29
|
+
var COMMANDS = [
|
|
30
|
+
"run-operation",
|
|
31
|
+
"run",
|
|
32
|
+
"test",
|
|
33
|
+
"seed",
|
|
34
|
+
"snapshot",
|
|
35
|
+
"list",
|
|
36
|
+
"ls",
|
|
37
|
+
"compile",
|
|
38
|
+
"build",
|
|
39
|
+
"deps",
|
|
40
|
+
"docs",
|
|
41
|
+
"source"
|
|
42
|
+
];
|
|
43
|
+
var SUBCOMMANDS = { docs: ["generate"], source: ["freshness"] };
|
|
44
|
+
var ARGUMENTS = ["--select", "--exclude", "--selector", "--defer", "--resource-type", "-s"];
|
|
45
|
+
var SELECTORS = ["--select", "--exclude", "-s"];
|
|
46
|
+
var METHODS = [
|
|
47
|
+
"path:",
|
|
48
|
+
"source:",
|
|
49
|
+
"tag:",
|
|
50
|
+
"package:",
|
|
51
|
+
"config:",
|
|
52
|
+
"test_type:",
|
|
53
|
+
"test_name:",
|
|
54
|
+
"state:",
|
|
55
|
+
"exposure:",
|
|
56
|
+
"metric:",
|
|
57
|
+
"result:",
|
|
58
|
+
"source_status:",
|
|
59
|
+
"column_name:"
|
|
60
|
+
];
|
|
61
|
+
var FLAGS = [
|
|
62
|
+
"--fail-fast",
|
|
63
|
+
"--warn-error",
|
|
64
|
+
"--favor-state",
|
|
65
|
+
"--vars",
|
|
66
|
+
"--models",
|
|
67
|
+
"--threads",
|
|
68
|
+
"--profiles-dir",
|
|
69
|
+
"--profile",
|
|
70
|
+
"--full-refresh"
|
|
71
|
+
];
|
|
72
|
+
var COMMAND_PHRASES = COMMANDS.flatMap((command) => {
|
|
73
|
+
const subcommands = SUBCOMMANDS[command];
|
|
74
|
+
return subcommands ? subcommands.map((subcommand) => `${command} ${subcommand}`) : [command];
|
|
75
|
+
});
|
|
76
|
+
var alternation = (list) => [...list].sort((a, b) => b.length - a.length).join("|");
|
|
77
|
+
var word = (list) => new RegExp(`^\\s+(?:${alternation(list)})\\b`, "i");
|
|
78
|
+
var prefix = (list) => new RegExp(`^\\s+(?:${alternation(list)})`, "i");
|
|
79
|
+
var WORD = /[\w:-]*$/;
|
|
80
|
+
var asOptions = (list, type) => list.map((label) => ({ label, type }));
|
|
81
|
+
var DBT = [{ label: "dbt", type: "keyword" }];
|
|
82
|
+
var COMMAND_OPTIONS = asOptions(COMMANDS, "keyword");
|
|
83
|
+
var SUBCOMMAND_OPTIONS = Object.fromEntries(
|
|
84
|
+
Object.entries(SUBCOMMANDS).map(([command, subcommands]) => [
|
|
85
|
+
command,
|
|
86
|
+
asOptions(subcommands, "keyword")
|
|
87
|
+
])
|
|
88
|
+
);
|
|
89
|
+
var ARGUMENT_OPTIONS = asOptions(ARGUMENTS, "variable");
|
|
90
|
+
var FLAG_OPTIONS = asOptions(FLAGS, "constant");
|
|
91
|
+
var METHOD_OPTIONS = asOptions(METHODS, "property");
|
|
92
|
+
var optionsAfter = (words) => {
|
|
93
|
+
const [step, command, ...rest] = words;
|
|
94
|
+
if (step === void 0) return DBT;
|
|
95
|
+
if (step.toLowerCase() !== "dbt") return [];
|
|
96
|
+
if (command === void 0) return COMMAND_OPTIONS;
|
|
97
|
+
const subcommands = SUBCOMMAND_OPTIONS[command.toLowerCase()];
|
|
98
|
+
if (subcommands && rest.length === 0) return subcommands;
|
|
99
|
+
const lastArgument = rest.filter((it) => it.startsWith("-")).at(-1);
|
|
100
|
+
const selecting = lastArgument !== void 0 && SELECTORS.includes(lastArgument.toLowerCase());
|
|
101
|
+
return selecting ? [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS, ...METHOD_OPTIONS] : [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS];
|
|
102
|
+
};
|
|
103
|
+
var complete = (context) => {
|
|
104
|
+
const typed = context.matchBefore(WORD);
|
|
105
|
+
if (!typed?.text && !context.explicit) return null;
|
|
106
|
+
const from = typed?.from ?? context.pos;
|
|
107
|
+
const line = context.state.doc.lineAt(from);
|
|
108
|
+
const options = optionsAfter(
|
|
109
|
+
line.text.slice(0, from - line.from).split(/\s+/).filter(Boolean)
|
|
110
|
+
);
|
|
111
|
+
return options.length > 0 ? { from, options, validFor: WORD } : null;
|
|
112
|
+
};
|
|
113
|
+
var dbt = simpleMode({
|
|
114
|
+
languageData: {
|
|
115
|
+
// `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
|
|
116
|
+
commentTokens: { line: "--", block: { open: "/*", close: "*/" } },
|
|
117
|
+
autocomplete: complete
|
|
118
|
+
},
|
|
119
|
+
start: [
|
|
120
|
+
{ regex: /"(?:[^\\]|\\.)*?(?:"|$)/, token: "string" },
|
|
121
|
+
// Word-bounded, so `dbtX` is not a dbt step whose first word happens to
|
|
122
|
+
// colour — the same thing the completion source asks of it.
|
|
123
|
+
{ regex: /dbt\b/, token: "keyword", sol: true },
|
|
124
|
+
{ regex: word(COMMAND_PHRASES), token: "keyword" },
|
|
125
|
+
{ regex: word(ARGUMENTS), token: "variableName" },
|
|
126
|
+
{ regex: prefix(METHODS), token: "propertyName" },
|
|
127
|
+
{ regex: prefix(FLAGS), token: "attributeName" },
|
|
128
|
+
{ regex: /(?:@|\*|,|\+\d+|\d+\+|\+)/, token: "operator" },
|
|
129
|
+
{ regex: /'.*'/, token: "string" },
|
|
130
|
+
{ regex: /true|false/, token: "atom" }
|
|
131
|
+
]
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// src/components/CodeEditor/modes/jsonnet.ts
|
|
135
|
+
var COMMENT_END = /^\*\//;
|
|
136
|
+
var COMMENT_START = /^\/\/|^#/;
|
|
137
|
+
var C_COMMENT_START = /^\/\*/;
|
|
138
|
+
var TEXT_BLOCK = /^\|\|\|/;
|
|
139
|
+
var TEXT_BLOCK_END = /^\s*\|\|\|/;
|
|
140
|
+
var RAW_DOUBLE = /^""/;
|
|
141
|
+
var RAW_SINGLE = /^''/;
|
|
142
|
+
var CLOSE_DOUBLE = /^"/;
|
|
143
|
+
var CLOSE_SINGLE = /^'/;
|
|
144
|
+
var ESCAPE = /^\\[\\"'/bfnrt0]/;
|
|
145
|
+
var UNICODE_ESCAPE = /^\\u[0-9a-fA-F]{4}/;
|
|
146
|
+
var BACKSLASH = /^\\/;
|
|
147
|
+
var IMPORT = /^import(?:str)?\s*(@?)(["'])/;
|
|
148
|
+
var QUOTE = /^(@?)(["'])/;
|
|
149
|
+
var ROOT = /^\$/;
|
|
150
|
+
var NUMBER = /^(?:\.\d+|\d+\.?\d*)(?:e[-+]?\d+)?/i;
|
|
151
|
+
var OPERATOR = /^[-+/*=<>!&~^|$%]+/;
|
|
152
|
+
var IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_]*/;
|
|
153
|
+
var KEYWORDS = {
|
|
154
|
+
local: "keyword",
|
|
155
|
+
self: "keyword",
|
|
156
|
+
super: "keyword",
|
|
157
|
+
assert: "keyword",
|
|
158
|
+
function: "keyword",
|
|
159
|
+
if: "keyword",
|
|
160
|
+
then: "keyword",
|
|
161
|
+
else: "keyword",
|
|
162
|
+
for: "keyword",
|
|
163
|
+
in: "keyword",
|
|
164
|
+
tailstrict: "keyword",
|
|
165
|
+
error: "keyword",
|
|
166
|
+
true: "atom",
|
|
167
|
+
false: "atom",
|
|
168
|
+
null: "atom"
|
|
169
|
+
};
|
|
170
|
+
var jsonnet = {
|
|
171
|
+
name: "jsonnet",
|
|
172
|
+
// `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
|
|
173
|
+
languageData: { commentTokens: { line: "//", block: { open: "/*", close: "*/" } } },
|
|
174
|
+
startState: () => ({
|
|
175
|
+
cComment: false,
|
|
176
|
+
textBlock: false,
|
|
177
|
+
textBlockIndent: null,
|
|
178
|
+
string: false,
|
|
179
|
+
importString: false,
|
|
180
|
+
stringSingle: false,
|
|
181
|
+
stringRaw: false
|
|
182
|
+
}),
|
|
183
|
+
token: (stream, state) => {
|
|
184
|
+
if (state.cComment) {
|
|
185
|
+
if (stream.match(COMMENT_END)) {
|
|
186
|
+
state.cComment = false;
|
|
187
|
+
return "comment";
|
|
188
|
+
}
|
|
189
|
+
stream.next();
|
|
190
|
+
return "comment";
|
|
191
|
+
}
|
|
192
|
+
if (state.textBlock) {
|
|
193
|
+
if (state.textBlockIndent == null) {
|
|
194
|
+
if (stream.match(TEXT_BLOCK_END)) {
|
|
195
|
+
state.textBlock = false;
|
|
196
|
+
return "string";
|
|
197
|
+
}
|
|
198
|
+
state.textBlockIndent = stream.indentation();
|
|
199
|
+
}
|
|
200
|
+
if (stream.indentation() >= state.textBlockIndent) {
|
|
201
|
+
stream.skipToEnd();
|
|
202
|
+
return "string";
|
|
203
|
+
}
|
|
204
|
+
if (stream.match(TEXT_BLOCK_END)) {
|
|
205
|
+
state.textBlock = false;
|
|
206
|
+
return "string";
|
|
207
|
+
}
|
|
208
|
+
stream.next();
|
|
209
|
+
return "invalid";
|
|
210
|
+
}
|
|
211
|
+
if (state.string || state.importString) {
|
|
212
|
+
const style = state.string ? "string" : "meta";
|
|
213
|
+
if (state.stringRaw) {
|
|
214
|
+
if (stream.match(state.stringSingle ? RAW_SINGLE : RAW_DOUBLE)) return "escape";
|
|
215
|
+
} else {
|
|
216
|
+
if (stream.match(ESCAPE)) return "escape";
|
|
217
|
+
if (stream.match(UNICODE_ESCAPE)) return "escape";
|
|
218
|
+
if (stream.match(BACKSLASH)) return "invalid";
|
|
219
|
+
}
|
|
220
|
+
if (stream.match(state.stringSingle ? CLOSE_SINGLE : CLOSE_DOUBLE)) {
|
|
221
|
+
state.string = false;
|
|
222
|
+
state.importString = false;
|
|
223
|
+
return style;
|
|
224
|
+
}
|
|
225
|
+
stream.next();
|
|
226
|
+
return style;
|
|
227
|
+
}
|
|
228
|
+
if (stream.match(COMMENT_START)) {
|
|
229
|
+
stream.skipToEnd();
|
|
230
|
+
return "comment";
|
|
231
|
+
}
|
|
232
|
+
if (stream.match(C_COMMENT_START)) {
|
|
233
|
+
state.cComment = true;
|
|
234
|
+
return "comment";
|
|
235
|
+
}
|
|
236
|
+
const imported = stream.match(IMPORT);
|
|
237
|
+
if (Array.isArray(imported)) {
|
|
238
|
+
state.importString = true;
|
|
239
|
+
state.stringRaw = imported[1] === "@";
|
|
240
|
+
state.stringSingle = imported[2] === "'";
|
|
241
|
+
return "meta";
|
|
242
|
+
}
|
|
243
|
+
const quoted = stream.match(QUOTE);
|
|
244
|
+
if (Array.isArray(quoted)) {
|
|
245
|
+
state.string = true;
|
|
246
|
+
state.stringRaw = quoted[1] === "@";
|
|
247
|
+
state.stringSingle = quoted[2] === "'";
|
|
248
|
+
return "string";
|
|
249
|
+
}
|
|
250
|
+
if (stream.match(TEXT_BLOCK)) {
|
|
251
|
+
state.textBlock = true;
|
|
252
|
+
state.textBlockIndent = null;
|
|
253
|
+
return "string";
|
|
254
|
+
}
|
|
255
|
+
if (stream.match(ROOT)) return "keyword";
|
|
256
|
+
if (stream.match(NUMBER)) return "number";
|
|
257
|
+
if (stream.match(OPERATOR)) return "operator";
|
|
258
|
+
const identifier = stream.match(IDENTIFIER);
|
|
259
|
+
if (Array.isArray(identifier)) return KEYWORDS[identifier[0]] ?? null;
|
|
260
|
+
stream.next();
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
var resolveToken = (token, fallbackChannels, alpha) => {
|
|
265
|
+
const channels = typeof document === "undefined" ? fallbackChannels : getComputedStyle(document.documentElement).getPropertyValue(`--${token}`).trim() || fallbackChannels;
|
|
266
|
+
return alpha === void 0 ? `rgb(${channels})` : `rgb(${channels} / ${alpha})`;
|
|
267
|
+
};
|
|
268
|
+
var isDarkScheme = () => typeof document !== "undefined" && document.documentElement.getAttribute("data-theme") === "dark";
|
|
269
|
+
var SSR_SIGNAL = "ssr";
|
|
270
|
+
var readThemeSignal = () => {
|
|
271
|
+
if (typeof document === "undefined") return SSR_SIGNAL;
|
|
272
|
+
const root = document.documentElement;
|
|
273
|
+
return `${root.getAttribute("data-theme") ?? ""}:${root.getAttribute("data-brand") ?? ""}`;
|
|
274
|
+
};
|
|
275
|
+
var subscribeThemeSignal = (onChange) => {
|
|
276
|
+
if (typeof document === "undefined") return () => {
|
|
277
|
+
};
|
|
278
|
+
const observer = new MutationObserver(onChange);
|
|
279
|
+
observer.observe(document.documentElement, {
|
|
280
|
+
attributes: true,
|
|
281
|
+
attributeFilter: ["data-theme", "data-brand"]
|
|
282
|
+
});
|
|
283
|
+
return () => observer.disconnect();
|
|
284
|
+
};
|
|
285
|
+
var useThemeSignal = () => useSyncExternalStore(subscribeThemeSignal, readThemeSignal, () => SSR_SIGNAL);
|
|
286
|
+
var themeCache = /* @__PURE__ */ new Map();
|
|
287
|
+
var useThemedExtension = (cacheKey, build) => {
|
|
288
|
+
const themeSignal = useThemeSignal();
|
|
289
|
+
const key = `${themeSignal} ${cacheKey}`;
|
|
290
|
+
let cached = themeCache.get(key);
|
|
291
|
+
if (!cached) {
|
|
292
|
+
cached = build();
|
|
293
|
+
themeCache.set(key, cached);
|
|
294
|
+
}
|
|
295
|
+
return cached;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
// src/components/CodeEditor/helpers.ts
|
|
299
|
+
var LANGUAGE_MODES = [
|
|
300
|
+
"application/json",
|
|
301
|
+
"text/plain",
|
|
302
|
+
"text/x-python",
|
|
303
|
+
"text/x-sql",
|
|
304
|
+
"text/x-mysql",
|
|
305
|
+
"text/x-pgsql",
|
|
306
|
+
"text/x-mssql",
|
|
307
|
+
// Snowflake, under a historical name — these strings are a published prop contract.
|
|
308
|
+
"text/x-sfsql",
|
|
309
|
+
"text/x-bqsql",
|
|
310
|
+
"text/x-plsql",
|
|
311
|
+
"text/x-rsrc",
|
|
312
|
+
"text/x-sh",
|
|
313
|
+
"text/x-toml",
|
|
314
|
+
"text/jsonnet",
|
|
315
|
+
"text/x-dbt",
|
|
316
|
+
"text/javascript",
|
|
317
|
+
"text/typescript"
|
|
318
|
+
];
|
|
319
|
+
var isLanguageMode = (mode) => LANGUAGE_MODES.includes(mode);
|
|
320
|
+
var READ_ONLY_EDITOR = '&.cm-editor:has(.cm-content[contenteditable="false"])';
|
|
321
|
+
var EDITABLE_EDITOR = '&.cm-editor:has(.cm-content[contenteditable="true"])';
|
|
322
|
+
var buildBaseThemeStyles = () => ({
|
|
323
|
+
"*": { lineHeight: "20px" },
|
|
324
|
+
"*::selection": {
|
|
325
|
+
backgroundColor: resolveToken("primary", "31 143 255"),
|
|
326
|
+
color: `${resolveToken("primary-foreground", "255 255 255")} !important`
|
|
327
|
+
},
|
|
328
|
+
[READ_ONLY_EDITOR]: {
|
|
329
|
+
backgroundColor: resolveToken("secondary", "226 232 240")
|
|
330
|
+
},
|
|
331
|
+
[`${READ_ONLY_EDITOR} .cm-gutters`]: {
|
|
332
|
+
backgroundColor: resolveToken("border", "229 231 235")
|
|
333
|
+
},
|
|
334
|
+
"&.cm-editor .cm-scroller": { overflowAnchor: "none" },
|
|
335
|
+
"&.cm-editor, &.cm-editor .cm-scroller": {
|
|
336
|
+
minHeight: "100%",
|
|
337
|
+
flexGrow: 1,
|
|
338
|
+
alignItems: "stretch !important",
|
|
339
|
+
outline: "none"
|
|
340
|
+
},
|
|
341
|
+
".cm-gutter.cm-foldGutter": { display: "none !important" },
|
|
342
|
+
".cm-gutter.cm-lineNumbers": { paddingLeft: "20px", paddingRight: "6px" },
|
|
343
|
+
".cm-gutters": { height: "auto" },
|
|
344
|
+
// merge (diff) view
|
|
345
|
+
'&[class*="cm-merge-"] .cm-deletedLine': { backgroundColor: colors.error[100] },
|
|
346
|
+
'&[class*="cm-merge-"] .cm-changedLine': { backgroundColor: colors.green[100] },
|
|
347
|
+
'&[class*="cm-merge-"] .cm-deletedLineGutter': { backgroundColor: colors.error[200] },
|
|
348
|
+
'&[class*="cm-merge-"] .cm-changedLineGutter': { backgroundColor: colors.green[200] },
|
|
349
|
+
'&[class*="cm-merge-"] .cm-deletedText': { background: colors.error[200] },
|
|
350
|
+
'&[class*="cm-merge-"] .cm-changedText': { background: colors.green[200] },
|
|
351
|
+
'&[class*="cm-merge-"]': {
|
|
352
|
+
backgroundColor: `${colors.white} !important`
|
|
353
|
+
},
|
|
354
|
+
'&[class*="cm-merge-"] .cm-gutters': {
|
|
355
|
+
backgroundColor: `${colors.white} !important`
|
|
356
|
+
},
|
|
357
|
+
".cm-changeGutter": { position: "absolute", zIndex: -1, width: "100%", paddingLeft: 0 },
|
|
358
|
+
'&[class*="cm-merge-"] .cm-changedLine,&[class*="cm-merge-"] .cm-line, &[class*="cm-merge-"] .cm-deletedChunk': { paddingLeft: 0 }
|
|
359
|
+
});
|
|
360
|
+
var ALWAYS_OFF = {
|
|
361
|
+
drawSelection: false,
|
|
362
|
+
foldGutter: false,
|
|
363
|
+
foldKeymap: false,
|
|
364
|
+
highlightActiveLine: false,
|
|
365
|
+
highlightActiveLineGutter: false
|
|
366
|
+
};
|
|
367
|
+
var buildBasicSetup = (readOnly) => ({
|
|
368
|
+
...ALWAYS_OFF,
|
|
369
|
+
...readOnly ? {
|
|
370
|
+
closeBrackets: false,
|
|
371
|
+
closeBracketsKeymap: false,
|
|
372
|
+
lintKeymap: false,
|
|
373
|
+
indentOnInput: false,
|
|
374
|
+
rectangularSelection: false,
|
|
375
|
+
dropCursor: false,
|
|
376
|
+
highlightSelectionMatches: false
|
|
377
|
+
} : null
|
|
378
|
+
});
|
|
379
|
+
var buildCustomTheme = () => {
|
|
380
|
+
const foreground = resolveToken("foreground", "30 41 59");
|
|
381
|
+
return githubLightInit({
|
|
382
|
+
settings: {
|
|
383
|
+
fontFamily: `'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New'`,
|
|
384
|
+
background: resolveToken("background", "249 250 251"),
|
|
385
|
+
foreground,
|
|
386
|
+
gutterBackground: resolveToken("muted", "241 245 249"),
|
|
387
|
+
gutterForeground: resolveToken("muted-foreground", "100 116 139"),
|
|
388
|
+
gutterBorder: "transparent",
|
|
389
|
+
lineHighlight: "transparent",
|
|
390
|
+
selection: resolveToken("primary", "31 143 255")
|
|
391
|
+
},
|
|
392
|
+
styles: [
|
|
393
|
+
{ tag: [tags.name, tags.special(tags.string), tags.bracket], color: foreground },
|
|
394
|
+
{ tag: tags.standard(tags.name), color: colors.purple[600] },
|
|
395
|
+
{ tag: tags.special(tags.name), color: colors.cyan[700] },
|
|
396
|
+
{ tag: tags.string, color: colors.warning[700] }
|
|
397
|
+
]
|
|
398
|
+
});
|
|
399
|
+
};
|
|
400
|
+
var getLanguageMode = (mode) => {
|
|
401
|
+
switch (mode) {
|
|
402
|
+
case void 0:
|
|
403
|
+
case "application/json":
|
|
404
|
+
return json();
|
|
405
|
+
case "text/x-python":
|
|
406
|
+
return python();
|
|
407
|
+
case "text/x-sql":
|
|
408
|
+
return getSqlLanguageSupport(StandardSQL);
|
|
409
|
+
case "text/x-mysql":
|
|
410
|
+
return getSqlLanguageSupport(MySQL);
|
|
411
|
+
case "text/x-pgsql":
|
|
412
|
+
return getSqlLanguageSupport(PostgreSQL);
|
|
413
|
+
case "text/x-mssql":
|
|
414
|
+
return getSqlLanguageSupport(MSSQL);
|
|
415
|
+
case "text/x-sfsql":
|
|
416
|
+
return getSqlLanguageSupport("snowflake");
|
|
417
|
+
case "text/x-bqsql":
|
|
418
|
+
return getSqlLanguageSupport("bigquery");
|
|
419
|
+
case "text/x-plsql":
|
|
420
|
+
return getSqlLanguageSupport(PLSQL);
|
|
421
|
+
case "text/x-rsrc":
|
|
422
|
+
return StreamLanguage.define(r);
|
|
423
|
+
case "text/x-sh":
|
|
424
|
+
return StreamLanguage.define(shell);
|
|
425
|
+
case "text/x-toml":
|
|
426
|
+
return StreamLanguage.define(toml);
|
|
427
|
+
case "text/jsonnet":
|
|
428
|
+
return StreamLanguage.define(jsonnet);
|
|
429
|
+
case "text/x-dbt":
|
|
430
|
+
return StreamLanguage.define(dbt);
|
|
431
|
+
case "text/javascript":
|
|
432
|
+
return javascript({ jsx: true });
|
|
433
|
+
case "text/typescript":
|
|
434
|
+
return javascript({ jsx: true, typescript: true });
|
|
435
|
+
// No language — `text/plain` lands here, and so does any mode added to
|
|
436
|
+
// LANGUAGE_MODES without an arm above. Unstyled text is the safe degradation;
|
|
437
|
+
// a `json()` default would colour unrelated content as if it were JSON.
|
|
438
|
+
default:
|
|
439
|
+
return [];
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
var shouldLintJson = (mode, readOnly) => mode === "application/json" && !readOnly;
|
|
443
|
+
var ButtonToolbar = ({ value, children }) => {
|
|
444
|
+
if (!value && !children) return null;
|
|
445
|
+
return /* @__PURE__ */ jsxs("div", { className: "tw:absolute tw:right-3 tw:top-1 tw:z-10 tw:flex tw:gap-0.5 tw:overflow-visible tw:rounded tw:border tw:border-solid tw:border-border tw:!bg-background tw:p-px tw:shadow-sm", children: [
|
|
446
|
+
!!value && /* @__PURE__ */ jsx(ClipboardButton, { size: "icon-xs", variant: "invisible", text: value }),
|
|
447
|
+
children
|
|
448
|
+
] });
|
|
449
|
+
};
|
|
450
|
+
var buildInputChrome = (isArgo) => ({
|
|
451
|
+
surface: isArgo ? resolveToken("muted", "241 245 249") : colors.neutral[100],
|
|
452
|
+
borderColor: isArgo ? resolveToken("input", "203 213 225") : colors.neutral[100],
|
|
453
|
+
readOnlySurface: isArgo ? resolveToken("muted", "241 245 249") : colors.neutral[150],
|
|
454
|
+
readOnlyBorderColor: isArgo ? resolveToken("input", "203 213 225") : colors.neutral[150],
|
|
455
|
+
hoverBorderColor: null,
|
|
456
|
+
focusBorderColor: isArgo ? resolveToken("primary", "37 99 235") : resolveToken("ring", "31 143 255"),
|
|
457
|
+
focusRing: `0 0 0 4px ${resolveToken("ring", "31 143 255", isArgo ? 0.5 : 0.3)}`,
|
|
458
|
+
radius: isArgo ? "var(--radius-lg, 0.25rem)" : "0.25rem",
|
|
459
|
+
// 2px border + 2×this + `.cm-content`'s own 4px + a 20px line, against the
|
|
460
|
+
// height a one-line `TextInput` has: argo forces `sizing: 'medium'` (36px),
|
|
461
|
+
// legacy leaves it at `default` (40px).
|
|
462
|
+
paddingY: isArgo ? "3px" : "5px",
|
|
463
|
+
// Tops `.cm-line`'s 6px/2px up to the 16px an input's text is inset by.
|
|
464
|
+
paddingX: { left: "10px", right: "14px" }
|
|
465
|
+
});
|
|
466
|
+
var buildCanvasChrome = () => ({
|
|
467
|
+
surface: resolveToken("card", "255 255 255"),
|
|
468
|
+
borderColor: "transparent",
|
|
469
|
+
readOnlySurface: resolveToken("muted", "241 245 249"),
|
|
470
|
+
readOnlyBorderColor: "transparent",
|
|
471
|
+
hoverBorderColor: resolveToken("ring", "31 143 255"),
|
|
472
|
+
focusBorderColor: resolveToken("ring", "31 143 255"),
|
|
473
|
+
focusRing: `0 0 0 4px ${resolveToken("ring", "31 143 255", 0.3)}`,
|
|
474
|
+
radius: "8px",
|
|
475
|
+
paddingY: "8px",
|
|
476
|
+
paddingX: null
|
|
477
|
+
});
|
|
478
|
+
var buildChromeStyles = (chrome) => ({
|
|
479
|
+
"&.cm-editor": {
|
|
480
|
+
border: `solid 1px ${chrome.borderColor}`,
|
|
481
|
+
borderRadius: chrome.radius,
|
|
482
|
+
backgroundColor: chrome.surface,
|
|
483
|
+
paddingTop: chrome.paddingY,
|
|
484
|
+
paddingBottom: chrome.paddingY
|
|
485
|
+
},
|
|
486
|
+
"&.cm-editor :is(.cm-gutters,.cm-scroller)": { backgroundColor: chrome.surface },
|
|
487
|
+
...chrome.paddingX ? {
|
|
488
|
+
// Only without a gutter: there the editor reads as a one-line input and
|
|
489
|
+
// its text should start where a neighbouring `TextInput`'s does. With a
|
|
490
|
+
// gutter, the gutter owns the left edge.
|
|
491
|
+
"&.cm-editor:not(:has(.cm-gutters)) .cm-content": {
|
|
492
|
+
paddingLeft: chrome.paddingX.left,
|
|
493
|
+
paddingRight: chrome.paddingX.right
|
|
494
|
+
}
|
|
495
|
+
} : null,
|
|
496
|
+
...chrome.hoverBorderColor ? { [`${EDITABLE_EDITOR}:hover`]: { borderColor: chrome.hoverBorderColor } } : null,
|
|
497
|
+
[`${EDITABLE_EDITOR}:focus-within`]: {
|
|
498
|
+
borderColor: chrome.focusBorderColor,
|
|
499
|
+
boxShadow: chrome.focusRing
|
|
500
|
+
},
|
|
501
|
+
[READ_ONLY_EDITOR]: {
|
|
502
|
+
backgroundColor: chrome.readOnlySurface,
|
|
503
|
+
borderColor: chrome.readOnlyBorderColor
|
|
504
|
+
},
|
|
505
|
+
[`${READ_ONLY_EDITOR} .cm-gutters`]: { backgroundColor: chrome.readOnlySurface },
|
|
506
|
+
[`${READ_ONLY_EDITOR} .cm-scroller`]: { backgroundColor: chrome.readOnlySurface }
|
|
507
|
+
});
|
|
508
|
+
var setSearchEffect = StateEffect.define();
|
|
509
|
+
function findMatches(doc, query) {
|
|
510
|
+
if (!query) return [];
|
|
511
|
+
const text = doc.toString();
|
|
512
|
+
try {
|
|
513
|
+
const regex = new RegExp(escapeStringRegexp(query), "gi");
|
|
514
|
+
return Array.from(text.matchAll(regex)).map((match, index) => {
|
|
515
|
+
const from = match.index;
|
|
516
|
+
const to = from + match[0].length;
|
|
517
|
+
return { from, to, text: match[0], localIndex: index };
|
|
518
|
+
});
|
|
519
|
+
} catch (e) {
|
|
520
|
+
console.warn("Invalid search regex:", e);
|
|
521
|
+
return [];
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
function createDecorations(matches, selectedLocalIndex) {
|
|
525
|
+
const decorations = matches.map((match) => {
|
|
526
|
+
const isSelected = match.localIndex === selectedLocalIndex;
|
|
527
|
+
const decoration = Decoration.mark({
|
|
528
|
+
class: isSelected ? "cm-searchMatch-selected" : "cm-searchMatch"
|
|
529
|
+
});
|
|
530
|
+
return decoration.range(match.from, match.to);
|
|
531
|
+
});
|
|
532
|
+
return Decoration.set(decorations, true);
|
|
533
|
+
}
|
|
534
|
+
var searchField = StateField.define({
|
|
535
|
+
create() {
|
|
536
|
+
return {
|
|
537
|
+
query: "",
|
|
538
|
+
selectedMatchIndex: void 0,
|
|
539
|
+
matches: [],
|
|
540
|
+
decorations: Decoration.none
|
|
541
|
+
};
|
|
542
|
+
},
|
|
543
|
+
update(state, tr) {
|
|
544
|
+
let newState = state;
|
|
545
|
+
for (const effect of tr.effects) {
|
|
546
|
+
if (!effect.is(setSearchEffect)) {
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
const { query, selectedMatchIndex } = effect.value;
|
|
550
|
+
const matches = findMatches(tr.state.doc, query);
|
|
551
|
+
const decorations = createDecorations(matches, selectedMatchIndex);
|
|
552
|
+
newState = {
|
|
553
|
+
query,
|
|
554
|
+
selectedMatchIndex,
|
|
555
|
+
matches,
|
|
556
|
+
decorations
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
if (tr.docChanged && newState.query) {
|
|
560
|
+
const matches = findMatches(tr.state.doc, newState.query);
|
|
561
|
+
const decorations = createDecorations(matches, newState.selectedMatchIndex);
|
|
562
|
+
newState = {
|
|
563
|
+
...newState,
|
|
564
|
+
matches,
|
|
565
|
+
decorations
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
return newState;
|
|
569
|
+
},
|
|
570
|
+
provide: (field) => EditorView.decorations.from(field, (state) => state.decorations)
|
|
571
|
+
});
|
|
572
|
+
var searchViewPlugin = ViewPlugin.fromClass(
|
|
573
|
+
class {
|
|
574
|
+
lastSelectedIndex;
|
|
575
|
+
update(update) {
|
|
576
|
+
const state = update.state.field(searchField);
|
|
577
|
+
if (state.selectedMatchIndex !== void 0 && state.selectedMatchIndex !== this.lastSelectedIndex) {
|
|
578
|
+
const match = state.matches[state.selectedMatchIndex];
|
|
579
|
+
if (match) {
|
|
580
|
+
requestAnimationFrame(() => {
|
|
581
|
+
update.view.dispatch({
|
|
582
|
+
effects: EditorView.scrollIntoView(match.from, { y: "center" })
|
|
583
|
+
});
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
this.lastSelectedIndex = state.selectedMatchIndex;
|
|
587
|
+
}
|
|
588
|
+
if (state.selectedMatchIndex === void 0) {
|
|
589
|
+
this.lastSelectedIndex = void 0;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
);
|
|
594
|
+
var searchTheme = EditorView.baseTheme({
|
|
595
|
+
".cm-searchMatch": {
|
|
596
|
+
backgroundColor: colors.blue[100]
|
|
597
|
+
},
|
|
598
|
+
".cm-searchMatch > span": {
|
|
599
|
+
color: `${colors.blue[600]} !important`
|
|
600
|
+
},
|
|
601
|
+
".cm-searchMatch-selected": {
|
|
602
|
+
backgroundColor: colors.blue[600]
|
|
603
|
+
},
|
|
604
|
+
".cm-searchMatch-selected > span": {
|
|
605
|
+
color: `${colors.white} !important`
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
function searchExtension() {
|
|
609
|
+
return [searchField, searchViewPlugin, searchTheme];
|
|
610
|
+
}
|
|
611
|
+
function updateSearch(view, query, selectedMatchIndex) {
|
|
612
|
+
view.dispatch({ effects: setSearchEffect.of({ query, selectedMatchIndex }) });
|
|
613
|
+
}
|
|
614
|
+
var ToggleComponentHelp = () => /* @__PURE__ */ jsxs("div", { children: [
|
|
615
|
+
"Use ",
|
|
616
|
+
/* @__PURE__ */ jsx(Kbd, { children: isMac ? "Command+/" : "Ctrl+/" }),
|
|
617
|
+
" to toggle comments."
|
|
618
|
+
] });
|
|
619
|
+
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);
|
|
620
|
+
var crops = (style) => style.overflowX !== "visible" || style.overflowY !== "visible" || style.maskImage !== "none" || style.contentVisibility !== "visible" || /\b(paint|strict|content)\b/.test(style.contain);
|
|
621
|
+
var findTooltipHost = (from) => {
|
|
622
|
+
let outermostCropper = null;
|
|
623
|
+
for (let node = from.parentElement; node && node !== document.body; node = node.parentElement) {
|
|
624
|
+
const style = getComputedStyle(node);
|
|
625
|
+
if (crops(style)) {
|
|
626
|
+
outermostCropper = node;
|
|
627
|
+
} else if (establishesFixedContainingBlock(style)) {
|
|
628
|
+
return outermostCropper?.parentElement ?? node;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
return outermostCropper?.parentElement ?? null;
|
|
632
|
+
};
|
|
633
|
+
var tooltipsExtension = () => {
|
|
634
|
+
const layer = new Compartment();
|
|
635
|
+
return [
|
|
636
|
+
layer.of(tooltips()),
|
|
637
|
+
ViewPlugin.define((view) => {
|
|
638
|
+
const scheduled = setTimeout(() => {
|
|
639
|
+
if (!view.dom.isConnected) return;
|
|
640
|
+
const parent = findTooltipHost(view.dom);
|
|
641
|
+
if (parent) view.dispatch({ effects: layer.reconfigure(tooltips({ parent })) });
|
|
642
|
+
});
|
|
643
|
+
return { destroy: () => clearTimeout(scheduled) };
|
|
644
|
+
})
|
|
645
|
+
];
|
|
646
|
+
};
|
|
647
|
+
var useTooltipsExtension = () => useMemo(tooltipsExtension, []);
|
|
648
|
+
|
|
649
|
+
// src/components/CodeEditor/variableCompletion.ts
|
|
650
|
+
var BOOST = 2e3;
|
|
651
|
+
var NAME = String.raw`[\w-]*`;
|
|
652
|
+
var AT_CARET = new RegExp(String.raw`(?:\{{1,2} ?)?${NAME}$`);
|
|
653
|
+
var NAME_AT_END = new RegExp(`${NAME}$`);
|
|
654
|
+
var OPENING = /\{{1,2} ?$/;
|
|
655
|
+
var CLOSING = /^ ?\}{1,2}/;
|
|
656
|
+
var completeVariables = (variables = []) => {
|
|
657
|
+
if (variables.length === 0) return () => null;
|
|
658
|
+
const options = variables.map(({ name, value }) => ({
|
|
659
|
+
// The bare name: `SqlEditor` filters prefix-only while `CodeEditor` filters
|
|
660
|
+
// fuzzily, and this is the only spelling both accept whether or not the caret
|
|
661
|
+
// has typed the braces. The braces are `displayLabel`, which is what renders.
|
|
662
|
+
label: name,
|
|
663
|
+
displayLabel: `{{${name}}}`,
|
|
664
|
+
detail: value,
|
|
665
|
+
type: "variable",
|
|
666
|
+
boost: BOOST,
|
|
667
|
+
apply: (view, completion, from, to) => {
|
|
668
|
+
const { doc } = view.state;
|
|
669
|
+
const line = doc.lineAt(from);
|
|
670
|
+
const insert = `{{${completion.label}}}`;
|
|
671
|
+
const opening = OPENING.exec(doc.sliceString(line.from, from));
|
|
672
|
+
const closing = CLOSING.exec(doc.sliceString(to, line.to));
|
|
673
|
+
const start = opening ? from - opening[0].length : from;
|
|
674
|
+
const end = closing ? to + closing[0].length : to;
|
|
675
|
+
view.dispatch({
|
|
676
|
+
changes: { from: start, to: end, insert },
|
|
677
|
+
selection: { anchor: start + insert.length }
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
}));
|
|
681
|
+
return (context) => {
|
|
682
|
+
const match = context.matchBefore(AT_CARET);
|
|
683
|
+
if (!match?.text) return null;
|
|
684
|
+
const [name = ""] = NAME_AT_END.exec(match.text) ?? [];
|
|
685
|
+
return { from: match.to - name.length, options };
|
|
686
|
+
};
|
|
687
|
+
};
|
|
688
|
+
var useVariableCompletion = (variables = []) => useStableCallback(completeVariables(variables));
|
|
689
|
+
var emptyObject = {};
|
|
690
|
+
var CodeEditor = ({
|
|
691
|
+
value,
|
|
692
|
+
previousValue,
|
|
693
|
+
onChange,
|
|
694
|
+
variant = "plain",
|
|
695
|
+
mode = "application/json",
|
|
696
|
+
placeholder: placeholder$1 = "",
|
|
697
|
+
ariaLabel,
|
|
698
|
+
searchQuery,
|
|
699
|
+
searchMatchIndex,
|
|
700
|
+
readOnly = false,
|
|
701
|
+
inputLocked = false,
|
|
702
|
+
autocompletions,
|
|
703
|
+
completionSource,
|
|
704
|
+
variables,
|
|
705
|
+
extraKeys = emptyObject,
|
|
706
|
+
withToggleCommentHint = false,
|
|
707
|
+
withAutofocus = false,
|
|
708
|
+
withLineNumbers = true,
|
|
709
|
+
withLineWrapping = true,
|
|
710
|
+
withCollapseUnchanged = false,
|
|
711
|
+
withCopyButton = false,
|
|
712
|
+
completeAny = false,
|
|
713
|
+
help = null,
|
|
714
|
+
helpPostfix = null,
|
|
715
|
+
renderAdditionalButtons,
|
|
716
|
+
className
|
|
717
|
+
}) => {
|
|
718
|
+
const handleChange = useStableCallback((next) => onChange?.(next));
|
|
719
|
+
const withSearch = searchQuery !== void 0;
|
|
720
|
+
const editorRef = useRef(null);
|
|
721
|
+
useEffect(() => {
|
|
722
|
+
const view = editorRef.current?.view;
|
|
723
|
+
if (view && withSearch) updateSearch(view, searchQuery, searchMatchIndex);
|
|
724
|
+
}, [withSearch, searchQuery, searchMatchIndex]);
|
|
725
|
+
const handleCreateEditor = useStableCallback((view) => {
|
|
726
|
+
if (searchQuery) updateSearch(view, searchQuery, searchMatchIndex);
|
|
727
|
+
});
|
|
728
|
+
const extraKeysRef = useRef(extraKeys);
|
|
729
|
+
useLayoutEffect(() => {
|
|
730
|
+
extraKeysRef.current = extraKeys;
|
|
731
|
+
});
|
|
732
|
+
const boundKeysSignature = Object.keys(extraKeys).join("\n");
|
|
733
|
+
const boundKeys = useMemo(
|
|
734
|
+
() => boundKeysSignature.split("\n").filter(Boolean),
|
|
735
|
+
[boundKeysSignature]
|
|
736
|
+
);
|
|
737
|
+
const tooltipLayer = useTooltipsExtension();
|
|
738
|
+
const variableCompletion = useVariableCompletion(variables);
|
|
739
|
+
const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
|
|
740
|
+
const isArgo = useArgoDesign();
|
|
741
|
+
const isField = variant === "field";
|
|
742
|
+
const baseTheme = useThemedExtension(
|
|
743
|
+
isField ? `code-editor:field:${isArgo ? "argo" : "legacy"}` : "code-editor:chrome",
|
|
744
|
+
() => EditorView.theme({
|
|
745
|
+
...buildBaseThemeStyles(),
|
|
746
|
+
...isField ? buildChromeStyles(buildInputChrome(isArgo)) : null
|
|
747
|
+
})
|
|
748
|
+
);
|
|
749
|
+
const commonExtensions = useMemo(() => {
|
|
750
|
+
const callerCompletions = completionSource ?? (completeAny ? completeAnyWord : autocompletions?.length ? autocompletions : null);
|
|
751
|
+
const completionEntries = [
|
|
752
|
+
...callerCompletions ? [{ autocomplete: callerCompletions }] : [],
|
|
753
|
+
{ autocomplete: variableCompletion }
|
|
754
|
+
];
|
|
755
|
+
return [
|
|
756
|
+
getLanguageMode(mode),
|
|
757
|
+
shouldLintJson(mode, readOnly) ? linter(jsonParseLinter()) : [],
|
|
758
|
+
withLineWrapping ? EditorView.lineWrapping : [],
|
|
759
|
+
EditorState.languageData.of(() => completionEntries),
|
|
760
|
+
keymap$1.of(
|
|
761
|
+
boundKeys.map((key) => ({
|
|
762
|
+
key,
|
|
763
|
+
run: () => {
|
|
764
|
+
extraKeysRef.current[key]?.();
|
|
765
|
+
return true;
|
|
766
|
+
}
|
|
767
|
+
}))
|
|
768
|
+
),
|
|
769
|
+
readOnly ? [] : [
|
|
770
|
+
// CodeMirror's own default. Gating it on the props hid completions the
|
|
771
|
+
// *language* supplies — dbt's vocabulary, Snowflake's keywords — behind
|
|
772
|
+
// a shortcut, and macOS leaves no usable one. With nothing to offer, no
|
|
773
|
+
// popup opens anyway.
|
|
774
|
+
autocompletion()
|
|
775
|
+
],
|
|
776
|
+
ariaLabel ? EditorView.contentAttributes.of({ "aria-label": ariaLabel }) : [],
|
|
777
|
+
withSearch ? searchExtension() : [],
|
|
778
|
+
tooltipLayer,
|
|
779
|
+
baseTheme
|
|
780
|
+
];
|
|
781
|
+
}, [
|
|
782
|
+
autocompletions,
|
|
783
|
+
completionSource,
|
|
784
|
+
variableCompletion,
|
|
785
|
+
completeAny,
|
|
786
|
+
boundKeys,
|
|
787
|
+
mode,
|
|
788
|
+
readOnly,
|
|
789
|
+
withLineWrapping,
|
|
790
|
+
baseTheme,
|
|
791
|
+
ariaLabel,
|
|
792
|
+
withSearch,
|
|
793
|
+
tooltipLayer
|
|
794
|
+
]);
|
|
795
|
+
const extensions = useMemo(() => {
|
|
796
|
+
return [
|
|
797
|
+
...commonExtensions,
|
|
798
|
+
placeholder(placeholder$1),
|
|
799
|
+
EditorView.editable.of(!readOnly),
|
|
800
|
+
// The lock is this facet and nothing else. `contenteditable` is what the
|
|
801
|
+
// read-only wash keys off, and `basicSetup` is what holds the undo history,
|
|
802
|
+
// so leaving both alone is what makes the lock invisible.
|
|
803
|
+
EditorState.readOnly.of(readOnly || inputLocked),
|
|
804
|
+
previousValue ? unifiedMergeView({
|
|
805
|
+
original: previousValue,
|
|
806
|
+
mergeControls: false,
|
|
807
|
+
highlightChanges: false,
|
|
808
|
+
collapseUnchanged: withCollapseUnchanged ? {} : void 0
|
|
809
|
+
}) : []
|
|
810
|
+
];
|
|
811
|
+
}, [commonExtensions, placeholder$1, readOnly, inputLocked, previousValue, withCollapseUnchanged]);
|
|
812
|
+
const config = useMemo(() => {
|
|
813
|
+
return {
|
|
814
|
+
...buildBasicSetup(readOnly),
|
|
815
|
+
lineNumbers: withLineNumbers,
|
|
816
|
+
// Mod-f opens CodeMirror's own panel, which would run a second query and a
|
|
817
|
+
// second match count over the same document beside the caller's input.
|
|
818
|
+
...withSearch ? { searchKeymap: false } : null
|
|
819
|
+
};
|
|
820
|
+
}, [withLineNumbers, readOnly, withSearch]);
|
|
821
|
+
return (
|
|
822
|
+
// oxlint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
823
|
+
/* @__PURE__ */ jsxs(
|
|
824
|
+
"div",
|
|
825
|
+
{
|
|
826
|
+
"data-variant": variant,
|
|
827
|
+
className: cn(
|
|
828
|
+
// Scoped to the box CodeMirror renders into rather than to every child, so
|
|
829
|
+
// the toolbar below does not have to undo all three in `!important`.
|
|
830
|
+
"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:[&_>.cm-theme]:h-full",
|
|
831
|
+
// A field's `.cm-editor` is rounded, so the square box behind it would show
|
|
832
|
+
// at the corners, and `overflow-auto` would crop the focus ring — a shadow
|
|
833
|
+
// painted outside the editor's own box.
|
|
834
|
+
isField ? "tw:[&_>.cm-theme]:overflow-visible tw:[&_>.cm-theme]:bg-transparent" : "tw:[&_>.cm-theme]:overflow-auto tw:[&_>.cm-theme]:bg-background",
|
|
835
|
+
className
|
|
836
|
+
),
|
|
837
|
+
onKeyDown: (event) => {
|
|
838
|
+
if (event.key === keyCodes.ESCAPE) {
|
|
839
|
+
event.stopPropagation();
|
|
840
|
+
}
|
|
841
|
+
},
|
|
842
|
+
children: [
|
|
843
|
+
/* @__PURE__ */ jsx(ButtonToolbar, { value: withCopyButton ? value : void 0, children: renderAdditionalButtons?.(value) }),
|
|
844
|
+
/* @__PURE__ */ jsx(
|
|
845
|
+
CodeMirror,
|
|
846
|
+
{
|
|
847
|
+
ref: editorRef,
|
|
848
|
+
onCreateEditor: handleCreateEditor,
|
|
849
|
+
theme: customTheme,
|
|
850
|
+
value,
|
|
851
|
+
onChange: handleChange,
|
|
852
|
+
extensions,
|
|
853
|
+
autoFocus: withAutofocus,
|
|
854
|
+
basicSetup: config
|
|
855
|
+
}
|
|
856
|
+
),
|
|
857
|
+
!readOnly && (withToggleCommentHint || help || helpPostfix) && /* @__PURE__ */ jsxs(HelpBlock, { className: "tw:mt-2 tw:flex tw:flex-wrap tw:gap-1", children: [
|
|
858
|
+
help,
|
|
859
|
+
withToggleCommentHint ? /* @__PURE__ */ jsx(ToggleComponentHelp, {}) : null,
|
|
860
|
+
helpPostfix
|
|
861
|
+
] })
|
|
862
|
+
]
|
|
863
|
+
}
|
|
864
|
+
)
|
|
865
|
+
);
|
|
866
|
+
};
|
|
867
|
+
var activeQueryFirstLine = Decoration.line({ class: "cm-active-query cm-active-query-first" });
|
|
868
|
+
var activeQueryMiddleLine = Decoration.line({ class: "cm-active-query" });
|
|
869
|
+
var activeQueryLastLine = Decoration.line({ class: "cm-active-query cm-active-query-last" });
|
|
870
|
+
var activeQuerySingleLine = Decoration.line({
|
|
871
|
+
class: "cm-active-query cm-active-query-first cm-active-query-last"
|
|
872
|
+
});
|
|
873
|
+
var findActiveQueryRange = (doc, cursorPos, boundaries) => {
|
|
874
|
+
if (boundaries.length === 0) return null;
|
|
875
|
+
let match = boundaries[boundaries.length - 1];
|
|
876
|
+
for (const boundary of boundaries) {
|
|
877
|
+
if (cursorPos <= boundary.to) {
|
|
878
|
+
match = boundary;
|
|
879
|
+
break;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
if (!match) return null;
|
|
883
|
+
const queryText = doc.slice(match.from, match.to);
|
|
884
|
+
const leadingWhitespace = queryText.length - queryText.trimStart().length;
|
|
885
|
+
const trailingWhitespace = queryText.length - queryText.trimEnd().length;
|
|
886
|
+
const trimmedStart = match.from + leadingWhitespace;
|
|
887
|
+
const trimmedEnd = match.to - trailingWhitespace;
|
|
888
|
+
if (trimmedStart >= trimmedEnd) return null;
|
|
889
|
+
return { from: trimmedStart, to: trimmedEnd };
|
|
890
|
+
};
|
|
891
|
+
var computeBoundaries = (queries) => {
|
|
892
|
+
const boundaries = [];
|
|
893
|
+
let offset = 0;
|
|
894
|
+
for (const query of queries) {
|
|
895
|
+
boundaries.push({ from: offset, to: offset + query.length });
|
|
896
|
+
offset += query.length;
|
|
897
|
+
}
|
|
898
|
+
return boundaries;
|
|
899
|
+
};
|
|
900
|
+
var mapBoundariesThroughChanges = (boundaries, changes) => {
|
|
901
|
+
const prevLen = changes.length;
|
|
902
|
+
const mapped = [];
|
|
903
|
+
for (const b of boundaries) {
|
|
904
|
+
const from = changes.mapPos(Math.max(0, Math.min(b.from, prevLen)), -1);
|
|
905
|
+
const to = changes.mapPos(Math.max(0, Math.min(b.to, prevLen)), 1);
|
|
906
|
+
if (from < to) mapped.push({ from, to });
|
|
907
|
+
}
|
|
908
|
+
return mapped;
|
|
909
|
+
};
|
|
910
|
+
var buildDecorations = (view, range) => {
|
|
911
|
+
const startLine = view.state.doc.lineAt(range.from).number;
|
|
912
|
+
const endLine = view.state.doc.lineAt(range.to).number;
|
|
913
|
+
const decorations = [];
|
|
914
|
+
for (let lineNum = startLine; lineNum <= endLine; lineNum++) {
|
|
915
|
+
const lineStart = view.state.doc.line(lineNum).from;
|
|
916
|
+
if (startLine === endLine) {
|
|
917
|
+
decorations.push(activeQuerySingleLine.range(lineStart));
|
|
918
|
+
} else if (lineNum === startLine) {
|
|
919
|
+
decorations.push(activeQueryFirstLine.range(lineStart));
|
|
920
|
+
} else if (lineNum === endLine) {
|
|
921
|
+
decorations.push(activeQueryLastLine.range(lineStart));
|
|
922
|
+
} else {
|
|
923
|
+
decorations.push(activeQueryMiddleLine.range(lineStart));
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
return Decoration.set(decorations);
|
|
927
|
+
};
|
|
928
|
+
var activeQueryHighlight = (splitQueries) => {
|
|
929
|
+
return [
|
|
930
|
+
ViewPlugin.fromClass(
|
|
931
|
+
class {
|
|
932
|
+
decorations = Decoration.none;
|
|
933
|
+
debounceTimer = null;
|
|
934
|
+
seq = 0;
|
|
935
|
+
cachedDoc = "";
|
|
936
|
+
cachedBoundaries = [];
|
|
937
|
+
destroyed = false;
|
|
938
|
+
constructor(view) {
|
|
939
|
+
this.scheduleDocParse(view);
|
|
940
|
+
}
|
|
941
|
+
update(update) {
|
|
942
|
+
if (update.focusChanged && !update.view.hasFocus) {
|
|
943
|
+
this.decorations = Decoration.none;
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
if (update.docChanged) {
|
|
947
|
+
if (this.cachedBoundaries.length > 0) {
|
|
948
|
+
this.cachedBoundaries = mapBoundariesThroughChanges(
|
|
949
|
+
this.cachedBoundaries,
|
|
950
|
+
update.changes
|
|
951
|
+
);
|
|
952
|
+
this.cachedDoc = update.state.doc.toString();
|
|
953
|
+
this.updateFromCache(update.view);
|
|
954
|
+
}
|
|
955
|
+
this.scheduleDocParse(update.view);
|
|
956
|
+
} else if (update.selectionSet || update.focusChanged && update.view.hasFocus) {
|
|
957
|
+
this.updateFromCache(update.view);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
destroy() {
|
|
961
|
+
this.destroyed = true;
|
|
962
|
+
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Update decorations using cached query boundaries.
|
|
966
|
+
* Only mutates this.decorations — does NOT call view.dispatch().
|
|
967
|
+
* When called from update() (sync), CodeMirror picks up the new
|
|
968
|
+
* decorations via the accessor. When called from the async
|
|
969
|
+
* scheduleDocParse callback, the caller must dispatch separately.
|
|
970
|
+
*/
|
|
971
|
+
updateFromCache(view) {
|
|
972
|
+
if (!view.hasFocus) {
|
|
973
|
+
this.decorations = Decoration.none;
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
const { main } = view.state.selection;
|
|
977
|
+
if (main.from !== main.to) {
|
|
978
|
+
this.decorations = Decoration.none;
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
const doc = view.state.doc.toString();
|
|
982
|
+
if (doc !== this.cachedDoc) return;
|
|
983
|
+
if (this.cachedBoundaries.length === 0) {
|
|
984
|
+
this.decorations = Decoration.none;
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
const range = findActiveQueryRange(doc, main.head, this.cachedBoundaries);
|
|
988
|
+
this.decorations = range ? buildDecorations(view, range) : Decoration.none;
|
|
989
|
+
}
|
|
990
|
+
/** Parse queries async (debounced) and update decorations. */
|
|
991
|
+
scheduleDocParse(view) {
|
|
992
|
+
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
993
|
+
this.debounceTimer = setTimeout(async () => {
|
|
994
|
+
const seq = ++this.seq;
|
|
995
|
+
const doc = view.state.doc.toString();
|
|
996
|
+
if (!doc.trim()) {
|
|
997
|
+
this.cachedDoc = doc;
|
|
998
|
+
this.cachedBoundaries = [];
|
|
999
|
+
if (this.decorations !== Decoration.none) {
|
|
1000
|
+
this.decorations = Decoration.none;
|
|
1001
|
+
if (!this.destroyed) view.dispatch();
|
|
1002
|
+
}
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
let queries;
|
|
1006
|
+
try {
|
|
1007
|
+
queries = await splitQueries(doc);
|
|
1008
|
+
} catch {
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1011
|
+
if (this.destroyed || seq !== this.seq) return;
|
|
1012
|
+
this.cachedDoc = doc;
|
|
1013
|
+
this.cachedBoundaries = computeBoundaries(queries);
|
|
1014
|
+
this.updateFromCache(view);
|
|
1015
|
+
if (!this.destroyed) view.dispatch();
|
|
1016
|
+
}, 100);
|
|
1017
|
+
}
|
|
1018
|
+
},
|
|
1019
|
+
{ decorations: (v) => v.decorations }
|
|
1020
|
+
),
|
|
1021
|
+
EditorView.baseTheme({
|
|
1022
|
+
".cm-active-query": {
|
|
1023
|
+
boxShadow: `inset -1px 0 0 0 ${colors.blue[300]}, inset 1px 0 0 0 ${colors.blue[300]}`,
|
|
1024
|
+
marginRight: "8px"
|
|
1025
|
+
},
|
|
1026
|
+
".cm-active-query-first": {
|
|
1027
|
+
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]}`,
|
|
1028
|
+
borderRadius: "4px 4px 0 0"
|
|
1029
|
+
},
|
|
1030
|
+
".cm-active-query-last": {
|
|
1031
|
+
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]}`,
|
|
1032
|
+
borderRadius: "0 0 4px 4px"
|
|
1033
|
+
},
|
|
1034
|
+
".cm-active-query-first.cm-active-query-last": {
|
|
1035
|
+
boxShadow: `inset 0 0 0 1px ${colors.blue[300]}`,
|
|
1036
|
+
borderRadius: "4px"
|
|
1037
|
+
}
|
|
1038
|
+
})
|
|
1039
|
+
];
|
|
1040
|
+
};
|
|
1041
|
+
var HighlightMarker = class extends GutterMarker {
|
|
1042
|
+
toDOM() {
|
|
1043
|
+
const marker = document.createElement("div");
|
|
1044
|
+
marker.className = "cm-highlight-marker";
|
|
1045
|
+
return marker;
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
var highlightMarker = new HighlightMarker();
|
|
1049
|
+
var forEachLineInRange = (doc, from, to, callback) => {
|
|
1050
|
+
const results = [];
|
|
1051
|
+
const fromLine = Math.max(1, from + 1);
|
|
1052
|
+
const toLine = Math.min(doc.lines, to + 1);
|
|
1053
|
+
for (let i = fromLine; i <= toLine; i++) {
|
|
1054
|
+
const line = doc.line(i);
|
|
1055
|
+
results.push(callback(line.from));
|
|
1056
|
+
}
|
|
1057
|
+
return results;
|
|
1058
|
+
};
|
|
1059
|
+
var setHighlightedLinesEffect = StateEffect.define();
|
|
1060
|
+
var highlightedLinesField = StateField.define({
|
|
1061
|
+
create() {
|
|
1062
|
+
return null;
|
|
1063
|
+
},
|
|
1064
|
+
update(value, transaction) {
|
|
1065
|
+
for (const effect of transaction.effects) {
|
|
1066
|
+
if (effect.is(setHighlightedLinesEffect)) {
|
|
1067
|
+
return effect.value;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
return value;
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
var highlightGutter = gutter({
|
|
1074
|
+
class: "cm-highlight-gutter",
|
|
1075
|
+
markers: (view) => {
|
|
1076
|
+
const highlightInfo = view.state.field(highlightedLinesField, false);
|
|
1077
|
+
if (!highlightInfo) {
|
|
1078
|
+
return RangeSet.empty;
|
|
1079
|
+
}
|
|
1080
|
+
const markers = forEachLineInRange(
|
|
1081
|
+
view.state.doc,
|
|
1082
|
+
highlightInfo.from,
|
|
1083
|
+
highlightInfo.to,
|
|
1084
|
+
(lineFrom) => highlightMarker.range(lineFrom)
|
|
1085
|
+
);
|
|
1086
|
+
return RangeSet.of(markers);
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
1089
|
+
var errorLineDecorations = StateField.define({
|
|
1090
|
+
create() {
|
|
1091
|
+
return Decoration.none;
|
|
1092
|
+
},
|
|
1093
|
+
update(decorations, transaction) {
|
|
1094
|
+
decorations = decorations.map(transaction.changes);
|
|
1095
|
+
for (const effect of transaction.effects) {
|
|
1096
|
+
if (!effect.is(setHighlightedLinesEffect)) {
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
if (!effect.value || !effect.value.error) {
|
|
1100
|
+
return Decoration.none;
|
|
1101
|
+
}
|
|
1102
|
+
const decorationArray = forEachLineInRange(
|
|
1103
|
+
transaction.state.doc,
|
|
1104
|
+
effect.value.error.from,
|
|
1105
|
+
effect.value.error.to,
|
|
1106
|
+
(lineFrom) => Decoration.line({ class: "cm-error-line" }).range(lineFrom)
|
|
1107
|
+
);
|
|
1108
|
+
return Decoration.set(decorationArray);
|
|
1109
|
+
}
|
|
1110
|
+
return decorations;
|
|
1111
|
+
},
|
|
1112
|
+
provide: (f) => EditorView.decorations.from(f)
|
|
1113
|
+
});
|
|
1114
|
+
var processingLineDecorations = StateField.define({
|
|
1115
|
+
create() {
|
|
1116
|
+
return Decoration.none;
|
|
1117
|
+
},
|
|
1118
|
+
update(decorations, transaction) {
|
|
1119
|
+
decorations = decorations.map(transaction.changes);
|
|
1120
|
+
for (const effect of transaction.effects) {
|
|
1121
|
+
if (!effect.is(setHighlightedLinesEffect)) {
|
|
1122
|
+
continue;
|
|
1123
|
+
}
|
|
1124
|
+
if (!effect.value || !effect.value.processing) {
|
|
1125
|
+
return Decoration.none;
|
|
1126
|
+
}
|
|
1127
|
+
const decorationArray = forEachLineInRange(
|
|
1128
|
+
transaction.state.doc,
|
|
1129
|
+
effect.value.processing.from,
|
|
1130
|
+
effect.value.processing.to,
|
|
1131
|
+
(lineFrom) => Decoration.line({ class: "cm-processing-line" }).range(lineFrom)
|
|
1132
|
+
);
|
|
1133
|
+
return Decoration.set(decorationArray);
|
|
1134
|
+
}
|
|
1135
|
+
return decorations;
|
|
1136
|
+
},
|
|
1137
|
+
provide: (f) => EditorView.decorations.from(f)
|
|
1138
|
+
});
|
|
1139
|
+
var highlightedLinesTheme = EditorView.baseTheme({
|
|
1140
|
+
".cm-highlight-gutter": {
|
|
1141
|
+
width: "2px",
|
|
1142
|
+
marginRight: "2px"
|
|
1143
|
+
},
|
|
1144
|
+
".cm-highlight-marker": {
|
|
1145
|
+
width: "2px",
|
|
1146
|
+
height: "100%",
|
|
1147
|
+
backgroundColor: colors.blue[500]
|
|
1148
|
+
},
|
|
1149
|
+
".cm-error-line": {
|
|
1150
|
+
backgroundColor: `${colors.error[100]} !important`
|
|
1151
|
+
},
|
|
1152
|
+
".cm-processing-line": {
|
|
1153
|
+
backgroundColor: `${colors.blue[100]} !important`
|
|
1154
|
+
}
|
|
1155
|
+
});
|
|
1156
|
+
function highlightingExtension() {
|
|
1157
|
+
return [
|
|
1158
|
+
highlightedLinesField,
|
|
1159
|
+
highlightGutter,
|
|
1160
|
+
errorLineDecorations,
|
|
1161
|
+
processingLineDecorations,
|
|
1162
|
+
highlightedLinesTheme
|
|
1163
|
+
];
|
|
1164
|
+
}
|
|
1165
|
+
function updateHighlighting(view, lines) {
|
|
1166
|
+
view.dispatch({ effects: setHighlightedLinesEffect.of(lines ?? null) });
|
|
1167
|
+
}
|
|
1168
|
+
var OWN_KEYMAPS = {
|
|
1169
|
+
defaultKeymap: false,
|
|
1170
|
+
completionKeymap: false,
|
|
1171
|
+
searchKeymap: false
|
|
1172
|
+
};
|
|
1173
|
+
var CUSTOM_KEYMAP = [
|
|
1174
|
+
{
|
|
1175
|
+
key: "Escape",
|
|
1176
|
+
stopPropagation: true,
|
|
1177
|
+
run: (view) => {
|
|
1178
|
+
view.contentDOM.blur();
|
|
1179
|
+
return true;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
];
|
|
1183
|
+
var OWN_KEYMAP_EXTENSION = keymap.of([...defaultKeymap, ...CUSTOM_KEYMAP]);
|
|
1184
|
+
var buildTheme = () => ({
|
|
1185
|
+
...buildBaseThemeStyles(),
|
|
1186
|
+
...buildChromeStyles(buildCanvasChrome())
|
|
1187
|
+
});
|
|
1188
|
+
var SqlEditor = ({
|
|
1189
|
+
value,
|
|
1190
|
+
onChange,
|
|
1191
|
+
onSelectionChange,
|
|
1192
|
+
onCreateEditor,
|
|
1193
|
+
onDestroyEditor,
|
|
1194
|
+
onBlurEditor,
|
|
1195
|
+
onFocusEditor,
|
|
1196
|
+
placeholder = "",
|
|
1197
|
+
searchQuery = "",
|
|
1198
|
+
searchMatchIndex,
|
|
1199
|
+
readOnly = false,
|
|
1200
|
+
queryParser,
|
|
1201
|
+
autoFocus = false,
|
|
1202
|
+
lineNumbers = true,
|
|
1203
|
+
className,
|
|
1204
|
+
schema,
|
|
1205
|
+
completionSource,
|
|
1206
|
+
variables,
|
|
1207
|
+
defaultDatabase,
|
|
1208
|
+
defaultSchema,
|
|
1209
|
+
highlightLines,
|
|
1210
|
+
dialect
|
|
1211
|
+
}) => {
|
|
1212
|
+
const editorRef = useRef(null);
|
|
1213
|
+
const handleChange = useStableCallback((next) => onChange?.(next));
|
|
1214
|
+
const parseQueries = useStableCallback(async (sql) => await queryParser?.(sql) ?? []);
|
|
1215
|
+
const handleBlur = useStableCallback((view) => onBlurEditor?.(view));
|
|
1216
|
+
const handleFocus = useStableCallback((view) => onFocusEditor?.(view));
|
|
1217
|
+
const handleUpdate = useStableCallback((update) => {
|
|
1218
|
+
if (update.selectionSet) {
|
|
1219
|
+
const { main } = update.state.selection;
|
|
1220
|
+
onSelectionChange?.(update.state.sliceDoc(main.from, main.to));
|
|
1221
|
+
}
|
|
1222
|
+
});
|
|
1223
|
+
const variableCompletion = useVariableCompletion(variables);
|
|
1224
|
+
const withQueryParser = queryParser !== void 0;
|
|
1225
|
+
const tooltipLayer = useTooltipsExtension();
|
|
1226
|
+
const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
|
|
1227
|
+
const themeExtension = useThemedExtension(
|
|
1228
|
+
"sql-editor:chrome",
|
|
1229
|
+
() => EditorView$1.theme(buildTheme())
|
|
1230
|
+
);
|
|
1231
|
+
const extensions = useMemo(() => {
|
|
1232
|
+
return [
|
|
1233
|
+
EditorView$1.lineWrapping,
|
|
1234
|
+
OWN_KEYMAP_EXTENSION,
|
|
1235
|
+
...installExtensions({
|
|
1236
|
+
schema,
|
|
1237
|
+
defaultDatabase,
|
|
1238
|
+
defaultSchema,
|
|
1239
|
+
variableCompletion,
|
|
1240
|
+
completionSource,
|
|
1241
|
+
dialect
|
|
1242
|
+
}),
|
|
1243
|
+
searchExtension(),
|
|
1244
|
+
highlightingExtension(),
|
|
1245
|
+
withQueryParser ? activeQueryHighlight(parseQueries) : [],
|
|
1246
|
+
tooltipLayer,
|
|
1247
|
+
themeExtension,
|
|
1248
|
+
EditorView$1.domEventHandlers({
|
|
1249
|
+
blur: (_, view) => handleBlur(view),
|
|
1250
|
+
focus: (_, view) => handleFocus(view)
|
|
1251
|
+
})
|
|
1252
|
+
];
|
|
1253
|
+
}, [
|
|
1254
|
+
withQueryParser,
|
|
1255
|
+
parseQueries,
|
|
1256
|
+
schema,
|
|
1257
|
+
completionSource,
|
|
1258
|
+
defaultDatabase,
|
|
1259
|
+
defaultSchema,
|
|
1260
|
+
variableCompletion,
|
|
1261
|
+
dialect,
|
|
1262
|
+
handleBlur,
|
|
1263
|
+
handleFocus,
|
|
1264
|
+
themeExtension,
|
|
1265
|
+
tooltipLayer
|
|
1266
|
+
]);
|
|
1267
|
+
const defaultSetup = useMemo(() => {
|
|
1268
|
+
return { ...buildBasicSetup(readOnly), ...OWN_KEYMAPS, lineNumbers };
|
|
1269
|
+
}, [readOnly, lineNumbers]);
|
|
1270
|
+
useEffect(() => {
|
|
1271
|
+
if (editorRef.current?.view) {
|
|
1272
|
+
updateHighlighting(editorRef.current.view, highlightLines);
|
|
1273
|
+
}
|
|
1274
|
+
}, [highlightLines]);
|
|
1275
|
+
useEffect(() => {
|
|
1276
|
+
if (editorRef.current?.view) {
|
|
1277
|
+
updateSearch(editorRef.current.view, searchQuery, searchMatchIndex);
|
|
1278
|
+
}
|
|
1279
|
+
}, [searchQuery, searchMatchIndex]);
|
|
1280
|
+
const handleDestroy = useStableCallback(() => onDestroyEditor?.());
|
|
1281
|
+
useEffect(() => handleDestroy, [handleDestroy]);
|
|
1282
|
+
const handleCreate = useStableCallback((view, state) => {
|
|
1283
|
+
onCreateEditor?.(view, state);
|
|
1284
|
+
if (highlightLines) {
|
|
1285
|
+
updateHighlighting(view, highlightLines);
|
|
1286
|
+
}
|
|
1287
|
+
if (searchQuery) {
|
|
1288
|
+
updateSearch(view, searchQuery, searchMatchIndex);
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
return /* @__PURE__ */ jsx(
|
|
1292
|
+
CodeMirror,
|
|
1293
|
+
{
|
|
1294
|
+
ref: editorRef,
|
|
1295
|
+
theme: customTheme,
|
|
1296
|
+
extensions,
|
|
1297
|
+
value,
|
|
1298
|
+
onChange: handleChange,
|
|
1299
|
+
onUpdate: handleUpdate,
|
|
1300
|
+
onCreateEditor: handleCreate,
|
|
1301
|
+
autoFocus,
|
|
1302
|
+
placeholder,
|
|
1303
|
+
className,
|
|
1304
|
+
readOnly,
|
|
1305
|
+
editable: !readOnly,
|
|
1306
|
+
basicSetup: defaultSetup
|
|
1307
|
+
}
|
|
1308
|
+
);
|
|
1309
|
+
};
|
|
1310
|
+
|
|
1311
|
+
export { CodeEditor, LANGUAGE_MODES, SqlEditor, buildBasicSetup, isDarkScheme, isLanguageMode, resolveToken, useThemedExtension };
|
|
1312
|
+
//# sourceMappingURL=chunk-7PUUHEJQ.js.map
|
|
1313
|
+
//# sourceMappingURL=chunk-7PUUHEJQ.js.map
|