@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/rjsf.cjs
CHANGED
|
@@ -25,9 +25,10 @@ var r = require('@codemirror/legacy-modes/mode/r');
|
|
|
25
25
|
var shell = require('@codemirror/legacy-modes/mode/shell');
|
|
26
26
|
var toml = require('@codemirror/legacy-modes/mode/toml');
|
|
27
27
|
var codemirrorThemeGithub = require('@uiw/codemirror-theme-github');
|
|
28
|
-
var
|
|
28
|
+
var codemirrorLangSql = require('@keboola/codemirror-lang-sql');
|
|
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');
|
|
@@ -37,6 +38,7 @@ var TextareaAutosize = require('react-textarea-autosize');
|
|
|
37
38
|
var reactCheckbox = require('@radix-ui/react-checkbox');
|
|
38
39
|
var reactPopover = require('@radix-ui/react-popover');
|
|
39
40
|
var combobox = require('@base-ui/react/combobox');
|
|
41
|
+
var reactVirtual = require('@tanstack/react-virtual');
|
|
40
42
|
var RRadioGroup = require('@radix-ui/react-radio-group');
|
|
41
43
|
var RSeparator = require('@radix-ui/react-separator');
|
|
42
44
|
|
|
@@ -386,6 +388,9 @@ Tooltip.Trigger = TooltipTrigger;
|
|
|
386
388
|
// src/utils/createPrefixedString.ts
|
|
387
389
|
var createPrefixedString = (prefix2) => (literals) => literals.reduce((acc, literal) => acc + literal, `${prefix2}-`);
|
|
388
390
|
|
|
391
|
+
// src/utils/escapeStringRegexp.ts
|
|
392
|
+
var escapeStringRegexp = (string) => string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
|
|
393
|
+
|
|
389
394
|
// src/utils/mergeRefs.ts
|
|
390
395
|
function setRef(ref, value) {
|
|
391
396
|
if (typeof ref === "function") {
|
|
@@ -397,6 +402,21 @@ function setRef(ref, value) {
|
|
|
397
402
|
var mergeRefs = (...refs) => {
|
|
398
403
|
return (node) => refs.forEach((ref) => setRef(ref, node));
|
|
399
404
|
};
|
|
405
|
+
|
|
406
|
+
// src/utils/isMac.ts
|
|
407
|
+
var getIsMac = () => {
|
|
408
|
+
if (typeof navigator !== "undefined" && "userAgentData" in navigator) {
|
|
409
|
+
const platform = navigator.userAgentData.platform;
|
|
410
|
+
if (typeof platform === "string") {
|
|
411
|
+
return platform.toLowerCase() === "macos";
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (typeof navigator !== "undefined" && typeof navigator.platform === "string") {
|
|
415
|
+
return navigator.platform.toUpperCase().indexOf("MAC") >= 0;
|
|
416
|
+
}
|
|
417
|
+
return false;
|
|
418
|
+
};
|
|
419
|
+
var isMac = getIsMac();
|
|
400
420
|
var helpVariants = classVarianceAuthority.cva(["tw:m-0", "tw:text-xs"], {
|
|
401
421
|
defaultVariants: {
|
|
402
422
|
state: "default"
|
|
@@ -847,8 +867,6 @@ var ButtonToolbar = ({ value, children }) => {
|
|
|
847
867
|
};
|
|
848
868
|
var COMMANDS = [
|
|
849
869
|
"run-operation",
|
|
850
|
-
"source freshness",
|
|
851
|
-
"docs generate",
|
|
852
870
|
"run",
|
|
853
871
|
"test",
|
|
854
872
|
"seed",
|
|
@@ -857,9 +875,13 @@ var COMMANDS = [
|
|
|
857
875
|
"ls",
|
|
858
876
|
"compile",
|
|
859
877
|
"build",
|
|
860
|
-
"deps"
|
|
878
|
+
"deps",
|
|
879
|
+
"docs",
|
|
880
|
+
"source"
|
|
861
881
|
];
|
|
882
|
+
var SUBCOMMANDS = { docs: ["generate"], source: ["freshness"] };
|
|
862
883
|
var ARGUMENTS = ["--select", "--exclude", "--selector", "--defer", "--resource-type", "-s"];
|
|
884
|
+
var SELECTORS = ["--select", "--exclude", "-s"];
|
|
863
885
|
var METHODS = [
|
|
864
886
|
"path:",
|
|
865
887
|
"source:",
|
|
@@ -886,13 +908,59 @@ var FLAGS = [
|
|
|
886
908
|
"--profile",
|
|
887
909
|
"--full-refresh"
|
|
888
910
|
];
|
|
889
|
-
var
|
|
890
|
-
|
|
911
|
+
var COMMAND_PHRASES = COMMANDS.flatMap((command) => {
|
|
912
|
+
const subcommands = SUBCOMMANDS[command];
|
|
913
|
+
return subcommands ? subcommands.map((subcommand) => `${command} ${subcommand}`) : [command];
|
|
914
|
+
});
|
|
915
|
+
var alternation = (list) => [...list].sort((a, b) => b.length - a.length).join("|");
|
|
916
|
+
var word = (list) => new RegExp(`^\\s+(?:${alternation(list)})\\b`, "i");
|
|
917
|
+
var prefix = (list) => new RegExp(`^\\s+(?:${alternation(list)})`, "i");
|
|
918
|
+
var WORD = /[\w:-]*$/;
|
|
919
|
+
var asOptions = (list, type) => list.map((label) => ({ label, type }));
|
|
920
|
+
var DBT = [{ label: "dbt", type: "keyword" }];
|
|
921
|
+
var COMMAND_OPTIONS = asOptions(COMMANDS, "keyword");
|
|
922
|
+
var SUBCOMMAND_OPTIONS = Object.fromEntries(
|
|
923
|
+
Object.entries(SUBCOMMANDS).map(([command, subcommands]) => [
|
|
924
|
+
command,
|
|
925
|
+
asOptions(subcommands, "keyword")
|
|
926
|
+
])
|
|
927
|
+
);
|
|
928
|
+
var ARGUMENT_OPTIONS = asOptions(ARGUMENTS, "variable");
|
|
929
|
+
var FLAG_OPTIONS = asOptions(FLAGS, "constant");
|
|
930
|
+
var METHOD_OPTIONS = asOptions(METHODS, "property");
|
|
931
|
+
var optionsAfter = (words) => {
|
|
932
|
+
const [step, command, ...rest] = words;
|
|
933
|
+
if (step === void 0) return DBT;
|
|
934
|
+
if (step.toLowerCase() !== "dbt") return [];
|
|
935
|
+
if (command === void 0) return COMMAND_OPTIONS;
|
|
936
|
+
const subcommands = SUBCOMMAND_OPTIONS[command.toLowerCase()];
|
|
937
|
+
if (subcommands && rest.length === 0) return subcommands;
|
|
938
|
+
const lastArgument = rest.filter((it) => it.startsWith("-")).at(-1);
|
|
939
|
+
const selecting = lastArgument !== void 0 && SELECTORS.includes(lastArgument.toLowerCase());
|
|
940
|
+
return selecting ? [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS, ...METHOD_OPTIONS] : [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS];
|
|
941
|
+
};
|
|
942
|
+
var complete = (context) => {
|
|
943
|
+
const typed = context.matchBefore(WORD);
|
|
944
|
+
if (!typed?.text && !context.explicit) return null;
|
|
945
|
+
const from = typed?.from ?? context.pos;
|
|
946
|
+
const line = context.state.doc.lineAt(from);
|
|
947
|
+
const options = optionsAfter(
|
|
948
|
+
line.text.slice(0, from - line.from).split(/\s+/).filter(Boolean)
|
|
949
|
+
);
|
|
950
|
+
return options.length > 0 ? { from, options, validFor: WORD } : null;
|
|
951
|
+
};
|
|
891
952
|
var dbt = simpleMode.simpleMode({
|
|
953
|
+
languageData: {
|
|
954
|
+
// `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
|
|
955
|
+
commentTokens: { line: "--", block: { open: "/*", close: "*/" } },
|
|
956
|
+
autocomplete: complete
|
|
957
|
+
},
|
|
892
958
|
start: [
|
|
893
959
|
{ regex: /"(?:[^\\]|\\.)*?(?:"|$)/, token: "string" },
|
|
894
|
-
|
|
895
|
-
|
|
960
|
+
// Word-bounded, so `dbtX` is not a dbt step whose first word happens to
|
|
961
|
+
// colour — the same thing the completion source asks of it.
|
|
962
|
+
{ regex: /dbt\b/, token: "keyword", sol: true },
|
|
963
|
+
{ regex: word(COMMAND_PHRASES), token: "keyword" },
|
|
896
964
|
{ regex: word(ARGUMENTS), token: "variableName" },
|
|
897
965
|
{ regex: prefix(METHODS), token: "propertyName" },
|
|
898
966
|
{ regex: prefix(FLAGS), token: "attributeName" },
|
|
@@ -940,6 +1008,8 @@ var KEYWORDS = {
|
|
|
940
1008
|
};
|
|
941
1009
|
var jsonnet = {
|
|
942
1010
|
name: "jsonnet",
|
|
1011
|
+
// `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
|
|
1012
|
+
languageData: { commentTokens: { line: "//", block: { open: "/*", close: "*/" } } },
|
|
943
1013
|
startState: () => ({
|
|
944
1014
|
cComment: false,
|
|
945
1015
|
textBlock: false,
|
|
@@ -1072,6 +1142,7 @@ var LANGUAGE_MODES = [
|
|
|
1072
1142
|
"text/x-mysql",
|
|
1073
1143
|
"text/x-pgsql",
|
|
1074
1144
|
"text/x-mssql",
|
|
1145
|
+
// Snowflake, under a historical name — these strings are a published prop contract.
|
|
1075
1146
|
"text/x-sfsql",
|
|
1076
1147
|
"text/x-plsql",
|
|
1077
1148
|
"text/x-rsrc",
|
|
@@ -1133,8 +1204,6 @@ var ALWAYS_OFF = {
|
|
|
1133
1204
|
var buildBasicSetup = (readOnly) => ({
|
|
1134
1205
|
...ALWAYS_OFF,
|
|
1135
1206
|
...readOnly ? {
|
|
1136
|
-
history: false,
|
|
1137
|
-
historyKeymap: false,
|
|
1138
1207
|
closeBrackets: false,
|
|
1139
1208
|
closeBracketsKeymap: false,
|
|
1140
1209
|
lintKeymap: false,
|
|
@@ -1172,7 +1241,7 @@ var getLanguageMode = (mode) => {
|
|
|
1172
1241
|
case "text/x-mssql":
|
|
1173
1242
|
return langSql.sql({ upperCaseKeywords: true, dialect: langSql.MSSQL });
|
|
1174
1243
|
case "text/x-sfsql":
|
|
1175
|
-
return
|
|
1244
|
+
return langSql.sql({ upperCaseKeywords: true, dialect: codemirrorLangSql.getSqlDialect("snowflake") });
|
|
1176
1245
|
case "text/x-plsql":
|
|
1177
1246
|
return langSql.sql({ upperCaseKeywords: true, dialect: langSql.PLSQL });
|
|
1178
1247
|
case "text/x-rsrc":
|
|
@@ -1197,6 +1266,112 @@ var getLanguageMode = (mode) => {
|
|
|
1197
1266
|
}
|
|
1198
1267
|
};
|
|
1199
1268
|
var shouldLintJson = (mode, readOnly) => mode === "application/json" && !readOnly;
|
|
1269
|
+
var setSearchEffect = state.StateEffect.define();
|
|
1270
|
+
function findMatches(doc, query) {
|
|
1271
|
+
if (!query) return [];
|
|
1272
|
+
const text = doc.toString();
|
|
1273
|
+
try {
|
|
1274
|
+
const regex = new RegExp(escapeStringRegexp(query), "gi");
|
|
1275
|
+
return Array.from(text.matchAll(regex)).map((match2, index) => {
|
|
1276
|
+
const from = match2.index;
|
|
1277
|
+
const to = from + match2[0].length;
|
|
1278
|
+
return { from, to, text: match2[0], localIndex: index };
|
|
1279
|
+
});
|
|
1280
|
+
} catch (e) {
|
|
1281
|
+
console.warn("Invalid search regex:", e);
|
|
1282
|
+
return [];
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
function createDecorations(matches, selectedLocalIndex) {
|
|
1286
|
+
const decorations = matches.map((match2) => {
|
|
1287
|
+
const isSelected = match2.localIndex === selectedLocalIndex;
|
|
1288
|
+
const decoration = view.Decoration.mark({
|
|
1289
|
+
class: isSelected ? "cm-searchMatch-selected" : "cm-searchMatch"
|
|
1290
|
+
});
|
|
1291
|
+
return decoration.range(match2.from, match2.to);
|
|
1292
|
+
});
|
|
1293
|
+
return view.Decoration.set(decorations, true);
|
|
1294
|
+
}
|
|
1295
|
+
var searchField = state.StateField.define({
|
|
1296
|
+
create() {
|
|
1297
|
+
return {
|
|
1298
|
+
query: "",
|
|
1299
|
+
selectedMatchIndex: void 0,
|
|
1300
|
+
matches: [],
|
|
1301
|
+
decorations: view.Decoration.none
|
|
1302
|
+
};
|
|
1303
|
+
},
|
|
1304
|
+
update(state, tr) {
|
|
1305
|
+
let newState = state;
|
|
1306
|
+
for (const effect of tr.effects) {
|
|
1307
|
+
if (!effect.is(setSearchEffect)) {
|
|
1308
|
+
continue;
|
|
1309
|
+
}
|
|
1310
|
+
const { query, selectedMatchIndex } = effect.value;
|
|
1311
|
+
const matches = findMatches(tr.state.doc, query);
|
|
1312
|
+
const decorations = createDecorations(matches, selectedMatchIndex);
|
|
1313
|
+
newState = {
|
|
1314
|
+
query,
|
|
1315
|
+
selectedMatchIndex,
|
|
1316
|
+
matches,
|
|
1317
|
+
decorations
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
if (tr.docChanged && newState.query) {
|
|
1321
|
+
const matches = findMatches(tr.state.doc, newState.query);
|
|
1322
|
+
const decorations = createDecorations(matches, newState.selectedMatchIndex);
|
|
1323
|
+
newState = {
|
|
1324
|
+
...newState,
|
|
1325
|
+
matches,
|
|
1326
|
+
decorations
|
|
1327
|
+
};
|
|
1328
|
+
}
|
|
1329
|
+
return newState;
|
|
1330
|
+
},
|
|
1331
|
+
provide: (field) => view.EditorView.decorations.from(field, (state) => state.decorations)
|
|
1332
|
+
});
|
|
1333
|
+
var searchViewPlugin = view.ViewPlugin.fromClass(
|
|
1334
|
+
class {
|
|
1335
|
+
lastSelectedIndex;
|
|
1336
|
+
update(update) {
|
|
1337
|
+
const state = update.state.field(searchField);
|
|
1338
|
+
if (state.selectedMatchIndex !== void 0 && state.selectedMatchIndex !== this.lastSelectedIndex) {
|
|
1339
|
+
const match2 = state.matches[state.selectedMatchIndex];
|
|
1340
|
+
if (match2) {
|
|
1341
|
+
requestAnimationFrame(() => {
|
|
1342
|
+
update.view.dispatch({
|
|
1343
|
+
effects: view.EditorView.scrollIntoView(match2.from, { y: "center" })
|
|
1344
|
+
});
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
this.lastSelectedIndex = state.selectedMatchIndex;
|
|
1348
|
+
}
|
|
1349
|
+
if (state.selectedMatchIndex === void 0) {
|
|
1350
|
+
this.lastSelectedIndex = void 0;
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
);
|
|
1355
|
+
var searchTheme = view.EditorView.baseTheme({
|
|
1356
|
+
".cm-searchMatch": {
|
|
1357
|
+
backgroundColor: colors__default.default.blue[100]
|
|
1358
|
+
},
|
|
1359
|
+
".cm-searchMatch > span": {
|
|
1360
|
+
color: `${colors__default.default.blue[600]} !important`
|
|
1361
|
+
},
|
|
1362
|
+
".cm-searchMatch-selected": {
|
|
1363
|
+
backgroundColor: colors__default.default.blue[600]
|
|
1364
|
+
},
|
|
1365
|
+
".cm-searchMatch-selected > span": {
|
|
1366
|
+
color: `${colors__default.default.white} !important`
|
|
1367
|
+
}
|
|
1368
|
+
});
|
|
1369
|
+
function searchExtension() {
|
|
1370
|
+
return [searchField, searchViewPlugin, searchTheme];
|
|
1371
|
+
}
|
|
1372
|
+
function updateSearch(view, query, selectedMatchIndex) {
|
|
1373
|
+
view.dispatch({ effects: setSearchEffect.of({ query, selectedMatchIndex }) });
|
|
1374
|
+
}
|
|
1200
1375
|
var KbdSeparator = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("span", { ...props, className: cn("tw:text-xs tw:text-muted-foreground", className) });
|
|
1201
1376
|
var KbdGroup = ({ ref, className, children, separator, ...props }) => {
|
|
1202
1377
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1256,12 +1431,79 @@ Kbd.Group = KbdGroup;
|
|
|
1256
1431
|
Kbd.Separator = KbdSeparator;
|
|
1257
1432
|
var ToggleComponentHelp = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1258
1433
|
"Use ",
|
|
1259
|
-
/* @__PURE__ */ jsxRuntime.jsx(Kbd, { children: "Ctrl+/" }),
|
|
1260
|
-
" or ",
|
|
1261
|
-
/* @__PURE__ */ jsxRuntime.jsx(Kbd, { children: "Command+/" }),
|
|
1434
|
+
/* @__PURE__ */ jsxRuntime.jsx(Kbd, { children: isMac ? "Command+/" : "Ctrl+/" }),
|
|
1262
1435
|
" to toggle comments."
|
|
1263
1436
|
] });
|
|
1264
|
-
var
|
|
1437
|
+
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);
|
|
1438
|
+
var crops = (style) => style.overflowX !== "visible" || style.overflowY !== "visible" || style.maskImage !== "none" || style.contentVisibility !== "visible" || /\b(paint|strict|content)\b/.test(style.contain);
|
|
1439
|
+
var findTooltipHost = (from) => {
|
|
1440
|
+
let outermostCropper = null;
|
|
1441
|
+
for (let node = from.parentElement; node && node !== document.body; node = node.parentElement) {
|
|
1442
|
+
const style = getComputedStyle(node);
|
|
1443
|
+
if (crops(style)) {
|
|
1444
|
+
outermostCropper = node;
|
|
1445
|
+
} else if (establishesFixedContainingBlock(style)) {
|
|
1446
|
+
return outermostCropper?.parentElement ?? node;
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
return outermostCropper?.parentElement ?? null;
|
|
1450
|
+
};
|
|
1451
|
+
var tooltipsExtension = () => {
|
|
1452
|
+
const layer = new state.Compartment();
|
|
1453
|
+
return [
|
|
1454
|
+
layer.of(view.tooltips()),
|
|
1455
|
+
view.ViewPlugin.define((view$1) => {
|
|
1456
|
+
const scheduled = setTimeout(() => {
|
|
1457
|
+
if (!view$1.dom.isConnected) return;
|
|
1458
|
+
const parent = findTooltipHost(view$1.dom);
|
|
1459
|
+
if (parent) view$1.dispatch({ effects: layer.reconfigure(view.tooltips({ parent })) });
|
|
1460
|
+
});
|
|
1461
|
+
return { destroy: () => clearTimeout(scheduled) };
|
|
1462
|
+
})
|
|
1463
|
+
];
|
|
1464
|
+
};
|
|
1465
|
+
var useTooltipsExtension = () => React26.useMemo(tooltipsExtension, []);
|
|
1466
|
+
|
|
1467
|
+
// src/components/CodeEditor/variableCompletion.ts
|
|
1468
|
+
var BOOST = 2e3;
|
|
1469
|
+
var NAME = String.raw`[\w-]*`;
|
|
1470
|
+
var AT_CARET = new RegExp(String.raw`(?:\{{1,2} ?)?${NAME}$`);
|
|
1471
|
+
var NAME_AT_END = new RegExp(`${NAME}$`);
|
|
1472
|
+
var OPENING = /\{{1,2} ?$/;
|
|
1473
|
+
var CLOSING = /^ ?\}{1,2}/;
|
|
1474
|
+
var completeVariables = (variables = []) => {
|
|
1475
|
+
if (variables.length === 0) return () => null;
|
|
1476
|
+
const options = variables.map(({ name, value }) => ({
|
|
1477
|
+
// The bare name: `SqlEditor` filters prefix-only while `CodeEditor` filters
|
|
1478
|
+
// fuzzily, and this is the only spelling both accept whether or not the caret
|
|
1479
|
+
// has typed the braces. The braces are `displayLabel`, which is what renders.
|
|
1480
|
+
label: name,
|
|
1481
|
+
displayLabel: `{{${name}}}`,
|
|
1482
|
+
detail: value,
|
|
1483
|
+
type: "variable",
|
|
1484
|
+
boost: BOOST,
|
|
1485
|
+
apply: (view, completion, from, to) => {
|
|
1486
|
+
const { doc } = view.state;
|
|
1487
|
+
const line = doc.lineAt(from);
|
|
1488
|
+
const insert = `{{${completion.label}}}`;
|
|
1489
|
+
const opening = OPENING.exec(doc.sliceString(line.from, from));
|
|
1490
|
+
const closing = CLOSING.exec(doc.sliceString(to, line.to));
|
|
1491
|
+
const start = opening ? from - opening[0].length : from;
|
|
1492
|
+
const end = closing ? to + closing[0].length : to;
|
|
1493
|
+
view.dispatch({
|
|
1494
|
+
changes: { from: start, to: end, insert },
|
|
1495
|
+
selection: { anchor: start + insert.length }
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
}));
|
|
1499
|
+
return (context) => {
|
|
1500
|
+
const match2 = context.matchBefore(AT_CARET);
|
|
1501
|
+
if (!match2?.text) return null;
|
|
1502
|
+
const [name = ""] = NAME_AT_END.exec(match2.text) ?? [];
|
|
1503
|
+
return { from: match2.to - name.length, options };
|
|
1504
|
+
};
|
|
1505
|
+
};
|
|
1506
|
+
var useVariableCompletion = (variables = []) => useStableCallback(completeVariables(variables));
|
|
1265
1507
|
var emptyObject = {};
|
|
1266
1508
|
var CodeEditor = ({
|
|
1267
1509
|
value,
|
|
@@ -1270,8 +1512,13 @@ var CodeEditor = ({
|
|
|
1270
1512
|
mode = "application/json",
|
|
1271
1513
|
placeholder = "",
|
|
1272
1514
|
ariaLabel,
|
|
1515
|
+
searchQuery,
|
|
1516
|
+
searchMatchIndex,
|
|
1273
1517
|
readOnly = false,
|
|
1274
|
-
|
|
1518
|
+
inputLocked = false,
|
|
1519
|
+
autocompletions,
|
|
1520
|
+
completionSource,
|
|
1521
|
+
variables,
|
|
1275
1522
|
extraKeys = emptyObject,
|
|
1276
1523
|
withToggleCommentHint = false,
|
|
1277
1524
|
withAutofocus = false,
|
|
@@ -1286,49 +1533,86 @@ var CodeEditor = ({
|
|
|
1286
1533
|
className
|
|
1287
1534
|
}) => {
|
|
1288
1535
|
const handleChange = useStableCallback((next) => onChange?.(next));
|
|
1536
|
+
const withSearch = searchQuery !== void 0;
|
|
1537
|
+
const editorRef = React26.useRef(null);
|
|
1538
|
+
React26.useEffect(() => {
|
|
1539
|
+
const view = editorRef.current?.view;
|
|
1540
|
+
if (view && withSearch) updateSearch(view, searchQuery, searchMatchIndex);
|
|
1541
|
+
}, [withSearch, searchQuery, searchMatchIndex]);
|
|
1542
|
+
const handleCreateEditor = useStableCallback((view) => {
|
|
1543
|
+
if (searchQuery) updateSearch(view, searchQuery, searchMatchIndex);
|
|
1544
|
+
});
|
|
1545
|
+
const extraKeysRef = React26.useRef(extraKeys);
|
|
1546
|
+
React26.useLayoutEffect(() => {
|
|
1547
|
+
extraKeysRef.current = extraKeys;
|
|
1548
|
+
});
|
|
1549
|
+
const boundKeysSignature = Object.keys(extraKeys).join("\n");
|
|
1550
|
+
const boundKeys = React26.useMemo(
|
|
1551
|
+
() => boundKeysSignature.split("\n").filter(Boolean),
|
|
1552
|
+
[boundKeysSignature]
|
|
1553
|
+
);
|
|
1554
|
+
const tooltipLayer = useTooltipsExtension();
|
|
1555
|
+
const variableCompletion = useVariableCompletion(variables);
|
|
1289
1556
|
const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
|
|
1290
1557
|
const baseTheme = useThemedExtension(
|
|
1291
1558
|
"code-editor:chrome",
|
|
1292
1559
|
() => view.EditorView.theme(buildBaseThemeStyles())
|
|
1293
1560
|
);
|
|
1294
1561
|
const commonExtensions = React26.useMemo(() => {
|
|
1562
|
+
const callerCompletions = completionSource ?? (completeAny ? autocomplete.completeAnyWord : autocompletions?.length ? autocompletions : null);
|
|
1563
|
+
const completionEntries = [
|
|
1564
|
+
...callerCompletions ? [{ autocomplete: callerCompletions }] : [],
|
|
1565
|
+
{ autocomplete: variableCompletion }
|
|
1566
|
+
];
|
|
1295
1567
|
return [
|
|
1296
1568
|
getLanguageMode(mode),
|
|
1297
1569
|
shouldLintJson(mode, readOnly) ? lint.linter(langJson.jsonParseLinter()) : [],
|
|
1298
1570
|
withLineWrapping ? view.EditorView.lineWrapping : [],
|
|
1299
|
-
CodeMirror.EditorState.languageData.of(() =>
|
|
1300
|
-
{ autocomplete: completeAny ? autocomplete.completeAnyWord : autocompletions }
|
|
1301
|
-
]),
|
|
1571
|
+
CodeMirror.EditorState.languageData.of(() => completionEntries),
|
|
1302
1572
|
view.keymap.of(
|
|
1303
|
-
|
|
1573
|
+
boundKeys.map((key) => ({
|
|
1304
1574
|
key,
|
|
1305
1575
|
run: () => {
|
|
1306
|
-
|
|
1307
|
-
run();
|
|
1576
|
+
extraKeysRef.current[key]?.();
|
|
1308
1577
|
return true;
|
|
1309
1578
|
}
|
|
1310
1579
|
}))
|
|
1311
1580
|
),
|
|
1312
|
-
readOnly ? [] :
|
|
1581
|
+
readOnly ? [] : [
|
|
1582
|
+
// CodeMirror's own default. Gating it on the props hid completions the
|
|
1583
|
+
// *language* supplies — dbt's vocabulary, Snowflake's keywords — behind
|
|
1584
|
+
// a shortcut, and macOS leaves no usable one. With nothing to offer, no
|
|
1585
|
+
// popup opens anyway.
|
|
1586
|
+
autocomplete.autocompletion()
|
|
1587
|
+
],
|
|
1313
1588
|
ariaLabel ? view.EditorView.contentAttributes.of({ "aria-label": ariaLabel }) : [],
|
|
1589
|
+
withSearch ? searchExtension() : [],
|
|
1590
|
+
tooltipLayer,
|
|
1314
1591
|
baseTheme
|
|
1315
1592
|
];
|
|
1316
1593
|
}, [
|
|
1317
1594
|
autocompletions,
|
|
1595
|
+
completionSource,
|
|
1596
|
+
variableCompletion,
|
|
1318
1597
|
completeAny,
|
|
1319
|
-
|
|
1598
|
+
boundKeys,
|
|
1320
1599
|
mode,
|
|
1321
1600
|
readOnly,
|
|
1322
1601
|
withLineWrapping,
|
|
1323
1602
|
baseTheme,
|
|
1324
|
-
ariaLabel
|
|
1603
|
+
ariaLabel,
|
|
1604
|
+
withSearch,
|
|
1605
|
+
tooltipLayer
|
|
1325
1606
|
]);
|
|
1326
1607
|
const extensions = React26.useMemo(() => {
|
|
1327
1608
|
return [
|
|
1328
1609
|
...commonExtensions,
|
|
1329
1610
|
view.placeholder(placeholder),
|
|
1330
1611
|
view.EditorView.editable.of(!readOnly),
|
|
1331
|
-
|
|
1612
|
+
// The lock is this facet and nothing else. `contenteditable` is what the
|
|
1613
|
+
// read-only wash keys off, and `basicSetup` is what holds the undo history,
|
|
1614
|
+
// so leaving both alone is what makes the lock invisible.
|
|
1615
|
+
CodeMirror.EditorState.readOnly.of(readOnly || inputLocked),
|
|
1332
1616
|
previousValue ? merge.unifiedMergeView({
|
|
1333
1617
|
original: previousValue,
|
|
1334
1618
|
mergeControls: false,
|
|
@@ -1336,13 +1620,16 @@ var CodeEditor = ({
|
|
|
1336
1620
|
collapseUnchanged: withCollapseUnchanged ? {} : void 0
|
|
1337
1621
|
}) : []
|
|
1338
1622
|
];
|
|
1339
|
-
}, [commonExtensions, placeholder, readOnly, previousValue, withCollapseUnchanged]);
|
|
1623
|
+
}, [commonExtensions, placeholder, readOnly, inputLocked, previousValue, withCollapseUnchanged]);
|
|
1340
1624
|
const config = React26.useMemo(() => {
|
|
1341
1625
|
return {
|
|
1342
1626
|
...buildBasicSetup(readOnly),
|
|
1343
|
-
lineNumbers: withLineNumbers
|
|
1627
|
+
lineNumbers: withLineNumbers,
|
|
1628
|
+
// Mod-f opens CodeMirror's own panel, which would run a second query and a
|
|
1629
|
+
// second match count over the same document beside the caller's input.
|
|
1630
|
+
...withSearch ? { searchKeymap: false } : null
|
|
1344
1631
|
};
|
|
1345
|
-
}, [withLineNumbers, readOnly]);
|
|
1632
|
+
}, [withLineNumbers, readOnly, withSearch]);
|
|
1346
1633
|
const additionalButtons = renderAdditionalButtons?.(value);
|
|
1347
1634
|
const hasToolbar = withCopyButton && !!value || !!additionalButtons;
|
|
1348
1635
|
return (
|
|
@@ -1365,6 +1652,8 @@ var CodeEditor = ({
|
|
|
1365
1652
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1366
1653
|
CodeMirror__default.default,
|
|
1367
1654
|
{
|
|
1655
|
+
ref: editorRef,
|
|
1656
|
+
onCreateEditor: handleCreateEditor,
|
|
1368
1657
|
theme: customTheme,
|
|
1369
1658
|
value,
|
|
1370
1659
|
onChange: handleChange,
|
|
@@ -8948,9 +9237,9 @@ var ComboboxItemIndicator = ({ ref, className, variant = "check", ...props }) =>
|
|
|
8948
9237
|
"tw:absolute",
|
|
8949
9238
|
"tw:right-2",
|
|
8950
9239
|
"tw:group-data-[variant=default]/combobox-content:right-4",
|
|
8951
|
-
//
|
|
8952
|
-
//
|
|
8953
|
-
|
|
9240
|
+
// `render={<Check />}` makes the icon the indicator element itself (not a descendant), so a
|
|
9241
|
+
// `[&_svg]` rule never matches it — size it directly or Lucide renders at its 24px default.
|
|
9242
|
+
"tw:size-4",
|
|
8954
9243
|
"tw:group-data-[highlighted]/combobox-item:text-accent-foreground",
|
|
8955
9244
|
"tw:group-data-[variant=default]/combobox-content:group-data-[highlighted]/combobox-item:text-foreground",
|
|
8956
9245
|
className
|
|
@@ -9075,6 +9364,9 @@ var ComboboxGroupLabel = ({ ref, className, ...props }) => /* @__PURE__ */ jsxRu
|
|
|
9075
9364
|
}
|
|
9076
9365
|
);
|
|
9077
9366
|
var ComboboxCollection = ({ ...props }) => /* @__PURE__ */ jsxRuntime.jsx(combobox.Combobox.Collection, { "data-slot": "combobox-collection", ...props });
|
|
9367
|
+
var VIRTUALIZE_THRESHOLD = 30;
|
|
9368
|
+
var ESTIMATED_ROW_HEIGHT = 40;
|
|
9369
|
+
var ESTIMATED_LIST_HEIGHT = 320;
|
|
9078
9370
|
var Combobox = ({
|
|
9079
9371
|
// root props
|
|
9080
9372
|
items: _itemsProp,
|
|
@@ -9101,6 +9393,7 @@ var Combobox = ({
|
|
|
9101
9393
|
empty = "No items",
|
|
9102
9394
|
indicator,
|
|
9103
9395
|
prefix: prefix2,
|
|
9396
|
+
virtualized = false,
|
|
9104
9397
|
// creatable
|
|
9105
9398
|
allowCreate,
|
|
9106
9399
|
queryToCreateValue,
|
|
@@ -9124,7 +9417,9 @@ var Combobox = ({
|
|
|
9124
9417
|
const label = value === null ? "" : itemToStringLabelProp?.(value) ?? toLabel(value);
|
|
9125
9418
|
setInputValue((prev) => prev === label ? prev : label);
|
|
9126
9419
|
}, [value]);
|
|
9127
|
-
const
|
|
9420
|
+
const selectedLabel = value == null ? void 0 : itemToStringLabelProp?.(value) ?? toLabel(value);
|
|
9421
|
+
const isShowingSelection = selectedLabel !== void 0 && inputValue === selectedLabel;
|
|
9422
|
+
const query = (isShowingSelection ? "" : inputValue).trim();
|
|
9128
9423
|
const queryLower = query.toLowerCase();
|
|
9129
9424
|
const itemsProp = _itemsProp ?? [];
|
|
9130
9425
|
const sampleItem = itemsProp.flatMap((item) => isGroupItem(item) ? item.items : [item])[0];
|
|
@@ -9149,7 +9444,7 @@ var Combobox = ({
|
|
|
9149
9444
|
if (isCreatableItem(value2)) return value2.value;
|
|
9150
9445
|
return itemToStringLabelProp?.(value2) ?? toLabel(value2);
|
|
9151
9446
|
};
|
|
9152
|
-
const wrappedFilter = !allowCreate || !filter ? filter : (item, ...args) => isCreatableItem(item) || filter(item, ...args);
|
|
9447
|
+
const wrappedFilter = isShowingSelection ? () => true : !allowCreate || !filter ? filter : (item, ...args) => isCreatableItem(item) || filter(item, ...args);
|
|
9153
9448
|
const wrappedItemToStringValue = !allowCreate || !itemToStringValue ? itemToStringValue : (item) => isCreatableItem(item) ? item.value : itemToStringValue(item);
|
|
9154
9449
|
const isItemEqualToValue = (a, b) => {
|
|
9155
9450
|
if (isCreatableItem(a) || isCreatableItem(b)) return toValueKey(a) === toValueKey(b);
|
|
@@ -9184,10 +9479,34 @@ var Combobox = ({
|
|
|
9184
9479
|
closeReasonRef.current = "item-press";
|
|
9185
9480
|
onValueChange?.(next, event);
|
|
9186
9481
|
};
|
|
9187
|
-
const
|
|
9482
|
+
const [listElement, setListElement] = React26.useState(null);
|
|
9483
|
+
const isGrouped = isGroupItems(allItems);
|
|
9484
|
+
const shouldVirtualize = !isGrouped && (virtualized === true || virtualized === "auto" && allItems.length > VIRTUALIZE_THRESHOLD);
|
|
9485
|
+
const matchesQuery = (item) => {
|
|
9486
|
+
if (isCreatableItem(item)) return true;
|
|
9487
|
+
if (!query) return true;
|
|
9488
|
+
if (filter) return !!filter(item, query, (value2) => itemToStringLabel(value2) ?? toLabel(value2));
|
|
9489
|
+
return (itemToStringLabel(item) ?? toLabel(item)).toLowerCase().includes(queryLower);
|
|
9490
|
+
};
|
|
9491
|
+
const virtualItems = shouldVirtualize ? items.filter(matchesQuery) : [];
|
|
9492
|
+
const virtualizer = reactVirtual.useVirtualizer({
|
|
9493
|
+
count: virtualItems.length,
|
|
9494
|
+
getScrollElement: () => listElement,
|
|
9495
|
+
estimateSize: () => ESTIMATED_ROW_HEIGHT,
|
|
9496
|
+
overscan: 12,
|
|
9497
|
+
enabled: shouldVirtualize,
|
|
9498
|
+
// Seed a viewport height so rows paint on the first frame. Without it the list measures 0 until
|
|
9499
|
+
// the ResizeObserver fires (a frame later), which renders an empty popup on open.
|
|
9500
|
+
initialRect: { width: 0, height: ESTIMATED_LIST_HEIGHT }
|
|
9501
|
+
});
|
|
9502
|
+
const renderItem = (item, index) => {
|
|
9503
|
+
if (isCreatableItem(item)) {
|
|
9504
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Combobox.Item, { index, value: item, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {}), children: queryToCreateLabel(item.value) });
|
|
9505
|
+
}
|
|
9188
9506
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9189
9507
|
Combobox.Item,
|
|
9190
9508
|
{
|
|
9509
|
+
index,
|
|
9191
9510
|
value: item,
|
|
9192
9511
|
indicator,
|
|
9193
9512
|
icon: itemToIcon(item),
|
|
@@ -9196,13 +9515,20 @@ var Combobox = ({
|
|
|
9196
9515
|
}
|
|
9197
9516
|
);
|
|
9198
9517
|
};
|
|
9518
|
+
const rowStyle = (offset) => ({
|
|
9519
|
+
position: "absolute",
|
|
9520
|
+
top: 0,
|
|
9521
|
+
left: 0,
|
|
9522
|
+
width: "100%",
|
|
9523
|
+
transform: `translateY(${offset}px)`
|
|
9524
|
+
});
|
|
9199
9525
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9200
9526
|
combobox.Combobox.Root,
|
|
9201
9527
|
{
|
|
9202
|
-
items,
|
|
9528
|
+
items: shouldVirtualize ? virtualItems : items,
|
|
9203
9529
|
value,
|
|
9204
9530
|
defaultValue,
|
|
9205
|
-
filter: wrappedFilter,
|
|
9531
|
+
filter: shouldVirtualize ? null : wrappedFilter,
|
|
9206
9532
|
onValueChange: handleOnValueChange,
|
|
9207
9533
|
itemToStringLabel,
|
|
9208
9534
|
isItemEqualToValue,
|
|
@@ -9212,6 +9538,12 @@ var Combobox = ({
|
|
|
9212
9538
|
inputRef,
|
|
9213
9539
|
inputValue,
|
|
9214
9540
|
onInputValueChange: handleInputValueChange,
|
|
9541
|
+
virtualized: shouldVirtualize,
|
|
9542
|
+
onItemHighlighted: (_, details) => {
|
|
9543
|
+
if (shouldVirtualize && details.reason === "keyboard") {
|
|
9544
|
+
virtualizer.scrollToIndex(details.index);
|
|
9545
|
+
}
|
|
9546
|
+
},
|
|
9215
9547
|
children: [
|
|
9216
9548
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9217
9549
|
ComboboxInputGroup,
|
|
@@ -9233,7 +9565,30 @@ var Combobox = ({
|
|
|
9233
9565
|
),
|
|
9234
9566
|
/* @__PURE__ */ jsxRuntime.jsxs(ComboboxContent, { children: [
|
|
9235
9567
|
/* @__PURE__ */ jsxRuntime.jsx(ComboboxEmpty, { children: empty }),
|
|
9236
|
-
/* @__PURE__ */ jsxRuntime.jsx(ComboboxList, { children:
|
|
9568
|
+
shouldVirtualize ? /* @__PURE__ */ jsxRuntime.jsx(ComboboxList, { ref: setListElement, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9569
|
+
"div",
|
|
9570
|
+
{
|
|
9571
|
+
style: {
|
|
9572
|
+
position: "relative",
|
|
9573
|
+
width: "100%",
|
|
9574
|
+
height: `${virtualizer.getTotalSize()}px`
|
|
9575
|
+
},
|
|
9576
|
+
children: virtualizer.getVirtualItems().map((row) => {
|
|
9577
|
+
const item = virtualItems[row.index];
|
|
9578
|
+
if (item === void 0) return null;
|
|
9579
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9580
|
+
"div",
|
|
9581
|
+
{
|
|
9582
|
+
"data-index": row.index,
|
|
9583
|
+
ref: virtualizer.measureElement,
|
|
9584
|
+
style: rowStyle(row.start),
|
|
9585
|
+
children: renderItem(item, row.index)
|
|
9586
|
+
},
|
|
9587
|
+
row.key
|
|
9588
|
+
);
|
|
9589
|
+
})
|
|
9590
|
+
}
|
|
9591
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(ComboboxList, { children: (itemOrGroup) => {
|
|
9237
9592
|
if (isCreatableItem(itemOrGroup))
|
|
9238
9593
|
return /* @__PURE__ */ jsxRuntime.jsx(Combobox.Item, { value: itemOrGroup, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {}), children: queryToCreateLabel(itemOrGroup.value) });
|
|
9239
9594
|
if (isGroupItem(itemOrGroup)) {
|
|
@@ -9244,7 +9599,7 @@ var Combobox = ({
|
|
|
9244
9599
|
const groupLabel = groupToLabel(itemOrGroup);
|
|
9245
9600
|
return /* @__PURE__ */ jsxRuntime.jsxs(Combobox.Group, { items: itemOrGroup.items, children: [
|
|
9246
9601
|
groupLabel && /* @__PURE__ */ jsxRuntime.jsx(Combobox.GroupLabel, { children: groupLabel }),
|
|
9247
|
-
/* @__PURE__ */ jsxRuntime.jsx(Combobox.GroupList, { children: renderItem })
|
|
9602
|
+
/* @__PURE__ */ jsxRuntime.jsx(Combobox.GroupList, { children: (item) => renderItem(item) })
|
|
9248
9603
|
] });
|
|
9249
9604
|
}
|
|
9250
9605
|
return renderItem(itemOrGroup);
|