@keboola/design 8.0.0 → 9.0.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 +325 -129
- package/dist/editors.cjs.map +1 -1
- package/dist/editors.d.cts +29 -3
- package/dist/editors.d.ts +29 -3
- package/dist/editors.js +329 -133
- package/dist/editors.js.map +1 -1
- package/dist/rjsf.cjs +317 -20
- package/dist/rjsf.cjs.map +1 -1
- package/dist/rjsf.js +321 -24
- package/dist/rjsf.js.map +1 -1
- package/package.json +5 -5
package/dist/editors.cjs
CHANGED
|
@@ -26,9 +26,9 @@ var codemirrorThemeGithub = require('@uiw/codemirror-theme-github');
|
|
|
26
26
|
var codemirrorLangSfsql = require('@keboola/codemirror-lang-sfsql');
|
|
27
27
|
var colors = require('@keboola/tailwind-config/colors');
|
|
28
28
|
var simpleMode = require('@codemirror/legacy-modes/mode/simple-mode');
|
|
29
|
+
var state = require('@codemirror/state');
|
|
29
30
|
var commands = require('@codemirror/commands');
|
|
30
31
|
var codemirrorLangSql = require('@keboola/codemirror-lang-sql');
|
|
31
|
-
var state = require('@codemirror/state');
|
|
32
32
|
|
|
33
33
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
34
34
|
|
|
@@ -297,6 +297,21 @@ Tooltip.Trigger = TooltipTrigger;
|
|
|
297
297
|
|
|
298
298
|
// src/utils/escapeStringRegexp.ts
|
|
299
299
|
var escapeStringRegexp = (string) => string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
|
|
300
|
+
|
|
301
|
+
// src/utils/isMac.ts
|
|
302
|
+
var getIsMac = () => {
|
|
303
|
+
if (typeof navigator !== "undefined" && "userAgentData" in navigator) {
|
|
304
|
+
const platform = navigator.userAgentData.platform;
|
|
305
|
+
if (typeof platform === "string") {
|
|
306
|
+
return platform.toLowerCase() === "macos";
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (typeof navigator !== "undefined" && typeof navigator.platform === "string") {
|
|
310
|
+
return navigator.platform.toUpperCase().indexOf("MAC") >= 0;
|
|
311
|
+
}
|
|
312
|
+
return false;
|
|
313
|
+
};
|
|
314
|
+
var isMac = getIsMac();
|
|
300
315
|
var helpVariants = classVarianceAuthority.cva(["tw:m-0", "tw:text-xs"], {
|
|
301
316
|
defaultVariants: {
|
|
302
317
|
state: "default"
|
|
@@ -747,8 +762,6 @@ var ButtonToolbar = ({ value, children }) => {
|
|
|
747
762
|
};
|
|
748
763
|
var COMMANDS = [
|
|
749
764
|
"run-operation",
|
|
750
|
-
"source freshness",
|
|
751
|
-
"docs generate",
|
|
752
765
|
"run",
|
|
753
766
|
"test",
|
|
754
767
|
"seed",
|
|
@@ -757,9 +770,13 @@ var COMMANDS = [
|
|
|
757
770
|
"ls",
|
|
758
771
|
"compile",
|
|
759
772
|
"build",
|
|
760
|
-
"deps"
|
|
773
|
+
"deps",
|
|
774
|
+
"docs",
|
|
775
|
+
"source"
|
|
761
776
|
];
|
|
777
|
+
var SUBCOMMANDS = { docs: ["generate"], source: ["freshness"] };
|
|
762
778
|
var ARGUMENTS = ["--select", "--exclude", "--selector", "--defer", "--resource-type", "-s"];
|
|
779
|
+
var SELECTORS = ["--select", "--exclude", "-s"];
|
|
763
780
|
var METHODS = [
|
|
764
781
|
"path:",
|
|
765
782
|
"source:",
|
|
@@ -786,13 +803,59 @@ var FLAGS = [
|
|
|
786
803
|
"--profile",
|
|
787
804
|
"--full-refresh"
|
|
788
805
|
];
|
|
789
|
-
var
|
|
790
|
-
|
|
806
|
+
var COMMAND_PHRASES = COMMANDS.flatMap((command) => {
|
|
807
|
+
const subcommands = SUBCOMMANDS[command];
|
|
808
|
+
return subcommands ? subcommands.map((subcommand) => `${command} ${subcommand}`) : [command];
|
|
809
|
+
});
|
|
810
|
+
var alternation = (list) => [...list].sort((a, b) => b.length - a.length).join("|");
|
|
811
|
+
var word = (list) => new RegExp(`^\\s+(?:${alternation(list)})\\b`, "i");
|
|
812
|
+
var prefix = (list) => new RegExp(`^\\s+(?:${alternation(list)})`, "i");
|
|
813
|
+
var WORD = /[\w:-]*$/;
|
|
814
|
+
var asOptions = (list, type) => list.map((label) => ({ label, type }));
|
|
815
|
+
var DBT = [{ label: "dbt", type: "keyword" }];
|
|
816
|
+
var COMMAND_OPTIONS = asOptions(COMMANDS, "keyword");
|
|
817
|
+
var SUBCOMMAND_OPTIONS = Object.fromEntries(
|
|
818
|
+
Object.entries(SUBCOMMANDS).map(([command, subcommands]) => [
|
|
819
|
+
command,
|
|
820
|
+
asOptions(subcommands, "keyword")
|
|
821
|
+
])
|
|
822
|
+
);
|
|
823
|
+
var ARGUMENT_OPTIONS = asOptions(ARGUMENTS, "variable");
|
|
824
|
+
var FLAG_OPTIONS = asOptions(FLAGS, "constant");
|
|
825
|
+
var METHOD_OPTIONS = asOptions(METHODS, "property");
|
|
826
|
+
var optionsAfter = (words) => {
|
|
827
|
+
const [step, command, ...rest] = words;
|
|
828
|
+
if (step === void 0) return DBT;
|
|
829
|
+
if (step.toLowerCase() !== "dbt") return [];
|
|
830
|
+
if (command === void 0) return COMMAND_OPTIONS;
|
|
831
|
+
const subcommands = SUBCOMMAND_OPTIONS[command.toLowerCase()];
|
|
832
|
+
if (subcommands && rest.length === 0) return subcommands;
|
|
833
|
+
const lastArgument = rest.filter((it) => it.startsWith("-")).at(-1);
|
|
834
|
+
const selecting = lastArgument !== void 0 && SELECTORS.includes(lastArgument.toLowerCase());
|
|
835
|
+
return selecting ? [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS, ...METHOD_OPTIONS] : [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS];
|
|
836
|
+
};
|
|
837
|
+
var complete = (context) => {
|
|
838
|
+
const typed = context.matchBefore(WORD);
|
|
839
|
+
if (!typed?.text && !context.explicit) return null;
|
|
840
|
+
const from = typed?.from ?? context.pos;
|
|
841
|
+
const line = context.state.doc.lineAt(from);
|
|
842
|
+
const options = optionsAfter(
|
|
843
|
+
line.text.slice(0, from - line.from).split(/\s+/).filter(Boolean)
|
|
844
|
+
);
|
|
845
|
+
return options.length > 0 ? { from, options, validFor: WORD } : null;
|
|
846
|
+
};
|
|
791
847
|
var dbt = simpleMode.simpleMode({
|
|
848
|
+
languageData: {
|
|
849
|
+
// `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
|
|
850
|
+
commentTokens: { line: "--", block: { open: "/*", close: "*/" } },
|
|
851
|
+
autocomplete: complete
|
|
852
|
+
},
|
|
792
853
|
start: [
|
|
793
854
|
{ regex: /"(?:[^\\]|\\.)*?(?:"|$)/, token: "string" },
|
|
794
|
-
|
|
795
|
-
|
|
855
|
+
// Word-bounded, so `dbtX` is not a dbt step whose first word happens to
|
|
856
|
+
// colour — the same thing the completion source asks of it.
|
|
857
|
+
{ regex: /dbt\b/, token: "keyword", sol: true },
|
|
858
|
+
{ regex: word(COMMAND_PHRASES), token: "keyword" },
|
|
796
859
|
{ regex: word(ARGUMENTS), token: "variableName" },
|
|
797
860
|
{ regex: prefix(METHODS), token: "propertyName" },
|
|
798
861
|
{ regex: prefix(FLAGS), token: "attributeName" },
|
|
@@ -840,6 +903,8 @@ var KEYWORDS = {
|
|
|
840
903
|
};
|
|
841
904
|
var jsonnet = {
|
|
842
905
|
name: "jsonnet",
|
|
906
|
+
// `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
|
|
907
|
+
languageData: { commentTokens: { line: "//", block: { open: "/*", close: "*/" } } },
|
|
843
908
|
startState: () => ({
|
|
844
909
|
cComment: false,
|
|
845
910
|
textBlock: false,
|
|
@@ -1056,6 +1121,20 @@ var buildCustomTheme = () => codemirrorThemeGithub.githubLightInit({
|
|
|
1056
1121
|
selection: resolveToken("primary", "31 143 255")
|
|
1057
1122
|
}
|
|
1058
1123
|
});
|
|
1124
|
+
var sfsqlWithLanguageData = {
|
|
1125
|
+
...codemirrorLangSfsql.sfsql,
|
|
1126
|
+
languageData: {
|
|
1127
|
+
...codemirrorLangSfsql.sfsql.languageData,
|
|
1128
|
+
// `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
|
|
1129
|
+
commentTokens: { line: "--", block: { open: "/*", close: "*/" } },
|
|
1130
|
+
autocomplete: autocomplete.completeFromList(
|
|
1131
|
+
Object.keys(codemirrorLangSfsql.modeSpec.keywords).map((label) => ({
|
|
1132
|
+
label: label.toUpperCase(),
|
|
1133
|
+
type: "keyword"
|
|
1134
|
+
}))
|
|
1135
|
+
)
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1059
1138
|
var getLanguageMode = (mode) => {
|
|
1060
1139
|
switch (mode) {
|
|
1061
1140
|
case void 0:
|
|
@@ -1072,7 +1151,7 @@ var getLanguageMode = (mode) => {
|
|
|
1072
1151
|
case "text/x-mssql":
|
|
1073
1152
|
return langSql.sql({ upperCaseKeywords: true, dialect: langSql.MSSQL });
|
|
1074
1153
|
case "text/x-sfsql":
|
|
1075
|
-
return language.StreamLanguage.define(
|
|
1154
|
+
return language.StreamLanguage.define(sfsqlWithLanguageData);
|
|
1076
1155
|
case "text/x-plsql":
|
|
1077
1156
|
return langSql.sql({ upperCaseKeywords: true, dialect: langSql.PLSQL });
|
|
1078
1157
|
case "text/x-rsrc":
|
|
@@ -1097,6 +1176,112 @@ var getLanguageMode = (mode) => {
|
|
|
1097
1176
|
}
|
|
1098
1177
|
};
|
|
1099
1178
|
var shouldLintJson = (mode, readOnly) => mode === "application/json" && !readOnly;
|
|
1179
|
+
var setSearchEffect = state.StateEffect.define();
|
|
1180
|
+
function findMatches(doc, query) {
|
|
1181
|
+
if (!query) return [];
|
|
1182
|
+
const text = doc.toString();
|
|
1183
|
+
try {
|
|
1184
|
+
const regex = new RegExp(escapeStringRegexp(query), "gi");
|
|
1185
|
+
return Array.from(text.matchAll(regex)).map((match, index) => {
|
|
1186
|
+
const from = match.index;
|
|
1187
|
+
const to = from + match[0].length;
|
|
1188
|
+
return { from, to, text: match[0], localIndex: index };
|
|
1189
|
+
});
|
|
1190
|
+
} catch (e) {
|
|
1191
|
+
console.warn("Invalid search regex:", e);
|
|
1192
|
+
return [];
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
function createDecorations(matches, selectedLocalIndex) {
|
|
1196
|
+
const decorations = matches.map((match) => {
|
|
1197
|
+
const isSelected = match.localIndex === selectedLocalIndex;
|
|
1198
|
+
const decoration = view.Decoration.mark({
|
|
1199
|
+
class: isSelected ? "cm-searchMatch-selected" : "cm-searchMatch"
|
|
1200
|
+
});
|
|
1201
|
+
return decoration.range(match.from, match.to);
|
|
1202
|
+
});
|
|
1203
|
+
return view.Decoration.set(decorations, true);
|
|
1204
|
+
}
|
|
1205
|
+
var searchField = state.StateField.define({
|
|
1206
|
+
create() {
|
|
1207
|
+
return {
|
|
1208
|
+
query: "",
|
|
1209
|
+
selectedMatchIndex: void 0,
|
|
1210
|
+
matches: [],
|
|
1211
|
+
decorations: view.Decoration.none
|
|
1212
|
+
};
|
|
1213
|
+
},
|
|
1214
|
+
update(state, tr) {
|
|
1215
|
+
let newState = state;
|
|
1216
|
+
for (const effect of tr.effects) {
|
|
1217
|
+
if (!effect.is(setSearchEffect)) {
|
|
1218
|
+
continue;
|
|
1219
|
+
}
|
|
1220
|
+
const { query, selectedMatchIndex } = effect.value;
|
|
1221
|
+
const matches = findMatches(tr.state.doc, query);
|
|
1222
|
+
const decorations = createDecorations(matches, selectedMatchIndex);
|
|
1223
|
+
newState = {
|
|
1224
|
+
query,
|
|
1225
|
+
selectedMatchIndex,
|
|
1226
|
+
matches,
|
|
1227
|
+
decorations
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
if (tr.docChanged && newState.query) {
|
|
1231
|
+
const matches = findMatches(tr.state.doc, newState.query);
|
|
1232
|
+
const decorations = createDecorations(matches, newState.selectedMatchIndex);
|
|
1233
|
+
newState = {
|
|
1234
|
+
...newState,
|
|
1235
|
+
matches,
|
|
1236
|
+
decorations
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
return newState;
|
|
1240
|
+
},
|
|
1241
|
+
provide: (field) => view.EditorView.decorations.from(field, (state) => state.decorations)
|
|
1242
|
+
});
|
|
1243
|
+
var searchViewPlugin = view.ViewPlugin.fromClass(
|
|
1244
|
+
class {
|
|
1245
|
+
lastSelectedIndex;
|
|
1246
|
+
update(update) {
|
|
1247
|
+
const state = update.state.field(searchField);
|
|
1248
|
+
if (state.selectedMatchIndex !== void 0 && state.selectedMatchIndex !== this.lastSelectedIndex) {
|
|
1249
|
+
const match = state.matches[state.selectedMatchIndex];
|
|
1250
|
+
if (match) {
|
|
1251
|
+
requestAnimationFrame(() => {
|
|
1252
|
+
update.view.dispatch({
|
|
1253
|
+
effects: view.EditorView.scrollIntoView(match.from, { y: "center" })
|
|
1254
|
+
});
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
this.lastSelectedIndex = state.selectedMatchIndex;
|
|
1258
|
+
}
|
|
1259
|
+
if (state.selectedMatchIndex === void 0) {
|
|
1260
|
+
this.lastSelectedIndex = void 0;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
);
|
|
1265
|
+
var searchTheme = view.EditorView.baseTheme({
|
|
1266
|
+
".cm-searchMatch": {
|
|
1267
|
+
backgroundColor: colors__default.default.blue[100]
|
|
1268
|
+
},
|
|
1269
|
+
".cm-searchMatch > span": {
|
|
1270
|
+
color: `${colors__default.default.blue[600]} !important`
|
|
1271
|
+
},
|
|
1272
|
+
".cm-searchMatch-selected": {
|
|
1273
|
+
backgroundColor: colors__default.default.blue[600]
|
|
1274
|
+
},
|
|
1275
|
+
".cm-searchMatch-selected > span": {
|
|
1276
|
+
color: `${colors__default.default.white} !important`
|
|
1277
|
+
}
|
|
1278
|
+
});
|
|
1279
|
+
function searchExtension() {
|
|
1280
|
+
return [searchField, searchViewPlugin, searchTheme];
|
|
1281
|
+
}
|
|
1282
|
+
function updateSearch(view, query, selectedMatchIndex) {
|
|
1283
|
+
view.dispatch({ effects: setSearchEffect.of({ query, selectedMatchIndex }) });
|
|
1284
|
+
}
|
|
1100
1285
|
var KbdSeparator = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("span", { ...props, className: cn("tw:text-xs tw:text-muted-foreground", className) });
|
|
1101
1286
|
var KbdGroup = ({ ref, className, children, separator, ...props }) => {
|
|
1102
1287
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1156,11 +1341,78 @@ Kbd.Group = KbdGroup;
|
|
|
1156
1341
|
Kbd.Separator = KbdSeparator;
|
|
1157
1342
|
var ToggleComponentHelp = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1158
1343
|
"Use ",
|
|
1159
|
-
/* @__PURE__ */ jsxRuntime.jsx(Kbd, { children: "Ctrl+/" }),
|
|
1160
|
-
" or ",
|
|
1161
|
-
/* @__PURE__ */ jsxRuntime.jsx(Kbd, { children: "Command+/" }),
|
|
1344
|
+
/* @__PURE__ */ jsxRuntime.jsx(Kbd, { children: isMac ? "Command+/" : "Ctrl+/" }),
|
|
1162
1345
|
" to toggle comments."
|
|
1163
1346
|
] });
|
|
1347
|
+
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);
|
|
1348
|
+
var crops = (style) => style.overflowX !== "visible" || style.overflowY !== "visible" || style.maskImage !== "none" || style.contentVisibility !== "visible" || /\b(paint|strict|content)\b/.test(style.contain);
|
|
1349
|
+
var findTooltipHost = (from) => {
|
|
1350
|
+
let outermostCropper = null;
|
|
1351
|
+
for (let node = from.parentElement; node && node !== document.body; node = node.parentElement) {
|
|
1352
|
+
const style = getComputedStyle(node);
|
|
1353
|
+
if (crops(style)) {
|
|
1354
|
+
outermostCropper = node;
|
|
1355
|
+
} else if (establishesFixedContainingBlock(style)) {
|
|
1356
|
+
return outermostCropper?.parentElement ?? node;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
return outermostCropper?.parentElement ?? null;
|
|
1360
|
+
};
|
|
1361
|
+
var tooltipsExtension = () => {
|
|
1362
|
+
const layer = new state.Compartment();
|
|
1363
|
+
return [
|
|
1364
|
+
layer.of(view.tooltips()),
|
|
1365
|
+
view.ViewPlugin.define((view$1) => {
|
|
1366
|
+
const scheduled = setTimeout(() => {
|
|
1367
|
+
if (!view$1.dom.isConnected) return;
|
|
1368
|
+
const parent = findTooltipHost(view$1.dom);
|
|
1369
|
+
if (parent) view$1.dispatch({ effects: layer.reconfigure(view.tooltips({ parent })) });
|
|
1370
|
+
});
|
|
1371
|
+
return { destroy: () => clearTimeout(scheduled) };
|
|
1372
|
+
})
|
|
1373
|
+
];
|
|
1374
|
+
};
|
|
1375
|
+
var useTooltipsExtension = () => react.useMemo(tooltipsExtension, []);
|
|
1376
|
+
|
|
1377
|
+
// src/components/CodeEditor/variableCompletion.ts
|
|
1378
|
+
var BOOST = 2e3;
|
|
1379
|
+
var NAME = String.raw`[\w-]*`;
|
|
1380
|
+
var AT_CARET = new RegExp(String.raw`(?:\{{1,2} ?)?${NAME}$`);
|
|
1381
|
+
var NAME_AT_END = new RegExp(`${NAME}$`);
|
|
1382
|
+
var OPENING = /\{{1,2} ?$/;
|
|
1383
|
+
var CLOSING = /^ ?\}{1,2}/;
|
|
1384
|
+
var completeVariables = (variables = []) => {
|
|
1385
|
+
if (variables.length === 0) return () => null;
|
|
1386
|
+
const options = variables.map(({ name, value }) => ({
|
|
1387
|
+
// The bare name: `SqlEditor` filters prefix-only while `CodeEditor` filters
|
|
1388
|
+
// fuzzily, and this is the only spelling both accept whether or not the caret
|
|
1389
|
+
// has typed the braces. The braces are `displayLabel`, which is what renders.
|
|
1390
|
+
label: name,
|
|
1391
|
+
displayLabel: `{{${name}}}`,
|
|
1392
|
+
detail: value,
|
|
1393
|
+
type: "variable",
|
|
1394
|
+
boost: BOOST,
|
|
1395
|
+
apply: (view, completion, from, to) => {
|
|
1396
|
+
const { doc } = view.state;
|
|
1397
|
+
const line = doc.lineAt(from);
|
|
1398
|
+
const insert = `{{${completion.label}}}`;
|
|
1399
|
+
const opening = OPENING.exec(doc.sliceString(line.from, from));
|
|
1400
|
+
const closing = CLOSING.exec(doc.sliceString(to, line.to));
|
|
1401
|
+
const start = opening ? from - opening[0].length : from;
|
|
1402
|
+
const end = closing ? to + closing[0].length : to;
|
|
1403
|
+
view.dispatch({
|
|
1404
|
+
changes: { from: start, to: end, insert },
|
|
1405
|
+
selection: { anchor: start + insert.length }
|
|
1406
|
+
});
|
|
1407
|
+
}
|
|
1408
|
+
}));
|
|
1409
|
+
return (context) => {
|
|
1410
|
+
const match = context.matchBefore(AT_CARET);
|
|
1411
|
+
if (!match?.text) return null;
|
|
1412
|
+
const [name = ""] = NAME_AT_END.exec(match.text) ?? [];
|
|
1413
|
+
return { from: match.to - name.length, options };
|
|
1414
|
+
};
|
|
1415
|
+
};
|
|
1164
1416
|
var emptyArray = [];
|
|
1165
1417
|
var emptyObject = {};
|
|
1166
1418
|
var CodeEditor = ({
|
|
@@ -1170,8 +1422,12 @@ var CodeEditor = ({
|
|
|
1170
1422
|
mode = "application/json",
|
|
1171
1423
|
placeholder = "",
|
|
1172
1424
|
ariaLabel,
|
|
1425
|
+
searchQuery,
|
|
1426
|
+
searchMatchIndex,
|
|
1173
1427
|
readOnly = false,
|
|
1174
1428
|
autocompletions = emptyArray,
|
|
1429
|
+
completionSource,
|
|
1430
|
+
variables,
|
|
1175
1431
|
extraKeys = emptyObject,
|
|
1176
1432
|
withToggleCommentHint = false,
|
|
1177
1433
|
withAutofocus = false,
|
|
@@ -1186,6 +1442,26 @@ var CodeEditor = ({
|
|
|
1186
1442
|
className
|
|
1187
1443
|
}) => {
|
|
1188
1444
|
const handleChange = useStableCallback((next) => onChange?.(next));
|
|
1445
|
+
const withSearch = searchQuery !== void 0;
|
|
1446
|
+
const editorRef = react.useRef(null);
|
|
1447
|
+
react.useEffect(() => {
|
|
1448
|
+
const view = editorRef.current?.view;
|
|
1449
|
+
if (view && withSearch) updateSearch(view, searchQuery, searchMatchIndex);
|
|
1450
|
+
}, [withSearch, searchQuery, searchMatchIndex]);
|
|
1451
|
+
const handleCreateEditor = useStableCallback((view) => {
|
|
1452
|
+
if (searchQuery) updateSearch(view, searchQuery, searchMatchIndex);
|
|
1453
|
+
});
|
|
1454
|
+
const extraKeysRef = react.useRef(extraKeys);
|
|
1455
|
+
react.useLayoutEffect(() => {
|
|
1456
|
+
extraKeysRef.current = extraKeys;
|
|
1457
|
+
});
|
|
1458
|
+
const boundKeysSignature = Object.keys(extraKeys).join("\n");
|
|
1459
|
+
const boundKeys = react.useMemo(
|
|
1460
|
+
() => boundKeysSignature.split("\n").filter(Boolean),
|
|
1461
|
+
[boundKeysSignature]
|
|
1462
|
+
);
|
|
1463
|
+
const tooltipLayer = useTooltipsExtension();
|
|
1464
|
+
const variableCompletion = react.useMemo(() => completeVariables(variables), [variables]);
|
|
1189
1465
|
const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
|
|
1190
1466
|
const baseTheme = useThemedExtension(
|
|
1191
1467
|
"code-editor:chrome",
|
|
@@ -1197,31 +1473,43 @@ var CodeEditor = ({
|
|
|
1197
1473
|
shouldLintJson(mode, readOnly) ? lint.linter(langJson.jsonParseLinter()) : [],
|
|
1198
1474
|
withLineWrapping ? view.EditorView.lineWrapping : [],
|
|
1199
1475
|
CodeMirror.EditorState.languageData.of(() => [
|
|
1200
|
-
{ autocomplete: completeAny ? autocomplete.completeAnyWord : autocompletions }
|
|
1476
|
+
{ autocomplete: completionSource ?? (completeAny ? autocomplete.completeAnyWord : autocompletions) }
|
|
1201
1477
|
]),
|
|
1478
|
+
CodeMirror.EditorState.languageData.of(() => [{ autocomplete: variableCompletion }]),
|
|
1202
1479
|
view.keymap.of(
|
|
1203
|
-
|
|
1480
|
+
boundKeys.map((key) => ({
|
|
1204
1481
|
key,
|
|
1205
1482
|
run: () => {
|
|
1206
|
-
|
|
1207
|
-
run();
|
|
1483
|
+
extraKeysRef.current[key]?.();
|
|
1208
1484
|
return true;
|
|
1209
1485
|
}
|
|
1210
1486
|
}))
|
|
1211
1487
|
),
|
|
1212
|
-
readOnly ? [] :
|
|
1488
|
+
readOnly ? [] : [
|
|
1489
|
+
// CodeMirror's own default. Gating it on the props hid completions the
|
|
1490
|
+
// *language* supplies — dbt's vocabulary, Snowflake's keywords — behind
|
|
1491
|
+
// a shortcut, and macOS leaves no usable one. With nothing to offer, no
|
|
1492
|
+
// popup opens anyway.
|
|
1493
|
+
autocomplete.autocompletion()
|
|
1494
|
+
],
|
|
1213
1495
|
ariaLabel ? view.EditorView.contentAttributes.of({ "aria-label": ariaLabel }) : [],
|
|
1496
|
+
withSearch ? searchExtension() : [],
|
|
1497
|
+
tooltipLayer,
|
|
1214
1498
|
baseTheme
|
|
1215
1499
|
];
|
|
1216
1500
|
}, [
|
|
1217
1501
|
autocompletions,
|
|
1502
|
+
completionSource,
|
|
1503
|
+
variableCompletion,
|
|
1218
1504
|
completeAny,
|
|
1219
|
-
|
|
1505
|
+
boundKeys,
|
|
1220
1506
|
mode,
|
|
1221
1507
|
readOnly,
|
|
1222
1508
|
withLineWrapping,
|
|
1223
1509
|
baseTheme,
|
|
1224
|
-
ariaLabel
|
|
1510
|
+
ariaLabel,
|
|
1511
|
+
withSearch,
|
|
1512
|
+
tooltipLayer
|
|
1225
1513
|
]);
|
|
1226
1514
|
const extensions = react.useMemo(() => {
|
|
1227
1515
|
return [
|
|
@@ -1240,9 +1528,12 @@ var CodeEditor = ({
|
|
|
1240
1528
|
const config = react.useMemo(() => {
|
|
1241
1529
|
return {
|
|
1242
1530
|
...buildBasicSetup(readOnly),
|
|
1243
|
-
lineNumbers: withLineNumbers
|
|
1531
|
+
lineNumbers: withLineNumbers,
|
|
1532
|
+
// Mod-f opens CodeMirror's own panel, which would run a second query and a
|
|
1533
|
+
// second match count over the same document beside the caller's input.
|
|
1534
|
+
...withSearch ? { searchKeymap: false } : null
|
|
1244
1535
|
};
|
|
1245
|
-
}, [withLineNumbers, readOnly]);
|
|
1536
|
+
}, [withLineNumbers, readOnly, withSearch]);
|
|
1246
1537
|
const additionalButtons = renderAdditionalButtons?.(value);
|
|
1247
1538
|
const hasToolbar = withCopyButton && !!value || !!additionalButtons;
|
|
1248
1539
|
return (
|
|
@@ -1265,6 +1556,8 @@ var CodeEditor = ({
|
|
|
1265
1556
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1266
1557
|
CodeMirror__default.default,
|
|
1267
1558
|
{
|
|
1559
|
+
ref: editorRef,
|
|
1560
|
+
onCreateEditor: handleCreateEditor,
|
|
1268
1561
|
theme: customTheme,
|
|
1269
1562
|
value,
|
|
1270
1563
|
onChange: handleChange,
|
|
@@ -1587,112 +1880,6 @@ function highlightingExtension(queryParser) {
|
|
|
1587
1880
|
function updateHighlighting(view, lines) {
|
|
1588
1881
|
view.dispatch({ effects: setHighlightedLinesEffect.of(lines ?? null) });
|
|
1589
1882
|
}
|
|
1590
|
-
var setSearchEffect = state.StateEffect.define();
|
|
1591
|
-
function findMatches(doc, query) {
|
|
1592
|
-
if (!query) return [];
|
|
1593
|
-
const text = doc.toString();
|
|
1594
|
-
try {
|
|
1595
|
-
const regex = new RegExp(escapeStringRegexp(query), "gi");
|
|
1596
|
-
return Array.from(text.matchAll(regex)).map((match, index) => {
|
|
1597
|
-
const from = match.index;
|
|
1598
|
-
const to = from + match[0].length;
|
|
1599
|
-
return { from, to, text: match[0], localIndex: index };
|
|
1600
|
-
});
|
|
1601
|
-
} catch (e) {
|
|
1602
|
-
console.warn("Invalid search regex:", e);
|
|
1603
|
-
return [];
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
function createDecorations(matches, selectedLocalIndex) {
|
|
1607
|
-
const decorations = matches.map((match) => {
|
|
1608
|
-
const isSelected = match.localIndex === selectedLocalIndex;
|
|
1609
|
-
const decoration = view.Decoration.mark({
|
|
1610
|
-
class: isSelected ? "cm-searchMatch-selected" : "cm-searchMatch"
|
|
1611
|
-
});
|
|
1612
|
-
return decoration.range(match.from, match.to);
|
|
1613
|
-
});
|
|
1614
|
-
return view.Decoration.set(decorations, true);
|
|
1615
|
-
}
|
|
1616
|
-
var searchField = state.StateField.define({
|
|
1617
|
-
create() {
|
|
1618
|
-
return {
|
|
1619
|
-
query: "",
|
|
1620
|
-
selectedMatchIndex: void 0,
|
|
1621
|
-
matches: [],
|
|
1622
|
-
decorations: view.Decoration.none
|
|
1623
|
-
};
|
|
1624
|
-
},
|
|
1625
|
-
update(state, tr) {
|
|
1626
|
-
let newState = state;
|
|
1627
|
-
for (const effect of tr.effects) {
|
|
1628
|
-
if (!effect.is(setSearchEffect)) {
|
|
1629
|
-
continue;
|
|
1630
|
-
}
|
|
1631
|
-
const { query, selectedMatchIndex } = effect.value;
|
|
1632
|
-
const matches = findMatches(tr.state.doc, query);
|
|
1633
|
-
const decorations = createDecorations(matches, selectedMatchIndex);
|
|
1634
|
-
newState = {
|
|
1635
|
-
query,
|
|
1636
|
-
selectedMatchIndex,
|
|
1637
|
-
matches,
|
|
1638
|
-
decorations
|
|
1639
|
-
};
|
|
1640
|
-
}
|
|
1641
|
-
if (tr.docChanged && newState.query) {
|
|
1642
|
-
const matches = findMatches(tr.state.doc, newState.query);
|
|
1643
|
-
const decorations = createDecorations(matches, newState.selectedMatchIndex);
|
|
1644
|
-
newState = {
|
|
1645
|
-
...newState,
|
|
1646
|
-
matches,
|
|
1647
|
-
decorations
|
|
1648
|
-
};
|
|
1649
|
-
}
|
|
1650
|
-
return newState;
|
|
1651
|
-
},
|
|
1652
|
-
provide: (field) => view.EditorView.decorations.from(field, (state) => state.decorations)
|
|
1653
|
-
});
|
|
1654
|
-
var searchViewPlugin = view.ViewPlugin.fromClass(
|
|
1655
|
-
class {
|
|
1656
|
-
lastSelectedIndex;
|
|
1657
|
-
update(update) {
|
|
1658
|
-
const state = update.state.field(searchField);
|
|
1659
|
-
if (state.selectedMatchIndex !== void 0 && state.selectedMatchIndex !== this.lastSelectedIndex) {
|
|
1660
|
-
const match = state.matches[state.selectedMatchIndex];
|
|
1661
|
-
if (match) {
|
|
1662
|
-
requestAnimationFrame(() => {
|
|
1663
|
-
update.view.dispatch({
|
|
1664
|
-
effects: view.EditorView.scrollIntoView(match.from, { y: "center" })
|
|
1665
|
-
});
|
|
1666
|
-
});
|
|
1667
|
-
}
|
|
1668
|
-
this.lastSelectedIndex = state.selectedMatchIndex;
|
|
1669
|
-
}
|
|
1670
|
-
if (state.selectedMatchIndex === void 0) {
|
|
1671
|
-
this.lastSelectedIndex = void 0;
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
|
-
);
|
|
1676
|
-
var searchTheme = view.EditorView.baseTheme({
|
|
1677
|
-
".cm-searchMatch": {
|
|
1678
|
-
backgroundColor: colors__default.default.blue[100]
|
|
1679
|
-
},
|
|
1680
|
-
".cm-searchMatch > span": {
|
|
1681
|
-
color: `${colors__default.default.blue[600]} !important`
|
|
1682
|
-
},
|
|
1683
|
-
".cm-searchMatch-selected": {
|
|
1684
|
-
backgroundColor: colors__default.default.blue[600]
|
|
1685
|
-
},
|
|
1686
|
-
".cm-searchMatch-selected > span": {
|
|
1687
|
-
color: `${colors__default.default.white} !important`
|
|
1688
|
-
}
|
|
1689
|
-
});
|
|
1690
|
-
function searchExtension() {
|
|
1691
|
-
return [searchField, searchViewPlugin, searchTheme];
|
|
1692
|
-
}
|
|
1693
|
-
function updateSearch(view, query, selectedMatchIndex) {
|
|
1694
|
-
view.dispatch({ effects: setSearchEffect.of({ query, selectedMatchIndex }) });
|
|
1695
|
-
}
|
|
1696
1883
|
var OWN_KEYMAPS = {
|
|
1697
1884
|
defaultKeymap: false,
|
|
1698
1885
|
completionKeymap: false,
|
|
@@ -1758,6 +1945,7 @@ var SqlEditor = ({
|
|
|
1758
1945
|
dialect
|
|
1759
1946
|
}) => {
|
|
1760
1947
|
const editorRef = react.useRef(null);
|
|
1948
|
+
const tooltipLayer = useTooltipsExtension();
|
|
1761
1949
|
const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
|
|
1762
1950
|
const themeExtension = useThemedExtension(
|
|
1763
1951
|
"sql-editor:chrome",
|
|
@@ -1768,9 +1956,16 @@ var SqlEditor = ({
|
|
|
1768
1956
|
return [
|
|
1769
1957
|
CodeMirror.EditorView.lineWrapping,
|
|
1770
1958
|
CodeMirror.keymap.of(extraKeys ? [...extraKeys, ...baseKeymap] : baseKeymap),
|
|
1771
|
-
...codemirrorLangSql.installExtensions({
|
|
1959
|
+
...codemirrorLangSql.installExtensions({
|
|
1960
|
+
schema,
|
|
1961
|
+
defaultDatabase,
|
|
1962
|
+
defaultSchema,
|
|
1963
|
+
variableCompletion: completeVariables(variables),
|
|
1964
|
+
dialect
|
|
1965
|
+
}),
|
|
1772
1966
|
searchExtension(),
|
|
1773
1967
|
highlightingExtension(queryParser),
|
|
1968
|
+
tooltipLayer,
|
|
1774
1969
|
themeExtension,
|
|
1775
1970
|
onBlurEditor ? CodeMirror.EditorView.domEventHandlers({ blur: (_, view) => onBlurEditor(view) }) : [],
|
|
1776
1971
|
onFocusEditor ? CodeMirror.EditorView.domEventHandlers({ focus: (_, view) => onFocusEditor(view) }) : []
|
|
@@ -1785,7 +1980,8 @@ var SqlEditor = ({
|
|
|
1785
1980
|
dialect,
|
|
1786
1981
|
onBlurEditor,
|
|
1787
1982
|
onFocusEditor,
|
|
1788
|
-
themeExtension
|
|
1983
|
+
themeExtension,
|
|
1984
|
+
tooltipLayer
|
|
1789
1985
|
]);
|
|
1790
1986
|
const defaultSetup = react.useMemo(() => {
|
|
1791
1987
|
return { ...buildBasicSetup(readOnly), ...OWN_KEYMAPS, lineNumbers };
|