@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/rjsf.cjs
CHANGED
|
@@ -28,6 +28,7 @@ var codemirrorThemeGithub = require('@uiw/codemirror-theme-github');
|
|
|
28
28
|
var codemirrorLangSfsql = require('@keboola/codemirror-lang-sfsql');
|
|
29
29
|
var colors = require('@keboola/tailwind-config/colors');
|
|
30
30
|
var simpleMode = require('@codemirror/legacy-modes/mode/simple-mode');
|
|
31
|
+
var state = require('@codemirror/state');
|
|
31
32
|
var DOMPurify = require('dompurify');
|
|
32
33
|
var reactCollapsible = require('@radix-ui/react-collapsible');
|
|
33
34
|
var RadixTabs = require('@radix-ui/react-tabs');
|
|
@@ -386,6 +387,9 @@ Tooltip.Trigger = TooltipTrigger;
|
|
|
386
387
|
// src/utils/createPrefixedString.ts
|
|
387
388
|
var createPrefixedString = (prefix2) => (literals) => literals.reduce((acc, literal) => acc + literal, `${prefix2}-`);
|
|
388
389
|
|
|
390
|
+
// src/utils/escapeStringRegexp.ts
|
|
391
|
+
var escapeStringRegexp = (string) => string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
|
|
392
|
+
|
|
389
393
|
// src/utils/mergeRefs.ts
|
|
390
394
|
function setRef(ref, value) {
|
|
391
395
|
if (typeof ref === "function") {
|
|
@@ -397,6 +401,21 @@ function setRef(ref, value) {
|
|
|
397
401
|
var mergeRefs = (...refs) => {
|
|
398
402
|
return (node) => refs.forEach((ref) => setRef(ref, node));
|
|
399
403
|
};
|
|
404
|
+
|
|
405
|
+
// src/utils/isMac.ts
|
|
406
|
+
var getIsMac = () => {
|
|
407
|
+
if (typeof navigator !== "undefined" && "userAgentData" in navigator) {
|
|
408
|
+
const platform = navigator.userAgentData.platform;
|
|
409
|
+
if (typeof platform === "string") {
|
|
410
|
+
return platform.toLowerCase() === "macos";
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (typeof navigator !== "undefined" && typeof navigator.platform === "string") {
|
|
414
|
+
return navigator.platform.toUpperCase().indexOf("MAC") >= 0;
|
|
415
|
+
}
|
|
416
|
+
return false;
|
|
417
|
+
};
|
|
418
|
+
var isMac = getIsMac();
|
|
400
419
|
var helpVariants = classVarianceAuthority.cva(["tw:m-0", "tw:text-xs"], {
|
|
401
420
|
defaultVariants: {
|
|
402
421
|
state: "default"
|
|
@@ -847,8 +866,6 @@ var ButtonToolbar = ({ value, children }) => {
|
|
|
847
866
|
};
|
|
848
867
|
var COMMANDS = [
|
|
849
868
|
"run-operation",
|
|
850
|
-
"source freshness",
|
|
851
|
-
"docs generate",
|
|
852
869
|
"run",
|
|
853
870
|
"test",
|
|
854
871
|
"seed",
|
|
@@ -857,9 +874,13 @@ var COMMANDS = [
|
|
|
857
874
|
"ls",
|
|
858
875
|
"compile",
|
|
859
876
|
"build",
|
|
860
|
-
"deps"
|
|
877
|
+
"deps",
|
|
878
|
+
"docs",
|
|
879
|
+
"source"
|
|
861
880
|
];
|
|
881
|
+
var SUBCOMMANDS = { docs: ["generate"], source: ["freshness"] };
|
|
862
882
|
var ARGUMENTS = ["--select", "--exclude", "--selector", "--defer", "--resource-type", "-s"];
|
|
883
|
+
var SELECTORS = ["--select", "--exclude", "-s"];
|
|
863
884
|
var METHODS = [
|
|
864
885
|
"path:",
|
|
865
886
|
"source:",
|
|
@@ -886,13 +907,59 @@ var FLAGS = [
|
|
|
886
907
|
"--profile",
|
|
887
908
|
"--full-refresh"
|
|
888
909
|
];
|
|
889
|
-
var
|
|
890
|
-
|
|
910
|
+
var COMMAND_PHRASES = COMMANDS.flatMap((command) => {
|
|
911
|
+
const subcommands = SUBCOMMANDS[command];
|
|
912
|
+
return subcommands ? subcommands.map((subcommand) => `${command} ${subcommand}`) : [command];
|
|
913
|
+
});
|
|
914
|
+
var alternation = (list) => [...list].sort((a, b) => b.length - a.length).join("|");
|
|
915
|
+
var word = (list) => new RegExp(`^\\s+(?:${alternation(list)})\\b`, "i");
|
|
916
|
+
var prefix = (list) => new RegExp(`^\\s+(?:${alternation(list)})`, "i");
|
|
917
|
+
var WORD = /[\w:-]*$/;
|
|
918
|
+
var asOptions = (list, type) => list.map((label) => ({ label, type }));
|
|
919
|
+
var DBT = [{ label: "dbt", type: "keyword" }];
|
|
920
|
+
var COMMAND_OPTIONS = asOptions(COMMANDS, "keyword");
|
|
921
|
+
var SUBCOMMAND_OPTIONS = Object.fromEntries(
|
|
922
|
+
Object.entries(SUBCOMMANDS).map(([command, subcommands]) => [
|
|
923
|
+
command,
|
|
924
|
+
asOptions(subcommands, "keyword")
|
|
925
|
+
])
|
|
926
|
+
);
|
|
927
|
+
var ARGUMENT_OPTIONS = asOptions(ARGUMENTS, "variable");
|
|
928
|
+
var FLAG_OPTIONS = asOptions(FLAGS, "constant");
|
|
929
|
+
var METHOD_OPTIONS = asOptions(METHODS, "property");
|
|
930
|
+
var optionsAfter = (words) => {
|
|
931
|
+
const [step, command, ...rest] = words;
|
|
932
|
+
if (step === void 0) return DBT;
|
|
933
|
+
if (step.toLowerCase() !== "dbt") return [];
|
|
934
|
+
if (command === void 0) return COMMAND_OPTIONS;
|
|
935
|
+
const subcommands = SUBCOMMAND_OPTIONS[command.toLowerCase()];
|
|
936
|
+
if (subcommands && rest.length === 0) return subcommands;
|
|
937
|
+
const lastArgument = rest.filter((it) => it.startsWith("-")).at(-1);
|
|
938
|
+
const selecting = lastArgument !== void 0 && SELECTORS.includes(lastArgument.toLowerCase());
|
|
939
|
+
return selecting ? [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS, ...METHOD_OPTIONS] : [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS];
|
|
940
|
+
};
|
|
941
|
+
var complete = (context) => {
|
|
942
|
+
const typed = context.matchBefore(WORD);
|
|
943
|
+
if (!typed?.text && !context.explicit) return null;
|
|
944
|
+
const from = typed?.from ?? context.pos;
|
|
945
|
+
const line = context.state.doc.lineAt(from);
|
|
946
|
+
const options = optionsAfter(
|
|
947
|
+
line.text.slice(0, from - line.from).split(/\s+/).filter(Boolean)
|
|
948
|
+
);
|
|
949
|
+
return options.length > 0 ? { from, options, validFor: WORD } : null;
|
|
950
|
+
};
|
|
891
951
|
var dbt = simpleMode.simpleMode({
|
|
952
|
+
languageData: {
|
|
953
|
+
// `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
|
|
954
|
+
commentTokens: { line: "--", block: { open: "/*", close: "*/" } },
|
|
955
|
+
autocomplete: complete
|
|
956
|
+
},
|
|
892
957
|
start: [
|
|
893
958
|
{ regex: /"(?:[^\\]|\\.)*?(?:"|$)/, token: "string" },
|
|
894
|
-
|
|
895
|
-
|
|
959
|
+
// Word-bounded, so `dbtX` is not a dbt step whose first word happens to
|
|
960
|
+
// colour — the same thing the completion source asks of it.
|
|
961
|
+
{ regex: /dbt\b/, token: "keyword", sol: true },
|
|
962
|
+
{ regex: word(COMMAND_PHRASES), token: "keyword" },
|
|
896
963
|
{ regex: word(ARGUMENTS), token: "variableName" },
|
|
897
964
|
{ regex: prefix(METHODS), token: "propertyName" },
|
|
898
965
|
{ regex: prefix(FLAGS), token: "attributeName" },
|
|
@@ -940,6 +1007,8 @@ var KEYWORDS = {
|
|
|
940
1007
|
};
|
|
941
1008
|
var jsonnet = {
|
|
942
1009
|
name: "jsonnet",
|
|
1010
|
+
// `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
|
|
1011
|
+
languageData: { commentTokens: { line: "//", block: { open: "/*", close: "*/" } } },
|
|
943
1012
|
startState: () => ({
|
|
944
1013
|
cComment: false,
|
|
945
1014
|
textBlock: false,
|
|
@@ -1156,6 +1225,20 @@ var buildCustomTheme = () => codemirrorThemeGithub.githubLightInit({
|
|
|
1156
1225
|
selection: resolveToken("primary", "31 143 255")
|
|
1157
1226
|
}
|
|
1158
1227
|
});
|
|
1228
|
+
var sfsqlWithLanguageData = {
|
|
1229
|
+
...codemirrorLangSfsql.sfsql,
|
|
1230
|
+
languageData: {
|
|
1231
|
+
...codemirrorLangSfsql.sfsql.languageData,
|
|
1232
|
+
// `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
|
|
1233
|
+
commentTokens: { line: "--", block: { open: "/*", close: "*/" } },
|
|
1234
|
+
autocomplete: autocomplete.completeFromList(
|
|
1235
|
+
Object.keys(codemirrorLangSfsql.modeSpec.keywords).map((label) => ({
|
|
1236
|
+
label: label.toUpperCase(),
|
|
1237
|
+
type: "keyword"
|
|
1238
|
+
}))
|
|
1239
|
+
)
|
|
1240
|
+
}
|
|
1241
|
+
};
|
|
1159
1242
|
var getLanguageMode = (mode) => {
|
|
1160
1243
|
switch (mode) {
|
|
1161
1244
|
case void 0:
|
|
@@ -1172,7 +1255,7 @@ var getLanguageMode = (mode) => {
|
|
|
1172
1255
|
case "text/x-mssql":
|
|
1173
1256
|
return langSql.sql({ upperCaseKeywords: true, dialect: langSql.MSSQL });
|
|
1174
1257
|
case "text/x-sfsql":
|
|
1175
|
-
return language.StreamLanguage.define(
|
|
1258
|
+
return language.StreamLanguage.define(sfsqlWithLanguageData);
|
|
1176
1259
|
case "text/x-plsql":
|
|
1177
1260
|
return langSql.sql({ upperCaseKeywords: true, dialect: langSql.PLSQL });
|
|
1178
1261
|
case "text/x-rsrc":
|
|
@@ -1197,6 +1280,112 @@ var getLanguageMode = (mode) => {
|
|
|
1197
1280
|
}
|
|
1198
1281
|
};
|
|
1199
1282
|
var shouldLintJson = (mode, readOnly) => mode === "application/json" && !readOnly;
|
|
1283
|
+
var setSearchEffect = state.StateEffect.define();
|
|
1284
|
+
function findMatches(doc, query) {
|
|
1285
|
+
if (!query) return [];
|
|
1286
|
+
const text = doc.toString();
|
|
1287
|
+
try {
|
|
1288
|
+
const regex = new RegExp(escapeStringRegexp(query), "gi");
|
|
1289
|
+
return Array.from(text.matchAll(regex)).map((match2, index) => {
|
|
1290
|
+
const from = match2.index;
|
|
1291
|
+
const to = from + match2[0].length;
|
|
1292
|
+
return { from, to, text: match2[0], localIndex: index };
|
|
1293
|
+
});
|
|
1294
|
+
} catch (e) {
|
|
1295
|
+
console.warn("Invalid search regex:", e);
|
|
1296
|
+
return [];
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
function createDecorations(matches, selectedLocalIndex) {
|
|
1300
|
+
const decorations = matches.map((match2) => {
|
|
1301
|
+
const isSelected = match2.localIndex === selectedLocalIndex;
|
|
1302
|
+
const decoration = view.Decoration.mark({
|
|
1303
|
+
class: isSelected ? "cm-searchMatch-selected" : "cm-searchMatch"
|
|
1304
|
+
});
|
|
1305
|
+
return decoration.range(match2.from, match2.to);
|
|
1306
|
+
});
|
|
1307
|
+
return view.Decoration.set(decorations, true);
|
|
1308
|
+
}
|
|
1309
|
+
var searchField = state.StateField.define({
|
|
1310
|
+
create() {
|
|
1311
|
+
return {
|
|
1312
|
+
query: "",
|
|
1313
|
+
selectedMatchIndex: void 0,
|
|
1314
|
+
matches: [],
|
|
1315
|
+
decorations: view.Decoration.none
|
|
1316
|
+
};
|
|
1317
|
+
},
|
|
1318
|
+
update(state, tr) {
|
|
1319
|
+
let newState = state;
|
|
1320
|
+
for (const effect of tr.effects) {
|
|
1321
|
+
if (!effect.is(setSearchEffect)) {
|
|
1322
|
+
continue;
|
|
1323
|
+
}
|
|
1324
|
+
const { query, selectedMatchIndex } = effect.value;
|
|
1325
|
+
const matches = findMatches(tr.state.doc, query);
|
|
1326
|
+
const decorations = createDecorations(matches, selectedMatchIndex);
|
|
1327
|
+
newState = {
|
|
1328
|
+
query,
|
|
1329
|
+
selectedMatchIndex,
|
|
1330
|
+
matches,
|
|
1331
|
+
decorations
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
if (tr.docChanged && newState.query) {
|
|
1335
|
+
const matches = findMatches(tr.state.doc, newState.query);
|
|
1336
|
+
const decorations = createDecorations(matches, newState.selectedMatchIndex);
|
|
1337
|
+
newState = {
|
|
1338
|
+
...newState,
|
|
1339
|
+
matches,
|
|
1340
|
+
decorations
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
return newState;
|
|
1344
|
+
},
|
|
1345
|
+
provide: (field) => view.EditorView.decorations.from(field, (state) => state.decorations)
|
|
1346
|
+
});
|
|
1347
|
+
var searchViewPlugin = view.ViewPlugin.fromClass(
|
|
1348
|
+
class {
|
|
1349
|
+
lastSelectedIndex;
|
|
1350
|
+
update(update) {
|
|
1351
|
+
const state = update.state.field(searchField);
|
|
1352
|
+
if (state.selectedMatchIndex !== void 0 && state.selectedMatchIndex !== this.lastSelectedIndex) {
|
|
1353
|
+
const match2 = state.matches[state.selectedMatchIndex];
|
|
1354
|
+
if (match2) {
|
|
1355
|
+
requestAnimationFrame(() => {
|
|
1356
|
+
update.view.dispatch({
|
|
1357
|
+
effects: view.EditorView.scrollIntoView(match2.from, { y: "center" })
|
|
1358
|
+
});
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
this.lastSelectedIndex = state.selectedMatchIndex;
|
|
1362
|
+
}
|
|
1363
|
+
if (state.selectedMatchIndex === void 0) {
|
|
1364
|
+
this.lastSelectedIndex = void 0;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
);
|
|
1369
|
+
var searchTheme = view.EditorView.baseTheme({
|
|
1370
|
+
".cm-searchMatch": {
|
|
1371
|
+
backgroundColor: colors__default.default.blue[100]
|
|
1372
|
+
},
|
|
1373
|
+
".cm-searchMatch > span": {
|
|
1374
|
+
color: `${colors__default.default.blue[600]} !important`
|
|
1375
|
+
},
|
|
1376
|
+
".cm-searchMatch-selected": {
|
|
1377
|
+
backgroundColor: colors__default.default.blue[600]
|
|
1378
|
+
},
|
|
1379
|
+
".cm-searchMatch-selected > span": {
|
|
1380
|
+
color: `${colors__default.default.white} !important`
|
|
1381
|
+
}
|
|
1382
|
+
});
|
|
1383
|
+
function searchExtension() {
|
|
1384
|
+
return [searchField, searchViewPlugin, searchTheme];
|
|
1385
|
+
}
|
|
1386
|
+
function updateSearch(view, query, selectedMatchIndex) {
|
|
1387
|
+
view.dispatch({ effects: setSearchEffect.of({ query, selectedMatchIndex }) });
|
|
1388
|
+
}
|
|
1200
1389
|
var KbdSeparator = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("span", { ...props, className: cn("tw:text-xs tw:text-muted-foreground", className) });
|
|
1201
1390
|
var KbdGroup = ({ ref, className, children, separator, ...props }) => {
|
|
1202
1391
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1256,11 +1445,78 @@ Kbd.Group = KbdGroup;
|
|
|
1256
1445
|
Kbd.Separator = KbdSeparator;
|
|
1257
1446
|
var ToggleComponentHelp = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1258
1447
|
"Use ",
|
|
1259
|
-
/* @__PURE__ */ jsxRuntime.jsx(Kbd, { children: "Ctrl+/" }),
|
|
1260
|
-
" or ",
|
|
1261
|
-
/* @__PURE__ */ jsxRuntime.jsx(Kbd, { children: "Command+/" }),
|
|
1448
|
+
/* @__PURE__ */ jsxRuntime.jsx(Kbd, { children: isMac ? "Command+/" : "Ctrl+/" }),
|
|
1262
1449
|
" to toggle comments."
|
|
1263
1450
|
] });
|
|
1451
|
+
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);
|
|
1452
|
+
var crops = (style) => style.overflowX !== "visible" || style.overflowY !== "visible" || style.maskImage !== "none" || style.contentVisibility !== "visible" || /\b(paint|strict|content)\b/.test(style.contain);
|
|
1453
|
+
var findTooltipHost = (from) => {
|
|
1454
|
+
let outermostCropper = null;
|
|
1455
|
+
for (let node = from.parentElement; node && node !== document.body; node = node.parentElement) {
|
|
1456
|
+
const style = getComputedStyle(node);
|
|
1457
|
+
if (crops(style)) {
|
|
1458
|
+
outermostCropper = node;
|
|
1459
|
+
} else if (establishesFixedContainingBlock(style)) {
|
|
1460
|
+
return outermostCropper?.parentElement ?? node;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
return outermostCropper?.parentElement ?? null;
|
|
1464
|
+
};
|
|
1465
|
+
var tooltipsExtension = () => {
|
|
1466
|
+
const layer = new state.Compartment();
|
|
1467
|
+
return [
|
|
1468
|
+
layer.of(view.tooltips()),
|
|
1469
|
+
view.ViewPlugin.define((view$1) => {
|
|
1470
|
+
const scheduled = setTimeout(() => {
|
|
1471
|
+
if (!view$1.dom.isConnected) return;
|
|
1472
|
+
const parent = findTooltipHost(view$1.dom);
|
|
1473
|
+
if (parent) view$1.dispatch({ effects: layer.reconfigure(view.tooltips({ parent })) });
|
|
1474
|
+
});
|
|
1475
|
+
return { destroy: () => clearTimeout(scheduled) };
|
|
1476
|
+
})
|
|
1477
|
+
];
|
|
1478
|
+
};
|
|
1479
|
+
var useTooltipsExtension = () => React26.useMemo(tooltipsExtension, []);
|
|
1480
|
+
|
|
1481
|
+
// src/components/CodeEditor/variableCompletion.ts
|
|
1482
|
+
var BOOST = 2e3;
|
|
1483
|
+
var NAME = String.raw`[\w-]*`;
|
|
1484
|
+
var AT_CARET = new RegExp(String.raw`(?:\{{1,2} ?)?${NAME}$`);
|
|
1485
|
+
var NAME_AT_END = new RegExp(`${NAME}$`);
|
|
1486
|
+
var OPENING = /\{{1,2} ?$/;
|
|
1487
|
+
var CLOSING = /^ ?\}{1,2}/;
|
|
1488
|
+
var completeVariables = (variables = []) => {
|
|
1489
|
+
if (variables.length === 0) return () => null;
|
|
1490
|
+
const options = variables.map(({ name, value }) => ({
|
|
1491
|
+
// The bare name: `SqlEditor` filters prefix-only while `CodeEditor` filters
|
|
1492
|
+
// fuzzily, and this is the only spelling both accept whether or not the caret
|
|
1493
|
+
// has typed the braces. The braces are `displayLabel`, which is what renders.
|
|
1494
|
+
label: name,
|
|
1495
|
+
displayLabel: `{{${name}}}`,
|
|
1496
|
+
detail: value,
|
|
1497
|
+
type: "variable",
|
|
1498
|
+
boost: BOOST,
|
|
1499
|
+
apply: (view, completion, from, to) => {
|
|
1500
|
+
const { doc } = view.state;
|
|
1501
|
+
const line = doc.lineAt(from);
|
|
1502
|
+
const insert = `{{${completion.label}}}`;
|
|
1503
|
+
const opening = OPENING.exec(doc.sliceString(line.from, from));
|
|
1504
|
+
const closing = CLOSING.exec(doc.sliceString(to, line.to));
|
|
1505
|
+
const start = opening ? from - opening[0].length : from;
|
|
1506
|
+
const end = closing ? to + closing[0].length : to;
|
|
1507
|
+
view.dispatch({
|
|
1508
|
+
changes: { from: start, to: end, insert },
|
|
1509
|
+
selection: { anchor: start + insert.length }
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1512
|
+
}));
|
|
1513
|
+
return (context) => {
|
|
1514
|
+
const match2 = context.matchBefore(AT_CARET);
|
|
1515
|
+
if (!match2?.text) return null;
|
|
1516
|
+
const [name = ""] = NAME_AT_END.exec(match2.text) ?? [];
|
|
1517
|
+
return { from: match2.to - name.length, options };
|
|
1518
|
+
};
|
|
1519
|
+
};
|
|
1264
1520
|
var emptyArray = [];
|
|
1265
1521
|
var emptyObject = {};
|
|
1266
1522
|
var CodeEditor = ({
|
|
@@ -1270,8 +1526,12 @@ var CodeEditor = ({
|
|
|
1270
1526
|
mode = "application/json",
|
|
1271
1527
|
placeholder = "",
|
|
1272
1528
|
ariaLabel,
|
|
1529
|
+
searchQuery,
|
|
1530
|
+
searchMatchIndex,
|
|
1273
1531
|
readOnly = false,
|
|
1274
1532
|
autocompletions = emptyArray,
|
|
1533
|
+
completionSource,
|
|
1534
|
+
variables,
|
|
1275
1535
|
extraKeys = emptyObject,
|
|
1276
1536
|
withToggleCommentHint = false,
|
|
1277
1537
|
withAutofocus = false,
|
|
@@ -1286,6 +1546,26 @@ var CodeEditor = ({
|
|
|
1286
1546
|
className
|
|
1287
1547
|
}) => {
|
|
1288
1548
|
const handleChange = useStableCallback((next) => onChange?.(next));
|
|
1549
|
+
const withSearch = searchQuery !== void 0;
|
|
1550
|
+
const editorRef = React26.useRef(null);
|
|
1551
|
+
React26.useEffect(() => {
|
|
1552
|
+
const view = editorRef.current?.view;
|
|
1553
|
+
if (view && withSearch) updateSearch(view, searchQuery, searchMatchIndex);
|
|
1554
|
+
}, [withSearch, searchQuery, searchMatchIndex]);
|
|
1555
|
+
const handleCreateEditor = useStableCallback((view) => {
|
|
1556
|
+
if (searchQuery) updateSearch(view, searchQuery, searchMatchIndex);
|
|
1557
|
+
});
|
|
1558
|
+
const extraKeysRef = React26.useRef(extraKeys);
|
|
1559
|
+
React26.useLayoutEffect(() => {
|
|
1560
|
+
extraKeysRef.current = extraKeys;
|
|
1561
|
+
});
|
|
1562
|
+
const boundKeysSignature = Object.keys(extraKeys).join("\n");
|
|
1563
|
+
const boundKeys = React26.useMemo(
|
|
1564
|
+
() => boundKeysSignature.split("\n").filter(Boolean),
|
|
1565
|
+
[boundKeysSignature]
|
|
1566
|
+
);
|
|
1567
|
+
const tooltipLayer = useTooltipsExtension();
|
|
1568
|
+
const variableCompletion = React26.useMemo(() => completeVariables(variables), [variables]);
|
|
1289
1569
|
const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
|
|
1290
1570
|
const baseTheme = useThemedExtension(
|
|
1291
1571
|
"code-editor:chrome",
|
|
@@ -1297,31 +1577,43 @@ var CodeEditor = ({
|
|
|
1297
1577
|
shouldLintJson(mode, readOnly) ? lint.linter(langJson.jsonParseLinter()) : [],
|
|
1298
1578
|
withLineWrapping ? view.EditorView.lineWrapping : [],
|
|
1299
1579
|
CodeMirror.EditorState.languageData.of(() => [
|
|
1300
|
-
{ autocomplete: completeAny ? autocomplete.completeAnyWord : autocompletions }
|
|
1580
|
+
{ autocomplete: completionSource ?? (completeAny ? autocomplete.completeAnyWord : autocompletions) }
|
|
1301
1581
|
]),
|
|
1582
|
+
CodeMirror.EditorState.languageData.of(() => [{ autocomplete: variableCompletion }]),
|
|
1302
1583
|
view.keymap.of(
|
|
1303
|
-
|
|
1584
|
+
boundKeys.map((key) => ({
|
|
1304
1585
|
key,
|
|
1305
1586
|
run: () => {
|
|
1306
|
-
|
|
1307
|
-
run();
|
|
1587
|
+
extraKeysRef.current[key]?.();
|
|
1308
1588
|
return true;
|
|
1309
1589
|
}
|
|
1310
1590
|
}))
|
|
1311
1591
|
),
|
|
1312
|
-
readOnly ? [] :
|
|
1592
|
+
readOnly ? [] : [
|
|
1593
|
+
// CodeMirror's own default. Gating it on the props hid completions the
|
|
1594
|
+
// *language* supplies — dbt's vocabulary, Snowflake's keywords — behind
|
|
1595
|
+
// a shortcut, and macOS leaves no usable one. With nothing to offer, no
|
|
1596
|
+
// popup opens anyway.
|
|
1597
|
+
autocomplete.autocompletion()
|
|
1598
|
+
],
|
|
1313
1599
|
ariaLabel ? view.EditorView.contentAttributes.of({ "aria-label": ariaLabel }) : [],
|
|
1600
|
+
withSearch ? searchExtension() : [],
|
|
1601
|
+
tooltipLayer,
|
|
1314
1602
|
baseTheme
|
|
1315
1603
|
];
|
|
1316
1604
|
}, [
|
|
1317
1605
|
autocompletions,
|
|
1606
|
+
completionSource,
|
|
1607
|
+
variableCompletion,
|
|
1318
1608
|
completeAny,
|
|
1319
|
-
|
|
1609
|
+
boundKeys,
|
|
1320
1610
|
mode,
|
|
1321
1611
|
readOnly,
|
|
1322
1612
|
withLineWrapping,
|
|
1323
1613
|
baseTheme,
|
|
1324
|
-
ariaLabel
|
|
1614
|
+
ariaLabel,
|
|
1615
|
+
withSearch,
|
|
1616
|
+
tooltipLayer
|
|
1325
1617
|
]);
|
|
1326
1618
|
const extensions = React26.useMemo(() => {
|
|
1327
1619
|
return [
|
|
@@ -1340,9 +1632,12 @@ var CodeEditor = ({
|
|
|
1340
1632
|
const config = React26.useMemo(() => {
|
|
1341
1633
|
return {
|
|
1342
1634
|
...buildBasicSetup(readOnly),
|
|
1343
|
-
lineNumbers: withLineNumbers
|
|
1635
|
+
lineNumbers: withLineNumbers,
|
|
1636
|
+
// Mod-f opens CodeMirror's own panel, which would run a second query and a
|
|
1637
|
+
// second match count over the same document beside the caller's input.
|
|
1638
|
+
...withSearch ? { searchKeymap: false } : null
|
|
1344
1639
|
};
|
|
1345
|
-
}, [withLineNumbers, readOnly]);
|
|
1640
|
+
}, [withLineNumbers, readOnly, withSearch]);
|
|
1346
1641
|
const additionalButtons = renderAdditionalButtons?.(value);
|
|
1347
1642
|
const hasToolbar = withCopyButton && !!value || !!additionalButtons;
|
|
1348
1643
|
return (
|
|
@@ -1365,6 +1660,8 @@ var CodeEditor = ({
|
|
|
1365
1660
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1366
1661
|
CodeMirror__default.default,
|
|
1367
1662
|
{
|
|
1663
|
+
ref: editorRef,
|
|
1664
|
+
onCreateEditor: handleCreateEditor,
|
|
1368
1665
|
theme: customTheme,
|
|
1369
1666
|
value,
|
|
1370
1667
|
onChange: handleChange,
|