@keboola/design 8.0.0 → 9.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/dist/editors.cjs +366 -186
- package/dist/editors.cjs.map +1 -1
- package/dist/editors.d.cts +56 -6
- package/dist/editors.d.ts +56 -6
- package/dist/editors.js +370 -190
- package/dist/editors.js.map +1 -1
- package/dist/index.cjs +89 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -4
- package/dist/index.d.ts +29 -4
- package/dist/index.js +89 -13
- package/dist/index.js.map +1 -1
- package/dist/rjsf.cjs +394 -39
- package/dist/rjsf.cjs.map +1 -1
- package/dist/rjsf.js +396 -41
- package/dist/rjsf.js.map +1 -1
- package/package.json +5 -5
package/dist/editors.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { createContext,
|
|
1
|
+
import { createContext, useRef, useEffect, useLayoutEffect, useMemo, useCallback, useSyncExternalStore, useState, use, Children, Fragment as Fragment$1 } from 'react';
|
|
2
2
|
import { completeAnyWord, autocompletion } from '@codemirror/autocomplete';
|
|
3
3
|
import { jsonParseLinter, json } from '@codemirror/lang-json';
|
|
4
4
|
import { linter } from '@codemirror/lint';
|
|
5
5
|
import { unifiedMergeView } from '@codemirror/merge';
|
|
6
|
-
import {
|
|
7
|
-
import CodeMirror, { EditorState, EditorView as EditorView$1
|
|
6
|
+
import { EditorView, Decoration, ViewPlugin, gutter, GutterMarker, keymap as keymap$1, placeholder, tooltips, gutterLineClass } from '@codemirror/view';
|
|
7
|
+
import CodeMirror, { keymap, EditorState, EditorView as EditorView$1 } from '@uiw/react-codemirror';
|
|
8
8
|
import { clsx } from 'clsx';
|
|
9
9
|
import { extendTailwindMerge } from 'tailwind-merge';
|
|
10
10
|
import { Root as Root$1, Trigger, Portal, Content } from '@radix-ui/react-tooltip';
|
|
@@ -21,12 +21,11 @@ import { r } from '@codemirror/legacy-modes/mode/r';
|
|
|
21
21
|
import { shell } from '@codemirror/legacy-modes/mode/shell';
|
|
22
22
|
import { toml } from '@codemirror/legacy-modes/mode/toml';
|
|
23
23
|
import { githubLightInit } from '@uiw/codemirror-theme-github';
|
|
24
|
-
import {
|
|
24
|
+
import { installExtensions, getSqlDialect } from '@keboola/codemirror-lang-sql';
|
|
25
25
|
import colors from '@keboola/tailwind-config/colors';
|
|
26
26
|
import { simpleMode } from '@codemirror/legacy-modes/mode/simple-mode';
|
|
27
|
+
import { StateEffect, StateField, RangeSet, Compartment, RangeSetBuilder } from '@codemirror/state';
|
|
27
28
|
import { defaultKeymap } from '@codemirror/commands';
|
|
28
|
-
import { installExtensions } from '@keboola/codemirror-lang-sql';
|
|
29
|
-
import { StateEffect, StateField, RangeSet, RangeSetBuilder } from '@codemirror/state';
|
|
30
29
|
|
|
31
30
|
// src/components/CodeEditor/CodeEditor.tsx
|
|
32
31
|
|
|
@@ -290,6 +289,21 @@ Tooltip.Trigger = TooltipTrigger;
|
|
|
290
289
|
|
|
291
290
|
// src/utils/escapeStringRegexp.ts
|
|
292
291
|
var escapeStringRegexp = (string) => string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
|
|
292
|
+
|
|
293
|
+
// src/utils/isMac.ts
|
|
294
|
+
var getIsMac = () => {
|
|
295
|
+
if (typeof navigator !== "undefined" && "userAgentData" in navigator) {
|
|
296
|
+
const platform = navigator.userAgentData.platform;
|
|
297
|
+
if (typeof platform === "string") {
|
|
298
|
+
return platform.toLowerCase() === "macos";
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (typeof navigator !== "undefined" && typeof navigator.platform === "string") {
|
|
302
|
+
return navigator.platform.toUpperCase().indexOf("MAC") >= 0;
|
|
303
|
+
}
|
|
304
|
+
return false;
|
|
305
|
+
};
|
|
306
|
+
var isMac = getIsMac();
|
|
293
307
|
var helpVariants = cva(["tw:m-0", "tw:text-xs"], {
|
|
294
308
|
defaultVariants: {
|
|
295
309
|
state: "default"
|
|
@@ -740,8 +754,6 @@ var ButtonToolbar = ({ value, children }) => {
|
|
|
740
754
|
};
|
|
741
755
|
var COMMANDS = [
|
|
742
756
|
"run-operation",
|
|
743
|
-
"source freshness",
|
|
744
|
-
"docs generate",
|
|
745
757
|
"run",
|
|
746
758
|
"test",
|
|
747
759
|
"seed",
|
|
@@ -750,9 +762,13 @@ var COMMANDS = [
|
|
|
750
762
|
"ls",
|
|
751
763
|
"compile",
|
|
752
764
|
"build",
|
|
753
|
-
"deps"
|
|
765
|
+
"deps",
|
|
766
|
+
"docs",
|
|
767
|
+
"source"
|
|
754
768
|
];
|
|
769
|
+
var SUBCOMMANDS = { docs: ["generate"], source: ["freshness"] };
|
|
755
770
|
var ARGUMENTS = ["--select", "--exclude", "--selector", "--defer", "--resource-type", "-s"];
|
|
771
|
+
var SELECTORS = ["--select", "--exclude", "-s"];
|
|
756
772
|
var METHODS = [
|
|
757
773
|
"path:",
|
|
758
774
|
"source:",
|
|
@@ -779,13 +795,59 @@ var FLAGS = [
|
|
|
779
795
|
"--profile",
|
|
780
796
|
"--full-refresh"
|
|
781
797
|
];
|
|
782
|
-
var
|
|
783
|
-
|
|
798
|
+
var COMMAND_PHRASES = COMMANDS.flatMap((command) => {
|
|
799
|
+
const subcommands = SUBCOMMANDS[command];
|
|
800
|
+
return subcommands ? subcommands.map((subcommand) => `${command} ${subcommand}`) : [command];
|
|
801
|
+
});
|
|
802
|
+
var alternation = (list) => [...list].sort((a, b) => b.length - a.length).join("|");
|
|
803
|
+
var word = (list) => new RegExp(`^\\s+(?:${alternation(list)})\\b`, "i");
|
|
804
|
+
var prefix = (list) => new RegExp(`^\\s+(?:${alternation(list)})`, "i");
|
|
805
|
+
var WORD = /[\w:-]*$/;
|
|
806
|
+
var asOptions = (list, type) => list.map((label) => ({ label, type }));
|
|
807
|
+
var DBT = [{ label: "dbt", type: "keyword" }];
|
|
808
|
+
var COMMAND_OPTIONS = asOptions(COMMANDS, "keyword");
|
|
809
|
+
var SUBCOMMAND_OPTIONS = Object.fromEntries(
|
|
810
|
+
Object.entries(SUBCOMMANDS).map(([command, subcommands]) => [
|
|
811
|
+
command,
|
|
812
|
+
asOptions(subcommands, "keyword")
|
|
813
|
+
])
|
|
814
|
+
);
|
|
815
|
+
var ARGUMENT_OPTIONS = asOptions(ARGUMENTS, "variable");
|
|
816
|
+
var FLAG_OPTIONS = asOptions(FLAGS, "constant");
|
|
817
|
+
var METHOD_OPTIONS = asOptions(METHODS, "property");
|
|
818
|
+
var optionsAfter = (words) => {
|
|
819
|
+
const [step, command, ...rest] = words;
|
|
820
|
+
if (step === void 0) return DBT;
|
|
821
|
+
if (step.toLowerCase() !== "dbt") return [];
|
|
822
|
+
if (command === void 0) return COMMAND_OPTIONS;
|
|
823
|
+
const subcommands = SUBCOMMAND_OPTIONS[command.toLowerCase()];
|
|
824
|
+
if (subcommands && rest.length === 0) return subcommands;
|
|
825
|
+
const lastArgument = rest.filter((it) => it.startsWith("-")).at(-1);
|
|
826
|
+
const selecting = lastArgument !== void 0 && SELECTORS.includes(lastArgument.toLowerCase());
|
|
827
|
+
return selecting ? [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS, ...METHOD_OPTIONS] : [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS];
|
|
828
|
+
};
|
|
829
|
+
var complete = (context) => {
|
|
830
|
+
const typed = context.matchBefore(WORD);
|
|
831
|
+
if (!typed?.text && !context.explicit) return null;
|
|
832
|
+
const from = typed?.from ?? context.pos;
|
|
833
|
+
const line = context.state.doc.lineAt(from);
|
|
834
|
+
const options = optionsAfter(
|
|
835
|
+
line.text.slice(0, from - line.from).split(/\s+/).filter(Boolean)
|
|
836
|
+
);
|
|
837
|
+
return options.length > 0 ? { from, options, validFor: WORD } : null;
|
|
838
|
+
};
|
|
784
839
|
var dbt = simpleMode({
|
|
840
|
+
languageData: {
|
|
841
|
+
// `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
|
|
842
|
+
commentTokens: { line: "--", block: { open: "/*", close: "*/" } },
|
|
843
|
+
autocomplete: complete
|
|
844
|
+
},
|
|
785
845
|
start: [
|
|
786
846
|
{ regex: /"(?:[^\\]|\\.)*?(?:"|$)/, token: "string" },
|
|
787
|
-
|
|
788
|
-
|
|
847
|
+
// Word-bounded, so `dbtX` is not a dbt step whose first word happens to
|
|
848
|
+
// colour — the same thing the completion source asks of it.
|
|
849
|
+
{ regex: /dbt\b/, token: "keyword", sol: true },
|
|
850
|
+
{ regex: word(COMMAND_PHRASES), token: "keyword" },
|
|
789
851
|
{ regex: word(ARGUMENTS), token: "variableName" },
|
|
790
852
|
{ regex: prefix(METHODS), token: "propertyName" },
|
|
791
853
|
{ regex: prefix(FLAGS), token: "attributeName" },
|
|
@@ -833,6 +895,8 @@ var KEYWORDS = {
|
|
|
833
895
|
};
|
|
834
896
|
var jsonnet = {
|
|
835
897
|
name: "jsonnet",
|
|
898
|
+
// `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
|
|
899
|
+
languageData: { commentTokens: { line: "//", block: { open: "/*", close: "*/" } } },
|
|
836
900
|
startState: () => ({
|
|
837
901
|
cComment: false,
|
|
838
902
|
textBlock: false,
|
|
@@ -965,6 +1029,7 @@ var LANGUAGE_MODES = [
|
|
|
965
1029
|
"text/x-mysql",
|
|
966
1030
|
"text/x-pgsql",
|
|
967
1031
|
"text/x-mssql",
|
|
1032
|
+
// Snowflake, under a historical name — these strings are a published prop contract.
|
|
968
1033
|
"text/x-sfsql",
|
|
969
1034
|
"text/x-plsql",
|
|
970
1035
|
"text/x-rsrc",
|
|
@@ -1026,8 +1091,6 @@ var ALWAYS_OFF = {
|
|
|
1026
1091
|
var buildBasicSetup = (readOnly) => ({
|
|
1027
1092
|
...ALWAYS_OFF,
|
|
1028
1093
|
...readOnly ? {
|
|
1029
|
-
history: false,
|
|
1030
|
-
historyKeymap: false,
|
|
1031
1094
|
closeBrackets: false,
|
|
1032
1095
|
closeBracketsKeymap: false,
|
|
1033
1096
|
lintKeymap: false,
|
|
@@ -1065,7 +1128,7 @@ var getLanguageMode = (mode) => {
|
|
|
1065
1128
|
case "text/x-mssql":
|
|
1066
1129
|
return sql({ upperCaseKeywords: true, dialect: MSSQL });
|
|
1067
1130
|
case "text/x-sfsql":
|
|
1068
|
-
return
|
|
1131
|
+
return sql({ upperCaseKeywords: true, dialect: getSqlDialect("snowflake") });
|
|
1069
1132
|
case "text/x-plsql":
|
|
1070
1133
|
return sql({ upperCaseKeywords: true, dialect: PLSQL });
|
|
1071
1134
|
case "text/x-rsrc":
|
|
@@ -1090,6 +1153,112 @@ var getLanguageMode = (mode) => {
|
|
|
1090
1153
|
}
|
|
1091
1154
|
};
|
|
1092
1155
|
var shouldLintJson = (mode, readOnly) => mode === "application/json" && !readOnly;
|
|
1156
|
+
var setSearchEffect = StateEffect.define();
|
|
1157
|
+
function findMatches(doc, query) {
|
|
1158
|
+
if (!query) return [];
|
|
1159
|
+
const text = doc.toString();
|
|
1160
|
+
try {
|
|
1161
|
+
const regex = new RegExp(escapeStringRegexp(query), "gi");
|
|
1162
|
+
return Array.from(text.matchAll(regex)).map((match, index) => {
|
|
1163
|
+
const from = match.index;
|
|
1164
|
+
const to = from + match[0].length;
|
|
1165
|
+
return { from, to, text: match[0], localIndex: index };
|
|
1166
|
+
});
|
|
1167
|
+
} catch (e) {
|
|
1168
|
+
console.warn("Invalid search regex:", e);
|
|
1169
|
+
return [];
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
function createDecorations(matches, selectedLocalIndex) {
|
|
1173
|
+
const decorations = matches.map((match) => {
|
|
1174
|
+
const isSelected = match.localIndex === selectedLocalIndex;
|
|
1175
|
+
const decoration = Decoration.mark({
|
|
1176
|
+
class: isSelected ? "cm-searchMatch-selected" : "cm-searchMatch"
|
|
1177
|
+
});
|
|
1178
|
+
return decoration.range(match.from, match.to);
|
|
1179
|
+
});
|
|
1180
|
+
return Decoration.set(decorations, true);
|
|
1181
|
+
}
|
|
1182
|
+
var searchField = StateField.define({
|
|
1183
|
+
create() {
|
|
1184
|
+
return {
|
|
1185
|
+
query: "",
|
|
1186
|
+
selectedMatchIndex: void 0,
|
|
1187
|
+
matches: [],
|
|
1188
|
+
decorations: Decoration.none
|
|
1189
|
+
};
|
|
1190
|
+
},
|
|
1191
|
+
update(state, tr) {
|
|
1192
|
+
let newState = state;
|
|
1193
|
+
for (const effect of tr.effects) {
|
|
1194
|
+
if (!effect.is(setSearchEffect)) {
|
|
1195
|
+
continue;
|
|
1196
|
+
}
|
|
1197
|
+
const { query, selectedMatchIndex } = effect.value;
|
|
1198
|
+
const matches = findMatches(tr.state.doc, query);
|
|
1199
|
+
const decorations = createDecorations(matches, selectedMatchIndex);
|
|
1200
|
+
newState = {
|
|
1201
|
+
query,
|
|
1202
|
+
selectedMatchIndex,
|
|
1203
|
+
matches,
|
|
1204
|
+
decorations
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
if (tr.docChanged && newState.query) {
|
|
1208
|
+
const matches = findMatches(tr.state.doc, newState.query);
|
|
1209
|
+
const decorations = createDecorations(matches, newState.selectedMatchIndex);
|
|
1210
|
+
newState = {
|
|
1211
|
+
...newState,
|
|
1212
|
+
matches,
|
|
1213
|
+
decorations
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
return newState;
|
|
1217
|
+
},
|
|
1218
|
+
provide: (field) => EditorView.decorations.from(field, (state) => state.decorations)
|
|
1219
|
+
});
|
|
1220
|
+
var searchViewPlugin = ViewPlugin.fromClass(
|
|
1221
|
+
class {
|
|
1222
|
+
lastSelectedIndex;
|
|
1223
|
+
update(update) {
|
|
1224
|
+
const state = update.state.field(searchField);
|
|
1225
|
+
if (state.selectedMatchIndex !== void 0 && state.selectedMatchIndex !== this.lastSelectedIndex) {
|
|
1226
|
+
const match = state.matches[state.selectedMatchIndex];
|
|
1227
|
+
if (match) {
|
|
1228
|
+
requestAnimationFrame(() => {
|
|
1229
|
+
update.view.dispatch({
|
|
1230
|
+
effects: EditorView.scrollIntoView(match.from, { y: "center" })
|
|
1231
|
+
});
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
this.lastSelectedIndex = state.selectedMatchIndex;
|
|
1235
|
+
}
|
|
1236
|
+
if (state.selectedMatchIndex === void 0) {
|
|
1237
|
+
this.lastSelectedIndex = void 0;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
);
|
|
1242
|
+
var searchTheme = EditorView.baseTheme({
|
|
1243
|
+
".cm-searchMatch": {
|
|
1244
|
+
backgroundColor: colors.blue[100]
|
|
1245
|
+
},
|
|
1246
|
+
".cm-searchMatch > span": {
|
|
1247
|
+
color: `${colors.blue[600]} !important`
|
|
1248
|
+
},
|
|
1249
|
+
".cm-searchMatch-selected": {
|
|
1250
|
+
backgroundColor: colors.blue[600]
|
|
1251
|
+
},
|
|
1252
|
+
".cm-searchMatch-selected > span": {
|
|
1253
|
+
color: `${colors.white} !important`
|
|
1254
|
+
}
|
|
1255
|
+
});
|
|
1256
|
+
function searchExtension() {
|
|
1257
|
+
return [searchField, searchViewPlugin, searchTheme];
|
|
1258
|
+
}
|
|
1259
|
+
function updateSearch(view, query, selectedMatchIndex) {
|
|
1260
|
+
view.dispatch({ effects: setSearchEffect.of({ query, selectedMatchIndex }) });
|
|
1261
|
+
}
|
|
1093
1262
|
var KbdSeparator = ({ className, ...props }) => /* @__PURE__ */ jsx("span", { ...props, className: cn("tw:text-xs tw:text-muted-foreground", className) });
|
|
1094
1263
|
var KbdGroup = ({ ref, className, children, separator, ...props }) => {
|
|
1095
1264
|
return /* @__PURE__ */ jsx(
|
|
@@ -1149,12 +1318,79 @@ Kbd.Group = KbdGroup;
|
|
|
1149
1318
|
Kbd.Separator = KbdSeparator;
|
|
1150
1319
|
var ToggleComponentHelp = () => /* @__PURE__ */ jsxs("div", { children: [
|
|
1151
1320
|
"Use ",
|
|
1152
|
-
/* @__PURE__ */ jsx(Kbd, { children: "Ctrl+/" }),
|
|
1153
|
-
" or ",
|
|
1154
|
-
/* @__PURE__ */ jsx(Kbd, { children: "Command+/" }),
|
|
1321
|
+
/* @__PURE__ */ jsx(Kbd, { children: isMac ? "Command+/" : "Ctrl+/" }),
|
|
1155
1322
|
" to toggle comments."
|
|
1156
1323
|
] });
|
|
1157
|
-
var
|
|
1324
|
+
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);
|
|
1325
|
+
var crops = (style) => style.overflowX !== "visible" || style.overflowY !== "visible" || style.maskImage !== "none" || style.contentVisibility !== "visible" || /\b(paint|strict|content)\b/.test(style.contain);
|
|
1326
|
+
var findTooltipHost = (from) => {
|
|
1327
|
+
let outermostCropper = null;
|
|
1328
|
+
for (let node = from.parentElement; node && node !== document.body; node = node.parentElement) {
|
|
1329
|
+
const style = getComputedStyle(node);
|
|
1330
|
+
if (crops(style)) {
|
|
1331
|
+
outermostCropper = node;
|
|
1332
|
+
} else if (establishesFixedContainingBlock(style)) {
|
|
1333
|
+
return outermostCropper?.parentElement ?? node;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
return outermostCropper?.parentElement ?? null;
|
|
1337
|
+
};
|
|
1338
|
+
var tooltipsExtension = () => {
|
|
1339
|
+
const layer = new Compartment();
|
|
1340
|
+
return [
|
|
1341
|
+
layer.of(tooltips()),
|
|
1342
|
+
ViewPlugin.define((view) => {
|
|
1343
|
+
const scheduled = setTimeout(() => {
|
|
1344
|
+
if (!view.dom.isConnected) return;
|
|
1345
|
+
const parent = findTooltipHost(view.dom);
|
|
1346
|
+
if (parent) view.dispatch({ effects: layer.reconfigure(tooltips({ parent })) });
|
|
1347
|
+
});
|
|
1348
|
+
return { destroy: () => clearTimeout(scheduled) };
|
|
1349
|
+
})
|
|
1350
|
+
];
|
|
1351
|
+
};
|
|
1352
|
+
var useTooltipsExtension = () => useMemo(tooltipsExtension, []);
|
|
1353
|
+
|
|
1354
|
+
// src/components/CodeEditor/variableCompletion.ts
|
|
1355
|
+
var BOOST = 2e3;
|
|
1356
|
+
var NAME = String.raw`[\w-]*`;
|
|
1357
|
+
var AT_CARET = new RegExp(String.raw`(?:\{{1,2} ?)?${NAME}$`);
|
|
1358
|
+
var NAME_AT_END = new RegExp(`${NAME}$`);
|
|
1359
|
+
var OPENING = /\{{1,2} ?$/;
|
|
1360
|
+
var CLOSING = /^ ?\}{1,2}/;
|
|
1361
|
+
var completeVariables = (variables = []) => {
|
|
1362
|
+
if (variables.length === 0) return () => null;
|
|
1363
|
+
const options = variables.map(({ name, value }) => ({
|
|
1364
|
+
// The bare name: `SqlEditor` filters prefix-only while `CodeEditor` filters
|
|
1365
|
+
// fuzzily, and this is the only spelling both accept whether or not the caret
|
|
1366
|
+
// has typed the braces. The braces are `displayLabel`, which is what renders.
|
|
1367
|
+
label: name,
|
|
1368
|
+
displayLabel: `{{${name}}}`,
|
|
1369
|
+
detail: value,
|
|
1370
|
+
type: "variable",
|
|
1371
|
+
boost: BOOST,
|
|
1372
|
+
apply: (view, completion, from, to) => {
|
|
1373
|
+
const { doc } = view.state;
|
|
1374
|
+
const line = doc.lineAt(from);
|
|
1375
|
+
const insert = `{{${completion.label}}}`;
|
|
1376
|
+
const opening = OPENING.exec(doc.sliceString(line.from, from));
|
|
1377
|
+
const closing = CLOSING.exec(doc.sliceString(to, line.to));
|
|
1378
|
+
const start = opening ? from - opening[0].length : from;
|
|
1379
|
+
const end = closing ? to + closing[0].length : to;
|
|
1380
|
+
view.dispatch({
|
|
1381
|
+
changes: { from: start, to: end, insert },
|
|
1382
|
+
selection: { anchor: start + insert.length }
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1385
|
+
}));
|
|
1386
|
+
return (context) => {
|
|
1387
|
+
const match = context.matchBefore(AT_CARET);
|
|
1388
|
+
if (!match?.text) return null;
|
|
1389
|
+
const [name = ""] = NAME_AT_END.exec(match.text) ?? [];
|
|
1390
|
+
return { from: match.to - name.length, options };
|
|
1391
|
+
};
|
|
1392
|
+
};
|
|
1393
|
+
var useVariableCompletion = (variables = []) => useStableCallback(completeVariables(variables));
|
|
1158
1394
|
var emptyObject = {};
|
|
1159
1395
|
var CodeEditor = ({
|
|
1160
1396
|
value,
|
|
@@ -1163,8 +1399,13 @@ var CodeEditor = ({
|
|
|
1163
1399
|
mode = "application/json",
|
|
1164
1400
|
placeholder: placeholder$1 = "",
|
|
1165
1401
|
ariaLabel,
|
|
1402
|
+
searchQuery,
|
|
1403
|
+
searchMatchIndex,
|
|
1166
1404
|
readOnly = false,
|
|
1167
|
-
|
|
1405
|
+
inputLocked = false,
|
|
1406
|
+
autocompletions,
|
|
1407
|
+
completionSource,
|
|
1408
|
+
variables,
|
|
1168
1409
|
extraKeys = emptyObject,
|
|
1169
1410
|
withToggleCommentHint = false,
|
|
1170
1411
|
withAutofocus = false,
|
|
@@ -1179,49 +1420,86 @@ var CodeEditor = ({
|
|
|
1179
1420
|
className
|
|
1180
1421
|
}) => {
|
|
1181
1422
|
const handleChange = useStableCallback((next) => onChange?.(next));
|
|
1423
|
+
const withSearch = searchQuery !== void 0;
|
|
1424
|
+
const editorRef = useRef(null);
|
|
1425
|
+
useEffect(() => {
|
|
1426
|
+
const view = editorRef.current?.view;
|
|
1427
|
+
if (view && withSearch) updateSearch(view, searchQuery, searchMatchIndex);
|
|
1428
|
+
}, [withSearch, searchQuery, searchMatchIndex]);
|
|
1429
|
+
const handleCreateEditor = useStableCallback((view) => {
|
|
1430
|
+
if (searchQuery) updateSearch(view, searchQuery, searchMatchIndex);
|
|
1431
|
+
});
|
|
1432
|
+
const extraKeysRef = useRef(extraKeys);
|
|
1433
|
+
useLayoutEffect(() => {
|
|
1434
|
+
extraKeysRef.current = extraKeys;
|
|
1435
|
+
});
|
|
1436
|
+
const boundKeysSignature = Object.keys(extraKeys).join("\n");
|
|
1437
|
+
const boundKeys = useMemo(
|
|
1438
|
+
() => boundKeysSignature.split("\n").filter(Boolean),
|
|
1439
|
+
[boundKeysSignature]
|
|
1440
|
+
);
|
|
1441
|
+
const tooltipLayer = useTooltipsExtension();
|
|
1442
|
+
const variableCompletion = useVariableCompletion(variables);
|
|
1182
1443
|
const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
|
|
1183
1444
|
const baseTheme = useThemedExtension(
|
|
1184
1445
|
"code-editor:chrome",
|
|
1185
1446
|
() => EditorView.theme(buildBaseThemeStyles())
|
|
1186
1447
|
);
|
|
1187
1448
|
const commonExtensions = useMemo(() => {
|
|
1449
|
+
const callerCompletions = completionSource ?? (completeAny ? completeAnyWord : autocompletions?.length ? autocompletions : null);
|
|
1450
|
+
const completionEntries = [
|
|
1451
|
+
...callerCompletions ? [{ autocomplete: callerCompletions }] : [],
|
|
1452
|
+
{ autocomplete: variableCompletion }
|
|
1453
|
+
];
|
|
1188
1454
|
return [
|
|
1189
1455
|
getLanguageMode(mode),
|
|
1190
1456
|
shouldLintJson(mode, readOnly) ? linter(jsonParseLinter()) : [],
|
|
1191
1457
|
withLineWrapping ? EditorView.lineWrapping : [],
|
|
1192
|
-
EditorState.languageData.of(() =>
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
keymap.of(
|
|
1196
|
-
Object.entries(extraKeys).map(([key, run]) => ({
|
|
1458
|
+
EditorState.languageData.of(() => completionEntries),
|
|
1459
|
+
keymap$1.of(
|
|
1460
|
+
boundKeys.map((key) => ({
|
|
1197
1461
|
key,
|
|
1198
1462
|
run: () => {
|
|
1199
|
-
|
|
1200
|
-
run();
|
|
1463
|
+
extraKeysRef.current[key]?.();
|
|
1201
1464
|
return true;
|
|
1202
1465
|
}
|
|
1203
1466
|
}))
|
|
1204
1467
|
),
|
|
1205
|
-
readOnly ? [] :
|
|
1468
|
+
readOnly ? [] : [
|
|
1469
|
+
// CodeMirror's own default. Gating it on the props hid completions the
|
|
1470
|
+
// *language* supplies — dbt's vocabulary, Snowflake's keywords — behind
|
|
1471
|
+
// a shortcut, and macOS leaves no usable one. With nothing to offer, no
|
|
1472
|
+
// popup opens anyway.
|
|
1473
|
+
autocompletion()
|
|
1474
|
+
],
|
|
1206
1475
|
ariaLabel ? EditorView.contentAttributes.of({ "aria-label": ariaLabel }) : [],
|
|
1476
|
+
withSearch ? searchExtension() : [],
|
|
1477
|
+
tooltipLayer,
|
|
1207
1478
|
baseTheme
|
|
1208
1479
|
];
|
|
1209
1480
|
}, [
|
|
1210
1481
|
autocompletions,
|
|
1482
|
+
completionSource,
|
|
1483
|
+
variableCompletion,
|
|
1211
1484
|
completeAny,
|
|
1212
|
-
|
|
1485
|
+
boundKeys,
|
|
1213
1486
|
mode,
|
|
1214
1487
|
readOnly,
|
|
1215
1488
|
withLineWrapping,
|
|
1216
1489
|
baseTheme,
|
|
1217
|
-
ariaLabel
|
|
1490
|
+
ariaLabel,
|
|
1491
|
+
withSearch,
|
|
1492
|
+
tooltipLayer
|
|
1218
1493
|
]);
|
|
1219
1494
|
const extensions = useMemo(() => {
|
|
1220
1495
|
return [
|
|
1221
1496
|
...commonExtensions,
|
|
1222
1497
|
placeholder(placeholder$1),
|
|
1223
1498
|
EditorView.editable.of(!readOnly),
|
|
1224
|
-
|
|
1499
|
+
// The lock is this facet and nothing else. `contenteditable` is what the
|
|
1500
|
+
// read-only wash keys off, and `basicSetup` is what holds the undo history,
|
|
1501
|
+
// so leaving both alone is what makes the lock invisible.
|
|
1502
|
+
EditorState.readOnly.of(readOnly || inputLocked),
|
|
1225
1503
|
previousValue ? unifiedMergeView({
|
|
1226
1504
|
original: previousValue,
|
|
1227
1505
|
mergeControls: false,
|
|
@@ -1229,13 +1507,16 @@ var CodeEditor = ({
|
|
|
1229
1507
|
collapseUnchanged: withCollapseUnchanged ? {} : void 0
|
|
1230
1508
|
}) : []
|
|
1231
1509
|
];
|
|
1232
|
-
}, [commonExtensions, placeholder$1, readOnly, previousValue, withCollapseUnchanged]);
|
|
1510
|
+
}, [commonExtensions, placeholder$1, readOnly, inputLocked, previousValue, withCollapseUnchanged]);
|
|
1233
1511
|
const config = useMemo(() => {
|
|
1234
1512
|
return {
|
|
1235
1513
|
...buildBasicSetup(readOnly),
|
|
1236
|
-
lineNumbers: withLineNumbers
|
|
1514
|
+
lineNumbers: withLineNumbers,
|
|
1515
|
+
// Mod-f opens CodeMirror's own panel, which would run a second query and a
|
|
1516
|
+
// second match count over the same document beside the caller's input.
|
|
1517
|
+
...withSearch ? { searchKeymap: false } : null
|
|
1237
1518
|
};
|
|
1238
|
-
}, [withLineNumbers, readOnly]);
|
|
1519
|
+
}, [withLineNumbers, readOnly, withSearch]);
|
|
1239
1520
|
const additionalButtons = renderAdditionalButtons?.(value);
|
|
1240
1521
|
const hasToolbar = withCopyButton && !!value || !!additionalButtons;
|
|
1241
1522
|
return (
|
|
@@ -1258,6 +1539,8 @@ var CodeEditor = ({
|
|
|
1258
1539
|
/* @__PURE__ */ jsx(
|
|
1259
1540
|
CodeMirror,
|
|
1260
1541
|
{
|
|
1542
|
+
ref: editorRef,
|
|
1543
|
+
onCreateEditor: handleCreateEditor,
|
|
1261
1544
|
theme: customTheme,
|
|
1262
1545
|
value,
|
|
1263
1546
|
onChange: handleChange,
|
|
@@ -1450,8 +1733,6 @@ var activeQueryHighlight = (splitQueries) => {
|
|
|
1450
1733
|
})
|
|
1451
1734
|
];
|
|
1452
1735
|
};
|
|
1453
|
-
|
|
1454
|
-
// src/components/CodeEditor/highlighting.ts
|
|
1455
1736
|
var HighlightMarker = class extends GutterMarker {
|
|
1456
1737
|
toDOM() {
|
|
1457
1738
|
const marker = document.createElement("div");
|
|
@@ -1567,125 +1848,18 @@ var highlightedLinesTheme = EditorView.baseTheme({
|
|
|
1567
1848
|
backgroundColor: `${colors.blue[100]} !important`
|
|
1568
1849
|
}
|
|
1569
1850
|
});
|
|
1570
|
-
function highlightingExtension(
|
|
1851
|
+
function highlightingExtension() {
|
|
1571
1852
|
return [
|
|
1572
1853
|
highlightedLinesField,
|
|
1573
1854
|
highlightGutter,
|
|
1574
1855
|
errorLineDecorations,
|
|
1575
1856
|
processingLineDecorations,
|
|
1576
|
-
highlightedLinesTheme
|
|
1577
|
-
...queryParser ? activeQueryHighlight(queryParser) : []
|
|
1857
|
+
highlightedLinesTheme
|
|
1578
1858
|
];
|
|
1579
1859
|
}
|
|
1580
1860
|
function updateHighlighting(view, lines) {
|
|
1581
1861
|
view.dispatch({ effects: setHighlightedLinesEffect.of(lines ?? null) });
|
|
1582
1862
|
}
|
|
1583
|
-
var setSearchEffect = StateEffect.define();
|
|
1584
|
-
function findMatches(doc, query) {
|
|
1585
|
-
if (!query) return [];
|
|
1586
|
-
const text = doc.toString();
|
|
1587
|
-
try {
|
|
1588
|
-
const regex = new RegExp(escapeStringRegexp(query), "gi");
|
|
1589
|
-
return Array.from(text.matchAll(regex)).map((match, index) => {
|
|
1590
|
-
const from = match.index;
|
|
1591
|
-
const to = from + match[0].length;
|
|
1592
|
-
return { from, to, text: match[0], localIndex: index };
|
|
1593
|
-
});
|
|
1594
|
-
} catch (e) {
|
|
1595
|
-
console.warn("Invalid search regex:", e);
|
|
1596
|
-
return [];
|
|
1597
|
-
}
|
|
1598
|
-
}
|
|
1599
|
-
function createDecorations(matches, selectedLocalIndex) {
|
|
1600
|
-
const decorations = matches.map((match) => {
|
|
1601
|
-
const isSelected = match.localIndex === selectedLocalIndex;
|
|
1602
|
-
const decoration = Decoration.mark({
|
|
1603
|
-
class: isSelected ? "cm-searchMatch-selected" : "cm-searchMatch"
|
|
1604
|
-
});
|
|
1605
|
-
return decoration.range(match.from, match.to);
|
|
1606
|
-
});
|
|
1607
|
-
return Decoration.set(decorations, true);
|
|
1608
|
-
}
|
|
1609
|
-
var searchField = StateField.define({
|
|
1610
|
-
create() {
|
|
1611
|
-
return {
|
|
1612
|
-
query: "",
|
|
1613
|
-
selectedMatchIndex: void 0,
|
|
1614
|
-
matches: [],
|
|
1615
|
-
decorations: Decoration.none
|
|
1616
|
-
};
|
|
1617
|
-
},
|
|
1618
|
-
update(state, tr) {
|
|
1619
|
-
let newState = state;
|
|
1620
|
-
for (const effect of tr.effects) {
|
|
1621
|
-
if (!effect.is(setSearchEffect)) {
|
|
1622
|
-
continue;
|
|
1623
|
-
}
|
|
1624
|
-
const { query, selectedMatchIndex } = effect.value;
|
|
1625
|
-
const matches = findMatches(tr.state.doc, query);
|
|
1626
|
-
const decorations = createDecorations(matches, selectedMatchIndex);
|
|
1627
|
-
newState = {
|
|
1628
|
-
query,
|
|
1629
|
-
selectedMatchIndex,
|
|
1630
|
-
matches,
|
|
1631
|
-
decorations
|
|
1632
|
-
};
|
|
1633
|
-
}
|
|
1634
|
-
if (tr.docChanged && newState.query) {
|
|
1635
|
-
const matches = findMatches(tr.state.doc, newState.query);
|
|
1636
|
-
const decorations = createDecorations(matches, newState.selectedMatchIndex);
|
|
1637
|
-
newState = {
|
|
1638
|
-
...newState,
|
|
1639
|
-
matches,
|
|
1640
|
-
decorations
|
|
1641
|
-
};
|
|
1642
|
-
}
|
|
1643
|
-
return newState;
|
|
1644
|
-
},
|
|
1645
|
-
provide: (field) => EditorView.decorations.from(field, (state) => state.decorations)
|
|
1646
|
-
});
|
|
1647
|
-
var searchViewPlugin = ViewPlugin.fromClass(
|
|
1648
|
-
class {
|
|
1649
|
-
lastSelectedIndex;
|
|
1650
|
-
update(update) {
|
|
1651
|
-
const state = update.state.field(searchField);
|
|
1652
|
-
if (state.selectedMatchIndex !== void 0 && state.selectedMatchIndex !== this.lastSelectedIndex) {
|
|
1653
|
-
const match = state.matches[state.selectedMatchIndex];
|
|
1654
|
-
if (match) {
|
|
1655
|
-
requestAnimationFrame(() => {
|
|
1656
|
-
update.view.dispatch({
|
|
1657
|
-
effects: EditorView.scrollIntoView(match.from, { y: "center" })
|
|
1658
|
-
});
|
|
1659
|
-
});
|
|
1660
|
-
}
|
|
1661
|
-
this.lastSelectedIndex = state.selectedMatchIndex;
|
|
1662
|
-
}
|
|
1663
|
-
if (state.selectedMatchIndex === void 0) {
|
|
1664
|
-
this.lastSelectedIndex = void 0;
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
}
|
|
1668
|
-
);
|
|
1669
|
-
var searchTheme = EditorView.baseTheme({
|
|
1670
|
-
".cm-searchMatch": {
|
|
1671
|
-
backgroundColor: colors.blue[100]
|
|
1672
|
-
},
|
|
1673
|
-
".cm-searchMatch > span": {
|
|
1674
|
-
color: `${colors.blue[600]} !important`
|
|
1675
|
-
},
|
|
1676
|
-
".cm-searchMatch-selected": {
|
|
1677
|
-
backgroundColor: colors.blue[600]
|
|
1678
|
-
},
|
|
1679
|
-
".cm-searchMatch-selected > span": {
|
|
1680
|
-
color: `${colors.white} !important`
|
|
1681
|
-
}
|
|
1682
|
-
});
|
|
1683
|
-
function searchExtension() {
|
|
1684
|
-
return [searchField, searchViewPlugin, searchTheme];
|
|
1685
|
-
}
|
|
1686
|
-
function updateSearch(view, query, selectedMatchIndex) {
|
|
1687
|
-
view.dispatch({ effects: setSearchEffect.of({ query, selectedMatchIndex }) });
|
|
1688
|
-
}
|
|
1689
1863
|
var OWN_KEYMAPS = {
|
|
1690
1864
|
defaultKeymap: false,
|
|
1691
1865
|
completionKeymap: false,
|
|
@@ -1701,6 +1875,7 @@ var CUSTOM_KEYMAP = [
|
|
|
1701
1875
|
}
|
|
1702
1876
|
}
|
|
1703
1877
|
];
|
|
1878
|
+
var OWN_KEYMAP_EXTENSION = keymap.of([...defaultKeymap, ...CUSTOM_KEYMAP]);
|
|
1704
1879
|
var buildTheme = () => ({
|
|
1705
1880
|
...buildBaseThemeStyles(),
|
|
1706
1881
|
"&.cm-editor": {
|
|
@@ -1738,7 +1913,6 @@ var SqlEditor = ({
|
|
|
1738
1913
|
searchQuery = "",
|
|
1739
1914
|
searchMatchIndex,
|
|
1740
1915
|
readOnly = false,
|
|
1741
|
-
extraKeys,
|
|
1742
1916
|
queryParser,
|
|
1743
1917
|
autoFocus = false,
|
|
1744
1918
|
lineNumbers = true,
|
|
@@ -1751,34 +1925,57 @@ var SqlEditor = ({
|
|
|
1751
1925
|
dialect
|
|
1752
1926
|
}) => {
|
|
1753
1927
|
const editorRef = useRef(null);
|
|
1928
|
+
const handleChange = useStableCallback((next) => onChange?.(next));
|
|
1929
|
+
const parseQueries = useStableCallback(async (sql2) => await queryParser?.(sql2) ?? []);
|
|
1930
|
+
const handleBlur = useStableCallback((view) => onBlurEditor?.(view));
|
|
1931
|
+
const handleFocus = useStableCallback((view) => onFocusEditor?.(view));
|
|
1932
|
+
const handleUpdate = useStableCallback((update) => {
|
|
1933
|
+
if (update.selectionSet) {
|
|
1934
|
+
const { main } = update.state.selection;
|
|
1935
|
+
onSelectionChange?.(update.state.sliceDoc(main.from, main.to));
|
|
1936
|
+
}
|
|
1937
|
+
});
|
|
1938
|
+
const variableCompletion = useVariableCompletion(variables);
|
|
1939
|
+
const withQueryParser = queryParser !== void 0;
|
|
1940
|
+
const tooltipLayer = useTooltipsExtension();
|
|
1754
1941
|
const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
|
|
1755
1942
|
const themeExtension = useThemedExtension(
|
|
1756
1943
|
"sql-editor:chrome",
|
|
1757
1944
|
() => EditorView$1.theme(buildTheme())
|
|
1758
1945
|
);
|
|
1759
1946
|
const extensions = useMemo(() => {
|
|
1760
|
-
const baseKeymap = [...defaultKeymap, ...CUSTOM_KEYMAP];
|
|
1761
1947
|
return [
|
|
1762
1948
|
EditorView$1.lineWrapping,
|
|
1763
|
-
|
|
1764
|
-
...installExtensions({
|
|
1949
|
+
OWN_KEYMAP_EXTENSION,
|
|
1950
|
+
...installExtensions({
|
|
1951
|
+
schema,
|
|
1952
|
+
defaultDatabase,
|
|
1953
|
+
defaultSchema,
|
|
1954
|
+
variableCompletion,
|
|
1955
|
+
dialect
|
|
1956
|
+
}),
|
|
1765
1957
|
searchExtension(),
|
|
1766
|
-
highlightingExtension(
|
|
1958
|
+
highlightingExtension(),
|
|
1959
|
+
withQueryParser ? activeQueryHighlight(parseQueries) : [],
|
|
1960
|
+
tooltipLayer,
|
|
1767
1961
|
themeExtension,
|
|
1768
|
-
|
|
1769
|
-
|
|
1962
|
+
EditorView$1.domEventHandlers({
|
|
1963
|
+
blur: (_, view) => handleBlur(view),
|
|
1964
|
+
focus: (_, view) => handleFocus(view)
|
|
1965
|
+
})
|
|
1770
1966
|
];
|
|
1771
1967
|
}, [
|
|
1772
|
-
|
|
1773
|
-
|
|
1968
|
+
withQueryParser,
|
|
1969
|
+
parseQueries,
|
|
1774
1970
|
schema,
|
|
1775
1971
|
defaultDatabase,
|
|
1776
1972
|
defaultSchema,
|
|
1777
|
-
|
|
1973
|
+
variableCompletion,
|
|
1778
1974
|
dialect,
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
themeExtension
|
|
1975
|
+
handleBlur,
|
|
1976
|
+
handleFocus,
|
|
1977
|
+
themeExtension,
|
|
1978
|
+
tooltipLayer
|
|
1782
1979
|
]);
|
|
1783
1980
|
const defaultSetup = useMemo(() => {
|
|
1784
1981
|
return { ...buildBasicSetup(readOnly), ...OWN_KEYMAPS, lineNumbers };
|
|
@@ -1793,34 +1990,17 @@ var SqlEditor = ({
|
|
|
1793
1990
|
updateSearch(editorRef.current.view, searchQuery, searchMatchIndex);
|
|
1794
1991
|
}
|
|
1795
1992
|
}, [searchQuery, searchMatchIndex]);
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
(
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
}
|
|
1808
|
-
if (searchQuery) {
|
|
1809
|
-
updateSearch(view, searchQuery, searchMatchIndex);
|
|
1810
|
-
}
|
|
1811
|
-
},
|
|
1812
|
-
[onCreateEditor, highlightLines, searchQuery, searchMatchIndex]
|
|
1813
|
-
);
|
|
1814
|
-
const handleOnUpdate = useCallback(
|
|
1815
|
-
(update) => {
|
|
1816
|
-
if (update.selectionSet) {
|
|
1817
|
-
const { main } = update.state.selection;
|
|
1818
|
-
const text = update.state.sliceDoc(main.from, main.to);
|
|
1819
|
-
onSelectionChange?.(text);
|
|
1820
|
-
}
|
|
1821
|
-
},
|
|
1822
|
-
[onSelectionChange]
|
|
1823
|
-
);
|
|
1993
|
+
const handleDestroy = useStableCallback(() => onDestroyEditor?.());
|
|
1994
|
+
useEffect(() => handleDestroy, [handleDestroy]);
|
|
1995
|
+
const handleCreate = useStableCallback((view, state) => {
|
|
1996
|
+
onCreateEditor?.(view, state);
|
|
1997
|
+
if (highlightLines) {
|
|
1998
|
+
updateHighlighting(view, highlightLines);
|
|
1999
|
+
}
|
|
2000
|
+
if (searchQuery) {
|
|
2001
|
+
updateSearch(view, searchQuery, searchMatchIndex);
|
|
2002
|
+
}
|
|
2003
|
+
});
|
|
1824
2004
|
return /* @__PURE__ */ jsx(
|
|
1825
2005
|
CodeMirror,
|
|
1826
2006
|
{
|
|
@@ -1828,9 +2008,9 @@ var SqlEditor = ({
|
|
|
1828
2008
|
theme: customTheme,
|
|
1829
2009
|
extensions,
|
|
1830
2010
|
value,
|
|
1831
|
-
onChange,
|
|
1832
|
-
onUpdate:
|
|
1833
|
-
onCreateEditor:
|
|
2011
|
+
onChange: handleChange,
|
|
2012
|
+
onUpdate: handleUpdate,
|
|
2013
|
+
onCreateEditor: handleCreate,
|
|
1834
2014
|
autoFocus,
|
|
1835
2015
|
placeholder,
|
|
1836
2016
|
className,
|