@keboola/design 9.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/rjsf.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import React26, { createContext, use, useCallback, useMemo, useRef, useState, useEffect, useContext, isValidElement, useLayoutEffect, useId, useSyncExternalStore, Children, Fragment as Fragment$1 } from 'react';
2
2
  import Form2 from '@rjsf/core';
3
3
  import validator from '@rjsf/validator-ajv8';
4
- import { completeFromList, completeAnyWord, autocompletion } from '@codemirror/autocomplete';
4
+ import { completeAnyWord, autocompletion } from '@codemirror/autocomplete';
5
5
  import { jsonParseLinter, json } from '@codemirror/lang-json';
6
6
  import { linter } from '@codemirror/lint';
7
7
  import { unifiedMergeView } from '@codemirror/merge';
@@ -23,7 +23,7 @@ import { r } from '@codemirror/legacy-modes/mode/r';
23
23
  import { shell } from '@codemirror/legacy-modes/mode/shell';
24
24
  import { toml } from '@codemirror/legacy-modes/mode/toml';
25
25
  import { githubLightInit } from '@uiw/codemirror-theme-github';
26
- import { modeSpec, sfsql } from '@keboola/codemirror-lang-sfsql';
26
+ import { getSqlDialect } from '@keboola/codemirror-lang-sql';
27
27
  import colors from '@keboola/tailwind-config/colors';
28
28
  import { simpleMode } from '@codemirror/legacy-modes/mode/simple-mode';
29
29
  import { StateEffect, StateField, Compartment } from '@codemirror/state';
@@ -36,6 +36,7 @@ import TextareaAutosize from 'react-textarea-autosize';
36
36
  import { Root, Indicator } from '@radix-ui/react-checkbox';
37
37
  import { Root as Root$3, Trigger as Trigger$1, Close, Portal as Portal$1, Content as Content$2 } from '@radix-ui/react-popover';
38
38
  import { Combobox as Combobox$1 } from '@base-ui/react/combobox';
39
+ import { useVirtualizer } from '@tanstack/react-virtual';
39
40
  import * as RRadioGroup from '@radix-ui/react-radio-group';
40
41
  import { Item, Indicator as Indicator$1 } from '@radix-ui/react-radio-group';
41
42
  import * as RSeparator from '@radix-ui/react-separator';
@@ -1107,6 +1108,7 @@ var LANGUAGE_MODES = [
1107
1108
  "text/x-mysql",
1108
1109
  "text/x-pgsql",
1109
1110
  "text/x-mssql",
1111
+ // Snowflake, under a historical name — these strings are a published prop contract.
1110
1112
  "text/x-sfsql",
1111
1113
  "text/x-plsql",
1112
1114
  "text/x-rsrc",
@@ -1168,8 +1170,6 @@ var ALWAYS_OFF = {
1168
1170
  var buildBasicSetup = (readOnly) => ({
1169
1171
  ...ALWAYS_OFF,
1170
1172
  ...readOnly ? {
1171
- history: false,
1172
- historyKeymap: false,
1173
1173
  closeBrackets: false,
1174
1174
  closeBracketsKeymap: false,
1175
1175
  lintKeymap: false,
@@ -1191,20 +1191,6 @@ var buildCustomTheme = () => githubLightInit({
1191
1191
  selection: resolveToken("primary", "31 143 255")
1192
1192
  }
1193
1193
  });
1194
- var sfsqlWithLanguageData = {
1195
- ...sfsql,
1196
- languageData: {
1197
- ...sfsql.languageData,
1198
- // `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
1199
- commentTokens: { line: "--", block: { open: "/*", close: "*/" } },
1200
- autocomplete: completeFromList(
1201
- Object.keys(modeSpec.keywords).map((label) => ({
1202
- label: label.toUpperCase(),
1203
- type: "keyword"
1204
- }))
1205
- )
1206
- }
1207
- };
1208
1194
  var getLanguageMode = (mode) => {
1209
1195
  switch (mode) {
1210
1196
  case void 0:
@@ -1221,7 +1207,7 @@ var getLanguageMode = (mode) => {
1221
1207
  case "text/x-mssql":
1222
1208
  return sql({ upperCaseKeywords: true, dialect: MSSQL });
1223
1209
  case "text/x-sfsql":
1224
- return StreamLanguage.define(sfsqlWithLanguageData);
1210
+ return sql({ upperCaseKeywords: true, dialect: getSqlDialect("snowflake") });
1225
1211
  case "text/x-plsql":
1226
1212
  return sql({ upperCaseKeywords: true, dialect: PLSQL });
1227
1213
  case "text/x-rsrc":
@@ -1483,7 +1469,7 @@ var completeVariables = (variables = []) => {
1483
1469
  return { from: match2.to - name.length, options };
1484
1470
  };
1485
1471
  };
1486
- var emptyArray = [];
1472
+ var useVariableCompletion = (variables = []) => useStableCallback(completeVariables(variables));
1487
1473
  var emptyObject = {};
1488
1474
  var CodeEditor = ({
1489
1475
  value,
@@ -1495,7 +1481,8 @@ var CodeEditor = ({
1495
1481
  searchQuery,
1496
1482
  searchMatchIndex,
1497
1483
  readOnly = false,
1498
- autocompletions = emptyArray,
1484
+ inputLocked = false,
1485
+ autocompletions,
1499
1486
  completionSource,
1500
1487
  variables,
1501
1488
  extraKeys = emptyObject,
@@ -1531,21 +1518,23 @@ var CodeEditor = ({
1531
1518
  [boundKeysSignature]
1532
1519
  );
1533
1520
  const tooltipLayer = useTooltipsExtension();
1534
- const variableCompletion = useMemo(() => completeVariables(variables), [variables]);
1521
+ const variableCompletion = useVariableCompletion(variables);
1535
1522
  const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
1536
1523
  const baseTheme = useThemedExtension(
1537
1524
  "code-editor:chrome",
1538
1525
  () => EditorView.theme(buildBaseThemeStyles())
1539
1526
  );
1540
1527
  const commonExtensions = useMemo(() => {
1528
+ const callerCompletions = completionSource ?? (completeAny ? completeAnyWord : autocompletions?.length ? autocompletions : null);
1529
+ const completionEntries = [
1530
+ ...callerCompletions ? [{ autocomplete: callerCompletions }] : [],
1531
+ { autocomplete: variableCompletion }
1532
+ ];
1541
1533
  return [
1542
1534
  getLanguageMode(mode),
1543
1535
  shouldLintJson(mode, readOnly) ? linter(jsonParseLinter()) : [],
1544
1536
  withLineWrapping ? EditorView.lineWrapping : [],
1545
- EditorState.languageData.of(() => [
1546
- { autocomplete: completionSource ?? (completeAny ? completeAnyWord : autocompletions) }
1547
- ]),
1548
- EditorState.languageData.of(() => [{ autocomplete: variableCompletion }]),
1537
+ EditorState.languageData.of(() => completionEntries),
1549
1538
  keymap.of(
1550
1539
  boundKeys.map((key) => ({
1551
1540
  key,
@@ -1586,7 +1575,10 @@ var CodeEditor = ({
1586
1575
  ...commonExtensions,
1587
1576
  placeholder(placeholder$1),
1588
1577
  EditorView.editable.of(!readOnly),
1589
- EditorState.readOnly.of(readOnly),
1578
+ // The lock is this facet and nothing else. `contenteditable` is what the
1579
+ // read-only wash keys off, and `basicSetup` is what holds the undo history,
1580
+ // so leaving both alone is what makes the lock invisible.
1581
+ EditorState.readOnly.of(readOnly || inputLocked),
1590
1582
  previousValue ? unifiedMergeView({
1591
1583
  original: previousValue,
1592
1584
  mergeControls: false,
@@ -1594,7 +1586,7 @@ var CodeEditor = ({
1594
1586
  collapseUnchanged: withCollapseUnchanged ? {} : void 0
1595
1587
  }) : []
1596
1588
  ];
1597
- }, [commonExtensions, placeholder$1, readOnly, previousValue, withCollapseUnchanged]);
1589
+ }, [commonExtensions, placeholder$1, readOnly, inputLocked, previousValue, withCollapseUnchanged]);
1598
1590
  const config = useMemo(() => {
1599
1591
  return {
1600
1592
  ...buildBasicSetup(readOnly),
@@ -9211,9 +9203,9 @@ var ComboboxItemIndicator = ({ ref, className, variant = "check", ...props }) =>
9211
9203
  "tw:absolute",
9212
9204
  "tw:right-2",
9213
9205
  "tw:group-data-[variant=default]/combobox-content:right-4",
9214
- // Lucide SVGs default to 24×24 — constrain the rendered child so the
9215
- // 16px indicator slot owns the actual size.
9216
- 'tw:[&_svg:not([class*="tw:size-"])]:size-4',
9206
+ // `render={<Check />}` makes the icon the indicator element itself (not a descendant), so a
9207
+ // `[&_svg]` rule never matches it — size it directly or Lucide renders at its 24px default.
9208
+ "tw:size-4",
9217
9209
  "tw:group-data-[highlighted]/combobox-item:text-accent-foreground",
9218
9210
  "tw:group-data-[variant=default]/combobox-content:group-data-[highlighted]/combobox-item:text-foreground",
9219
9211
  className
@@ -9338,6 +9330,9 @@ var ComboboxGroupLabel = ({ ref, className, ...props }) => /* @__PURE__ */ jsx(
9338
9330
  }
9339
9331
  );
9340
9332
  var ComboboxCollection = ({ ...props }) => /* @__PURE__ */ jsx(Combobox$1.Collection, { "data-slot": "combobox-collection", ...props });
9333
+ var VIRTUALIZE_THRESHOLD = 30;
9334
+ var ESTIMATED_ROW_HEIGHT = 40;
9335
+ var ESTIMATED_LIST_HEIGHT = 320;
9341
9336
  var Combobox = ({
9342
9337
  // root props
9343
9338
  items: _itemsProp,
@@ -9364,6 +9359,7 @@ var Combobox = ({
9364
9359
  empty = "No items",
9365
9360
  indicator,
9366
9361
  prefix: prefix2,
9362
+ virtualized = false,
9367
9363
  // creatable
9368
9364
  allowCreate,
9369
9365
  queryToCreateValue,
@@ -9387,7 +9383,9 @@ var Combobox = ({
9387
9383
  const label = value === null ? "" : itemToStringLabelProp?.(value) ?? toLabel(value);
9388
9384
  setInputValue((prev) => prev === label ? prev : label);
9389
9385
  }, [value]);
9390
- const query = inputValue.trim();
9386
+ const selectedLabel = value == null ? void 0 : itemToStringLabelProp?.(value) ?? toLabel(value);
9387
+ const isShowingSelection = selectedLabel !== void 0 && inputValue === selectedLabel;
9388
+ const query = (isShowingSelection ? "" : inputValue).trim();
9391
9389
  const queryLower = query.toLowerCase();
9392
9390
  const itemsProp = _itemsProp ?? [];
9393
9391
  const sampleItem = itemsProp.flatMap((item) => isGroupItem(item) ? item.items : [item])[0];
@@ -9412,7 +9410,7 @@ var Combobox = ({
9412
9410
  if (isCreatableItem(value2)) return value2.value;
9413
9411
  return itemToStringLabelProp?.(value2) ?? toLabel(value2);
9414
9412
  };
9415
- const wrappedFilter = !allowCreate || !filter ? filter : (item, ...args) => isCreatableItem(item) || filter(item, ...args);
9413
+ const wrappedFilter = isShowingSelection ? () => true : !allowCreate || !filter ? filter : (item, ...args) => isCreatableItem(item) || filter(item, ...args);
9416
9414
  const wrappedItemToStringValue = !allowCreate || !itemToStringValue ? itemToStringValue : (item) => isCreatableItem(item) ? item.value : itemToStringValue(item);
9417
9415
  const isItemEqualToValue = (a, b) => {
9418
9416
  if (isCreatableItem(a) || isCreatableItem(b)) return toValueKey(a) === toValueKey(b);
@@ -9447,10 +9445,34 @@ var Combobox = ({
9447
9445
  closeReasonRef.current = "item-press";
9448
9446
  onValueChange?.(next, event);
9449
9447
  };
9450
- const renderItem = (item) => {
9448
+ const [listElement, setListElement] = useState(null);
9449
+ const isGrouped = isGroupItems(allItems);
9450
+ const shouldVirtualize = !isGrouped && (virtualized === true || virtualized === "auto" && allItems.length > VIRTUALIZE_THRESHOLD);
9451
+ const matchesQuery = (item) => {
9452
+ if (isCreatableItem(item)) return true;
9453
+ if (!query) return true;
9454
+ if (filter) return !!filter(item, query, (value2) => itemToStringLabel(value2) ?? toLabel(value2));
9455
+ return (itemToStringLabel(item) ?? toLabel(item)).toLowerCase().includes(queryLower);
9456
+ };
9457
+ const virtualItems = shouldVirtualize ? items.filter(matchesQuery) : [];
9458
+ const virtualizer = useVirtualizer({
9459
+ count: virtualItems.length,
9460
+ getScrollElement: () => listElement,
9461
+ estimateSize: () => ESTIMATED_ROW_HEIGHT,
9462
+ overscan: 12,
9463
+ enabled: shouldVirtualize,
9464
+ // Seed a viewport height so rows paint on the first frame. Without it the list measures 0 until
9465
+ // the ResizeObserver fires (a frame later), which renders an empty popup on open.
9466
+ initialRect: { width: 0, height: ESTIMATED_LIST_HEIGHT }
9467
+ });
9468
+ const renderItem = (item, index) => {
9469
+ if (isCreatableItem(item)) {
9470
+ return /* @__PURE__ */ jsx(Combobox.Item, { index, value: item, icon: /* @__PURE__ */ jsx(Plus, {}), children: queryToCreateLabel(item.value) });
9471
+ }
9451
9472
  return /* @__PURE__ */ jsx(
9452
9473
  Combobox.Item,
9453
9474
  {
9475
+ index,
9454
9476
  value: item,
9455
9477
  indicator,
9456
9478
  icon: itemToIcon(item),
@@ -9459,13 +9481,20 @@ var Combobox = ({
9459
9481
  }
9460
9482
  );
9461
9483
  };
9484
+ const rowStyle = (offset) => ({
9485
+ position: "absolute",
9486
+ top: 0,
9487
+ left: 0,
9488
+ width: "100%",
9489
+ transform: `translateY(${offset}px)`
9490
+ });
9462
9491
  return /* @__PURE__ */ jsxs(
9463
9492
  Combobox$1.Root,
9464
9493
  {
9465
- items,
9494
+ items: shouldVirtualize ? virtualItems : items,
9466
9495
  value,
9467
9496
  defaultValue,
9468
- filter: wrappedFilter,
9497
+ filter: shouldVirtualize ? null : wrappedFilter,
9469
9498
  onValueChange: handleOnValueChange,
9470
9499
  itemToStringLabel,
9471
9500
  isItemEqualToValue,
@@ -9475,6 +9504,12 @@ var Combobox = ({
9475
9504
  inputRef,
9476
9505
  inputValue,
9477
9506
  onInputValueChange: handleInputValueChange,
9507
+ virtualized: shouldVirtualize,
9508
+ onItemHighlighted: (_, details) => {
9509
+ if (shouldVirtualize && details.reason === "keyboard") {
9510
+ virtualizer.scrollToIndex(details.index);
9511
+ }
9512
+ },
9478
9513
  children: [
9479
9514
  /* @__PURE__ */ jsxs(
9480
9515
  ComboboxInputGroup,
@@ -9496,7 +9531,30 @@ var Combobox = ({
9496
9531
  ),
9497
9532
  /* @__PURE__ */ jsxs(ComboboxContent, { children: [
9498
9533
  /* @__PURE__ */ jsx(ComboboxEmpty, { children: empty }),
9499
- /* @__PURE__ */ jsx(ComboboxList, { children: (itemOrGroup) => {
9534
+ shouldVirtualize ? /* @__PURE__ */ jsx(ComboboxList, { ref: setListElement, children: /* @__PURE__ */ jsx(
9535
+ "div",
9536
+ {
9537
+ style: {
9538
+ position: "relative",
9539
+ width: "100%",
9540
+ height: `${virtualizer.getTotalSize()}px`
9541
+ },
9542
+ children: virtualizer.getVirtualItems().map((row) => {
9543
+ const item = virtualItems[row.index];
9544
+ if (item === void 0) return null;
9545
+ return /* @__PURE__ */ jsx(
9546
+ "div",
9547
+ {
9548
+ "data-index": row.index,
9549
+ ref: virtualizer.measureElement,
9550
+ style: rowStyle(row.start),
9551
+ children: renderItem(item, row.index)
9552
+ },
9553
+ row.key
9554
+ );
9555
+ })
9556
+ }
9557
+ ) }) : /* @__PURE__ */ jsx(ComboboxList, { children: (itemOrGroup) => {
9500
9558
  if (isCreatableItem(itemOrGroup))
9501
9559
  return /* @__PURE__ */ jsx(Combobox.Item, { value: itemOrGroup, icon: /* @__PURE__ */ jsx(Plus, {}), children: queryToCreateLabel(itemOrGroup.value) });
9502
9560
  if (isGroupItem(itemOrGroup)) {
@@ -9507,7 +9565,7 @@ var Combobox = ({
9507
9565
  const groupLabel = groupToLabel(itemOrGroup);
9508
9566
  return /* @__PURE__ */ jsxs(Combobox.Group, { items: itemOrGroup.items, children: [
9509
9567
  groupLabel && /* @__PURE__ */ jsx(Combobox.GroupLabel, { children: groupLabel }),
9510
- /* @__PURE__ */ jsx(Combobox.GroupList, { children: renderItem })
9568
+ /* @__PURE__ */ jsx(Combobox.GroupList, { children: (item) => renderItem(item) })
9511
9569
  ] });
9512
9570
  }
9513
9571
  return renderItem(itemOrGroup);