@crisp-ui-kit/crisp 0.54.9 → 0.54.11

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.
Files changed (52) hide show
  1. package/dist/cjs/components/datatable/datatable.js +175 -12
  2. package/dist/cjs/components/datatable/datatable.recipe.js +30 -0
  3. package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +25 -2
  4. package/dist/cjs/components/tabletoolbar/tabletoolbar.js +159 -63
  5. package/dist/cjs/components/tabletoolbar/tabletoolbar.recipe.js +41 -9
  6. package/dist/cjs/components/text/text.recipe.js +17 -7
  7. package/dist/cjs/product/recordpage/column.js +19 -0
  8. package/dist/cjs/product/recordpage/recordpage.js +5 -4
  9. package/dist/cjs/product/recordpage/test-fixtures.js +55 -0
  10. package/dist/cjs/product/recordstable/index.js +1 -1
  11. package/dist/cjs/product/recordstable/recordstable.js +5 -0
  12. package/dist/cjs/product/savedviews/savedviews.recipe.js +13 -11
  13. package/dist/cjs/product/taskstable/taskstable.js +5 -0
  14. package/dist/datatable.css +17 -0
  15. package/dist/datatable.layered.css +17 -0
  16. package/dist/esm/components/datatable/datatable.js +175 -12
  17. package/dist/esm/components/datatable/datatable.recipe.js +30 -0
  18. package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +25 -2
  19. package/dist/esm/components/tabletoolbar/tabletoolbar.js +159 -63
  20. package/dist/esm/components/tabletoolbar/tabletoolbar.recipe.js +41 -9
  21. package/dist/esm/components/text/text.recipe.js +17 -7
  22. package/dist/esm/product/recordpage/column.js +16 -0
  23. package/dist/esm/product/recordpage/recordpage.js +2 -1
  24. package/dist/esm/product/recordpage/test-fixtures.js +52 -0
  25. package/dist/esm/product/recordstable/index.js +1 -1
  26. package/dist/esm/product/recordstable/recordstable.js +5 -0
  27. package/dist/esm/product/savedviews/savedviews.recipe.js +13 -11
  28. package/dist/esm/product/taskstable/taskstable.js +5 -0
  29. package/dist/recordstable.css +19 -2
  30. package/dist/recordstable.layered.css +19 -2
  31. package/dist/savedviews.css +6 -18
  32. package/dist/savedviews.layered.css +6 -18
  33. package/dist/styles.css +78 -24
  34. package/dist/styles.layered.css +78 -24
  35. package/dist/tabletoolbar.css +35 -3
  36. package/dist/tabletoolbar.layered.css +35 -3
  37. package/dist/text.css +1 -1
  38. package/dist/text.layered.css +1 -1
  39. package/dist/types/components/datatable/datatable.d.ts +38 -3
  40. package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +26 -1
  41. package/dist/types/components/text/text.recipe.d.ts +1 -1
  42. package/dist/types/product/recordpage/column.d.ts +112 -0
  43. package/dist/types/product/recordpage/recordpage.d.ts +1 -1
  44. package/dist/types/product/recordpage/test-fixtures.d.ts +3 -0
  45. package/dist/types/product/recordpanel/recordpanel.d.ts +1 -1
  46. package/dist/types/product/recordstable/index.d.ts +1 -1
  47. package/dist/types/product/recordstable/recordstable.d.ts +6 -1
  48. package/dist/types/product/taskstable/taskstable.d.ts +5 -0
  49. package/package.json +1 -1
  50. /package/dist/cjs/product/{recordstable → recordpage}/editable-field.js +0 -0
  51. /package/dist/esm/product/{recordstable → recordpage}/editable-field.js +0 -0
  52. /package/dist/types/product/{recordstable → recordpage}/editable-field.d.ts +0 -0
@@ -40,11 +40,41 @@ exports.TableToolbar = TableToolbar;
40
40
  const jsx_runtime_1 = require("react/jsx-runtime");
41
41
  const lucide_react_1 = require("lucide-react");
42
42
  const React = __importStar(require("react"));
43
+ const react_dom_1 = require("react-dom");
43
44
  const core_1 = require("../../core");
44
45
  const datepicker_1 = require("../datepicker");
45
46
  const menu_1 = require("../menu");
46
47
  const select_1 = require("../select");
47
48
  const tabletoolbar_recipe_1 = require("./tabletoolbar.recipe");
49
+ // crisp/#766, #772: portals View settings/Import-Export into a
50
+ // consumer-supplied target (e.g. a `<span>` rendered next to `SavedViews`,
51
+ // or another next to the primary action) instead of this toolbar's own row,
52
+ // when one is given -- a plain passthrough otherwise, so the default (no
53
+ // ref given) stays byte-identical to before this existed. Kept outside the
54
+ // main component (no closure over its state) so it's a stable reference
55
+ // across renders.
56
+ //
57
+ // #772 fix: every `.crisp-tabletoolbar-*` chrome rule is nested under this
58
+ // recipe's own root class (`& .crisp-tabletoolbar-tool { ... }`), which
59
+ // compiles to a real CSS descendant combinator -- it needs actual DOM
60
+ // containment under an element carrying that class. A portal target
61
+ // rendered by the CONSUMER, outside this component's own root `<div>`,
62
+ // breaks that containment even though React still considers the portaled
63
+ // content a child for event/context purposes: the classes were still
64
+ // applied, they just matched nothing, so the buttons rendered as unstyled
65
+ // native chrome. Same failure class `select.recipe.ts`'s own doc comment
66
+ // describes for its listbox portal to `document.body`. Fixed the same way
67
+ // `ToolbarTool` (below) already lets a bare `.crisp-tabletoolbar-tool` be
68
+ // used outside an actual `TableToolbar` tree: wrap the portaled content in
69
+ // its own `tabletoolbarRecipe()`-classed span. `display: contents` on that
70
+ // recipe's own base rule means the wrapper contributes no box of its own,
71
+ // so it changes nothing about layout -- only re-establishes the selector
72
+ // match.
73
+ function ViewBarSlot({ target, children, }) {
74
+ return target
75
+ ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("span", { className: (0, tabletoolbar_recipe_1.tabletoolbarRecipe)(), children: children }), target)
76
+ : children;
77
+ }
48
78
  // #592: shared by every direction-bearing ChevronRight usage below (the
49
79
  // field picker's own disclosure chevron, a flattened search result's
50
80
  // breadcrumb separator, and a filter chip's own breadcrumb separator) so
@@ -338,7 +368,7 @@ function applySorts(rows, sorts, get = (row, key) => row[key]) {
338
368
  * this (Sort: Due date/Assignee/Creation date; Filter: Assignee/Record/
339
369
  * Created by), which one shared list can't reproduce.
340
370
  */
341
- function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: filterColumnsProp, sorts: sortsProp, defaultSorts, onSortsChange, filters: filtersProp, defaultFilters, onFiltersChange, count, children, helpHref, className, sortLabel: sortLabelProp, filterLabel: filterLabelProp, reorderSortLabel: reorderSortLabelProp, noSortsLabel: noSortsLabelProp, addSortLabel: addSortLabelProp, learnSortingLabel: learnSortingLabelProp, selectConditionLabel: selectConditionLabelProp, sortFieldLabel: sortFieldLabelProp, sortDirectionLabel: sortDirectionLabelProp, removeSortLabel: removeSortLabelProp, filterFieldLabel: filterFieldLabelProp, filterFieldPlaceholder: filterFieldPlaceholderProp, filterValuePlaceholder: filterValuePlaceholderProp, filterOptionsLabel: filterOptionsLabelProp, deleteFilterLabel: deleteFilterLabelProp, ascendingLabel: ascendingLabelProp, descendingLabel: descendingLabelProp, sortTriggerLabel, filterTriggerLabel, inline, showSort = true, showViewSettings = true, viewColumns: viewColumnsProp, shownKeys: shownKeysProp, defaultShownKeys, onShownKeysChange, viewSettingsLabel: viewSettingsLabelProp, reorderAttributeLabel: reorderAttributeLabelProp, hideAttributeLabel, addAttributeToViewLabel: addAttributeToViewLabelProp, searchAttributesPlaceholder: searchAttributesPlaceholderProp, importExportLabel: importExportLabelProp, onImportCsv, onExportCsv, onExportExcel, importExportHelpHref, importCsvLabel: importCsvLabelProp, exportCsvLabel: exportCsvLabelProp, exportExcelLabel: exportExcelLabelProp, learnImportExportLabel: learnImportExportLabelProp, backLabel: backLabelProp, nestedFieldPlaceholder, ...rest }) {
371
+ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: filterColumnsProp, sorts: sortsProp, defaultSorts, onSortsChange, filters: filtersProp, defaultFilters, onFiltersChange, count, children, helpHref, className, sortLabel: sortLabelProp, filterLabel: filterLabelProp, reorderSortLabel: reorderSortLabelProp, noSortsLabel: noSortsLabelProp, addSortLabel: addSortLabelProp, learnSortingLabel: learnSortingLabelProp, selectConditionLabel: selectConditionLabelProp, sortFieldLabel: sortFieldLabelProp, sortDirectionLabel: sortDirectionLabelProp, removeSortLabel: removeSortLabelProp, filterFieldLabel: filterFieldLabelProp, filterFieldPlaceholder: filterFieldPlaceholderProp, filterValuePlaceholder: filterValuePlaceholderProp, filterOptionsLabel: filterOptionsLabelProp, deleteFilterLabel: deleteFilterLabelProp, ascendingLabel: ascendingLabelProp, descendingLabel: descendingLabelProp, sortTriggerLabel, filterTriggerLabel, inline, showSort = true, showViewSettings = true, viewSettingsRef, importExportRef, viewColumns: viewColumnsProp, shownKeys: shownKeysProp, defaultShownKeys, onShownKeysChange, viewSettingsLabel: viewSettingsLabelProp, reorderAttributeLabel: reorderAttributeLabelProp, hideAttributeLabel, addAttributeToViewLabel: addAttributeToViewLabelProp, searchAttributesPlaceholder: searchAttributesPlaceholderProp, importExportLabel: importExportLabelProp, onImportCsv, onExportCsv, onExportExcel, importExportHelpHref, importCsvLabel: importCsvLabelProp, exportCsvLabel: exportCsvLabelProp, exportExcelLabel: exportExcelLabelProp, learnImportExportLabel: learnImportExportLabelProp, backLabel: backLabelProp, nestedFieldPlaceholder, ...rest }) {
342
372
  // crisp/#471: an explicit prop always wins; missing, it reads the nearest
343
373
  // CrispMessagesProvider's translation of the English default below, or
344
374
  // that default itself with no provider — unchanged from before this
@@ -408,6 +438,19 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
408
438
  setShownKeysState(next);
409
439
  onShownKeysChange?.(next);
410
440
  };
441
+ // crisp/#766: a ref's `.current` is null during THIS render (a ref only
442
+ // attaches during commit, and the consumer's own target element may not
443
+ // even exist in the DOM yet on first paint) -- an effect after mount picks
444
+ // it up and re-renders once, the same one-render-late pattern the floating
445
+ // popovers elsewhere in this file already use for a portal target.
446
+ const [viewSettingsTarget, setViewSettingsTarget] = React.useState(null);
447
+ React.useEffect(() => {
448
+ setViewSettingsTarget(viewSettingsRef?.current ?? null);
449
+ }, [viewSettingsRef]);
450
+ const [importExportTarget, setImportExportTarget] = React.useState(null);
451
+ React.useEffect(() => {
452
+ setImportExportTarget(importExportRef?.current ?? null);
453
+ }, [importExportRef]);
411
454
  const [openMenu, setOpenMenu] = React.useState(null);
412
455
  const [dragSort, setDragSort] = React.useState(null);
413
456
  const [filterQuery, setFilterQuery] = React.useState("");
@@ -416,6 +459,12 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
416
459
  // [team, company] is Team -> Company, etc. Reset to [] wherever
417
460
  // `filterQuery` already resets (opening the picker fresh), same lifetime.
418
461
  const [fieldPickerPath, setFieldPickerPath] = React.useState([]);
462
+ // #754: which sort row's own field picker is open (its index into
463
+ // `sorts`), or `null` for the normal sort-row list — the same
464
+ // "one sub-screen behind a flag" split View settings' own
465
+ // `addingAttribute` already uses, parameterized by index since more than
466
+ // one sort row exists.
467
+ const [sortFieldPickerIndex, setSortFieldPickerIndex] = React.useState(null);
419
468
  // filters the "isanyof" checkbox list, same lifetime as filterQuery above
420
469
  const [anyOfQuery, setAnyOfQuery] = React.useState("");
421
470
  const [dragAttr, setDragAttr] = React.useState(null);
@@ -429,7 +478,6 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
429
478
  // built here -- hiding an attribute is a trailing control instead, see
430
479
  // the hide button below).
431
480
  const [addingAttribute, setAddingAttribute] = React.useState(false);
432
- const [addAttrQuery, setAddAttrQuery] = React.useState("");
433
481
  // close any open menu on outside click (anything not inside a menu or its
434
482
  // trigger) or Escape
435
483
  React.useEffect(() => {
@@ -512,10 +560,27 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
512
560
  };
513
561
  // #590: shown attributes, in `shownKeys`' order -- a key with no matching
514
562
  // `viewColumns` entry (stale state after a column is removed upstream)
515
- // drops out rather than rendering a blank row.
516
- const shownAttrs = shownKeys
517
- .map((k) => viewColumns.find((c) => c.key === k))
518
- .filter((c) => c != null);
563
+ // drops out rather than rendering a blank row. #754: `shownKeys` can now
564
+ // carry a dot-joined nested path ("team.jobTitle") from the add-attribute
565
+ // screen's own nested picker, so each key resolves via the same
566
+ // `resolveColumnPath` the filter chip uses -- the LEAF column's icon
567
+ // drives the row's own icon, and the label is the full breadcrumb
568
+ // ("Team › Job title"), joined as plain text rather than the chip's own
569
+ // muted/chevron treatment, which was measured specifically for the
570
+ // filter chip and wasn't re-verified for this row shape.
571
+ const shownAttrs = shownKeys.flatMap((k) => {
572
+ const path = resolveColumnPath(viewColumns, k);
573
+ const leaf = path.at(-1);
574
+ if (!leaf)
575
+ return [];
576
+ return [
577
+ {
578
+ key: k,
579
+ icon: leaf.icon,
580
+ label: path.length > 1 ? path.map((c) => c.label).join(" › ") : leaf.label,
581
+ },
582
+ ];
583
+ });
519
584
  const hiddenAttrs = viewColumns.filter((c) => !shownKeys.includes(c.key));
520
585
  const moveAttr = (from, to) => {
521
586
  if (from === to)
@@ -529,7 +594,8 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
529
594
  const showAttr = (key) => {
530
595
  putShownKeys([...shownKeys, key]);
531
596
  setAddingAttribute(false);
532
- setAddAttrQuery("");
597
+ setFieldPickerPath([]);
598
+ setFilterQuery("");
533
599
  };
534
600
  // #594: the filter chip's kebab is a real role="menu" (crisp/#188's shared
535
601
  // model — arrows, Home/End, typeahead, Escape), not a hand-rolled div like
@@ -562,15 +628,20 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
562
628
  close: () => setOpenMenu(null),
563
629
  contentRef: importExportMenuRef,
564
630
  });
565
- // Shared between the "Filter" trigger's own add-condition picker and each
566
- // chip's field segment (#462 follow-up) — both search the same
567
- // `filterColumns` list and differ only in what a pick does. #592: also
568
- // handles drilling into a `nestedColumns` column — `fieldPickerPath`
569
- // tracks the current scope ([] is the top level), reset to [] wherever
570
- // the picker opens fresh (both trigger onClicks, above).
571
- const filterFieldPicker = (onSelect) => {
631
+ // #754: generalized from the Filter-only `filterFieldPicker` (#592) to
632
+ // also drive Sort's own field picker and View settings' add-attribute
633
+ // screen — all three offer the identical nested-drill-down construct on
634
+ // live Attio (confirmed: "Team" with a count badge appears, and drills
635
+ // into the same People-attribute screen, in all three pickers). Shared
636
+ // `fieldPickerPath`/`filterQuery` state across all three call sites is
637
+ // safe: `openMenu` already only ever names ONE open popover at a time,
638
+ // so only one of Filter/Sort/View-settings' own picker can be showing.
639
+ // `fieldPickerPath` tracks the current scope ([] is the top level),
640
+ // reset to [] wherever a picker opens fresh (every trigger's own
641
+ // onClick).
642
+ const nestedFieldPicker = (columns, onSelect, topLevelPlaceholder, topLevelLabel) => {
572
643
  const scope = fieldPickerPath.at(-1);
573
- const scopeColumns = scope ? (scope.nestedColumns ?? []) : filterColumns;
644
+ const scopeColumns = scope ? (scope.nestedColumns ?? []) : columns;
574
645
  const query = filterQuery.trim().toLowerCase();
575
646
  const direct = scopeColumns.filter((c) => c.label.toLowerCase().includes(query));
576
647
  // #592: one level of flattening from wherever the picker is currently
@@ -598,9 +669,9 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
598
669
  setFilterQuery("");
599
670
  }, children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronLeft, { "data-rtl-flip": "", size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("input", { className: "crisp-tabletoolbar-menu-input", placeholder: nestedFieldPlaceholder
600
671
  ? nestedFieldPlaceholder(scope.nestedObjectLabel ?? scope.label.toLowerCase())
601
- : `Search ${scope.nestedObjectLabel ?? scope.label.toLowerCase()} attributes…`, "aria-label": filterFieldLabel,
672
+ : `Search ${scope.nestedObjectLabel ?? scope.label.toLowerCase()} attributes…`, "aria-label": topLevelLabel,
602
673
  // biome-ignore lint/a11y/noAutofocus: focus the picker on open
603
- autoFocus: true, value: filterQuery, onChange: (e) => setFilterQuery(e.target.value) })] })) : ((0, jsx_runtime_1.jsx)("input", { className: "crisp-tabletoolbar-menu-input", placeholder: filterFieldPlaceholder, "aria-label": filterFieldLabel,
674
+ autoFocus: true, value: filterQuery, onChange: (e) => setFilterQuery(e.target.value) })] })) : ((0, jsx_runtime_1.jsx)("input", { className: "crisp-tabletoolbar-menu-input", placeholder: topLevelPlaceholder, "aria-label": topLevelLabel,
604
675
  // biome-ignore lint/a11y/noAutofocus: focus the picker on open
605
676
  autoFocus: true, value: filterQuery, onChange: (e) => setFilterQuery(e.target.value) })), scope && ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-tabletoolbar-menu-item", onClick: () => selectPath(fieldPickerPath), children: [scope.icon ? ((0, jsx_runtime_1.jsx)(scope.icon, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)("span", { style: { width: 15 } })), scope.label] })), direct.map((col) => col.nestedColumns?.length ? ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-tabletoolbar-menu-item crisp-tabletoolbar-menu-item--expand", onClick: () => drillIn(col), children: [col.icon ? ((0, jsx_runtime_1.jsx)(col.icon, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)("span", { style: { width: 15 } })), col.label, (0, jsx_runtime_1.jsx)(RtlChevronRight, { size: 15, className: "crisp-tabletoolbar-menu-item-chevron" })] }, col.key)) : ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-tabletoolbar-menu-item", onClick: () => selectPath([...fieldPickerPath, col]), children: [col.icon ? ((0, jsx_runtime_1.jsx)(col.icon, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)("span", { style: { width: 15 } })), col.label] }, col.key))), nested.map(({ parent, col }) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-tabletoolbar-menu-item", onClick: () => selectPath([...fieldPickerPath, parent, col]), children: [col.icon ? ((0, jsx_runtime_1.jsx)(col.icon, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)("span", { style: { width: 15 } })), (0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-menu-item-path", children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-menu-item-path-parent", children: parent.label }), (0, jsx_runtime_1.jsx)(RtlChevronRight, { size: 15, className: "crisp-tabletoolbar-menu-item-path-sep" }), (0, jsx_runtime_1.jsx)("span", { children: col.label })] })] }, `${parent.key}.${col.key}`)))] }));
606
677
  };
@@ -613,23 +684,49 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
613
684
  // worse than an imperfect word order); `crispMessages` rather than a
614
685
  // second `useCrispMessage` call, since this only fires on the branch that
615
686
  // needs it.
687
+ // crisp/#788: "Sorted by" and the field name are NOT a font-weight split
688
+ // (both measure 500/medium live) -- the difference is colour/opacity only:
689
+ // "Sorted by" at 63% black, the field name at full-strength near-black
690
+ // (rgb(16,17,18)). The "+N" suffix is smaller (12px vs 14px) and its own
691
+ // mid-grey (rgb(80,81,85)), not muted-63%-black either -- three distinct
692
+ // treatments, not two. `sortField` isolates the resolved label so the
693
+ // default (non-`sortTriggerLabel`) render can wrap each part in its own
694
+ // span; `sortedLabel` stays a single string for the `sortTriggerLabel`
695
+ // escape hatch (a caller-supplied formatter can't be split, by definition)
696
+ // and the empty-state `sortLabel`.
697
+ const sortField = resolveColumnPath(sortColumns, sorts[0]?.key ?? "").at(-1)?.label;
616
698
  const sortedLabel = sortTriggerLabel
617
699
  ? sortTriggerLabel(sorts, sortColumns)
618
700
  : sorts.length
619
- ? `${crispMessages["Sorted by"] ?? "Sorted by"} ${sortColumns.find((c) => c.key === sorts[0].key)?.label}${sorts.length > 1 ? ` +${sorts.length - 1}` : ""}`
701
+ ? `${crispMessages["Sorted by"] ?? "Sorted by"} ${sortField}${sorts.length > 1 ? ` +${sorts.length - 1}` : ""}`
620
702
  : sortLabel;
621
- return ((0, jsx_runtime_1.jsx)("div", { className: (0, tabletoolbar_recipe_1.tabletoolbarRecipe)({ className }), ...rest, children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-tabletoolbar-toolbar", "data-inline": inline ? "" : undefined, children: [showSort && ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-toolgroup", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: `crisp-tabletoolbar-tool${sorts.length ? " crisp-tabletoolbar-tool--active" : ""}`, onClick: () => setOpenMenu(openMenu === "sort" ? null : "sort"), "aria-haspopup": "dialog", "aria-expanded": openMenu === "sort", "data-menu-trigger": true, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ArrowUpDown, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" }), sortedLabel] }), openMenu === "sort" && ((0, jsx_runtime_1.jsxs)("div", { ref: sortListRef, className: "crisp-tabletoolbar-menu crisp-tabletoolbar-sortpop", role: "dialog", "aria-label": sortLabel, children: [sorts.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-sort-empty", children: noSortsLabel })) : (sorts.map((s, i) => ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-tabletoolbar-sort-row", onDragOver: (e) => {
703
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, tabletoolbar_recipe_1.tabletoolbarRecipe)({ className }), ...rest, children: (0, jsx_runtime_1.jsxs)("div", { className: "crisp-tabletoolbar-toolbar", "data-inline": inline ? "" : undefined, children: [showSort && ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-toolgroup", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: `crisp-tabletoolbar-tool${sorts.length ? " crisp-tabletoolbar-tool--active" : " crisp-tabletoolbar-tool--dashed"}`, onClick: () => setOpenMenu(openMenu === "sort" ? null : "sort"), "aria-haspopup": "dialog", "aria-expanded": openMenu === "sort", "data-menu-trigger": true, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ArrowUpDown, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" }), sortTriggerLabel || !sorts.length ? (sortedLabel) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-sorted-prefix", children: crispMessages["Sorted by"] ?? "Sorted by" }), " ", (0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-sorted-field", children: sortField }), sorts.length > 1 && ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-sorted-count", children: [" ", "+", sorts.length - 1] }))] }))] }), openMenu === "sort" && ((0, jsx_runtime_1.jsxs)("div", { ref: sortListRef, className: "crisp-tabletoolbar-menu crisp-tabletoolbar-sortpop", role: "dialog", "aria-label": sortLabel, children: [sorts.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-sort-empty", children: noSortsLabel })) : (sorts.map((s, i) => ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-tabletoolbar-sort-row", onDragOver: (e) => {
622
704
  if (dragSort !== null)
623
705
  e.preventDefault();
624
706
  }, onDrop: () => {
625
707
  if (dragSort !== null)
626
708
  moveSort(dragSort, i);
627
709
  setDragSort(null);
628
- }, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-tabletoolbar-sort-grip", "aria-label": reorderSortLabel, draggable: true, onDragStart: () => setDragSort(i), onDragEnd: () => setDragSort(null), children: (0, jsx_runtime_1.jsx)(lucide_react_1.GripVertical, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)(select_1.Select, { className: "crisp-tabletoolbar-sort-field", searchable: true, value: s.key, onValueChange: (k) => setSortField(i, k), options: sortColumns.map((c) => ({
629
- value: c.key,
630
- label: c.icon ? ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-sort-optlabel", children: [(0, jsx_runtime_1.jsx)(c.icon, { size: 15, strokeWidth: 1.75 }), c.label] })) : (c.label),
631
- keywords: c.label,
632
- })), "aria-label": sortFieldLabel }), (0, jsx_runtime_1.jsx)(select_1.Select, { className: "crisp-tabletoolbar-sort-dir", value: s.dir, onValueChange: (d) => setSortDir(i, d), options: [
710
+ }, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-tabletoolbar-sort-grip", "aria-label": reorderSortLabel, draggable: true, onDragStart: () => setDragSort(i), onDragEnd: () => setDragSort(null), children: (0, jsx_runtime_1.jsx)(lucide_react_1.GripVertical, { size: 15, strokeWidth: 1.75 }) }), (() => {
711
+ // #754: the sort row's own field picker -- the
712
+ // same nested-drill-down construct Filter's field
713
+ // picker already has (#592), measured live:
714
+ // clicking a sort row's field (or "Add sort") opens
715
+ // an identical picker, "Team" (a relationship
716
+ // field) drills into the same People-attribute
717
+ // screen Filter's own "Team" does.
718
+ const sortColPath = resolveColumnPath(sortColumns, s.key);
719
+ const sortCol = sortColPath.at(-1);
720
+ const pickerOpen = sortFieldPickerIndex === i;
721
+ return ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-sort-field-picker", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-tabletoolbar-sort-field-trigger", "aria-haspopup": "dialog", "aria-expanded": pickerOpen, "aria-label": sortFieldLabel, onClick: () => {
722
+ setFieldPickerPath([]);
723
+ setFilterQuery("");
724
+ setSortFieldPickerIndex(pickerOpen ? null : i);
725
+ }, children: [sortCol?.icon ? ((0, jsx_runtime_1.jsx)(sortCol.icon, { size: 15, strokeWidth: 1.75 })) : null, sortColPath.length > 1 ? ((0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-fcond-path", children: sortColPath.map((c, pi) => ((0, jsx_runtime_1.jsxs)(React.Fragment, { children: [pi > 0 && ((0, jsx_runtime_1.jsx)(RtlChevronRight, { size: 14, className: "crisp-tabletoolbar-fcond-path-sep" })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-fcond-path-seg", children: c.label })] }, c.key))) })) : ((0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-sort-field-label", children: sortCol?.label }))] }), pickerOpen && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-menu", role: "dialog", "aria-label": sortFieldLabel, children: nestedFieldPicker(sortColumns, (key) => {
726
+ setSortField(i, key);
727
+ setSortFieldPickerIndex(null);
728
+ }, searchAttributesPlaceholder, sortFieldLabel) }))] }));
729
+ })(), (0, jsx_runtime_1.jsx)(select_1.Select, { className: "crisp-tabletoolbar-sort-dir", value: s.dir, onValueChange: (d) => setSortDir(i, d), options: [
633
730
  {
634
731
  value: "asc",
635
732
  label: ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-sort-optlabel", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ArrowUpNarrowWide, { size: 15, strokeWidth: 1.75 }), ascendingLabel] })),
@@ -640,14 +737,14 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
640
737
  label: ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-sort-optlabel", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDownWideNarrow, { size: 15, strokeWidth: 1.75 }), descendingLabel] })),
641
738
  keywords: descendingLabel,
642
739
  },
643
- ], "aria-label": sortDirectionLabel }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-tabletoolbar-sort-remove", onClick: () => removeSort(i), "aria-label": removeSortLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 15, strokeWidth: 1.75 }) })] }, s.key)))), (0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-sort-addrow", children: (0, jsx_runtime_1.jsxs)("button", { ref: addSortRef, type: "button", className: "crisp-tabletoolbar-sort-add", onClick: addSort, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), addSortLabel] }) }), helpHref && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-sort-foot", children: (0, jsx_runtime_1.jsxs)("a", { className: "crisp-tabletoolbar-sort-learn", href: helpHref, target: "_blank", rel: "noreferrer", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CircleHelp, { size: 14, strokeWidth: 1.75 }), learnSortingLabel] }) }))] }))] })), showSort && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-divider", "aria-hidden": "true" })), (0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-toolgroup", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: `crisp-tabletoolbar-tool crisp-tabletoolbar-tool--ghost${activeFilters ? " crisp-tabletoolbar-tool--active" : ""}`, onClick: () => {
740
+ ], "aria-label": sortDirectionLabel }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-tabletoolbar-sort-remove", onClick: () => removeSort(i), "aria-label": removeSortLabel, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 15, strokeWidth: 1.75 }) })] }, s.key)))), (0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-sort-addrow", children: (0, jsx_runtime_1.jsxs)("button", { ref: addSortRef, type: "button", className: "crisp-tabletoolbar-sort-add", onClick: addSort, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), addSortLabel] }) }), helpHref && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-sort-foot", children: (0, jsx_runtime_1.jsxs)("a", { className: "crisp-tabletoolbar-sort-learn", href: helpHref, target: "_blank", rel: "noreferrer", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CircleHelp, { size: 14, strokeWidth: 1.75 }), learnSortingLabel] }) }))] }))] })), showSort && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-divider", "aria-hidden": "true" })), (0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-toolgroup", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: `crisp-tabletoolbar-tool${activeFilters ? " crisp-tabletoolbar-tool--active" : " crisp-tabletoolbar-tool--dashed"}`, onClick: () => {
644
741
  setFieldPickerPath([]);
645
742
  setOpenMenu(openMenu === "filter" ? null : "filter");
646
743
  }, "aria-haspopup": "dialog", "aria-expanded": openMenu === "filter", "data-menu-trigger": true, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ListFilter, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" }), filterTriggerLabel
647
744
  ? filterTriggerLabel(activeFilters)
648
745
  : activeFilters
649
746
  ? `${filterLabel} · ${activeFilters}`
650
- : filterLabel] }), openMenu === "filter" && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-menu", role: "dialog", "aria-label": filterFieldLabel, children: filterFieldPicker(addFilter) }))] }), filters.map((cond) => {
747
+ : filterLabel] }), openMenu === "filter" && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-menu", role: "dialog", "aria-label": filterFieldLabel, children: nestedFieldPicker(filterColumns, addFilter, filterFieldPlaceholder, filterFieldLabel) }))] }), filters.map((cond) => {
651
748
  // #592: cond.key may be a dot-joined nested path
652
749
  // ("team.twitterFollowerCount") — resolve the full path so the
653
750
  // field segment can render its breadcrumb; `col` (the leaf) still
@@ -683,7 +780,7 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
683
780
  ? col?.type === "date"
684
781
  ? formatFilterDate(cond.value)
685
782
  : cond.value
686
- : filterValuePlaceholder })), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-tabletoolbar-fcond-seg crisp-tabletoolbar-fcond-seg--kebab", "data-menu-trigger": true, "aria-haspopup": "menu", "aria-expanded": kebabOpen, "aria-label": `${col?.label} ${filterOptionsLabel}`, onClick: () => setOpenMenu(kebabOpen ? null : `fkebab:${cond.id}`), children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreVertical, { size: 13, strokeWidth: 2 }) })] }), kebabOpen && ((0, jsx_runtime_1.jsx)("div", { ref: kebabMenuRef, className: "crisp-tabletoolbar-menu crisp-tabletoolbar-menu--right crisp-tabletoolbar-menu--hdr", role: "menu", "aria-label": `${col?.label} ${filterOptionsLabel}`, onKeyDown: onKebabKeyDown, children: (0, jsx_runtime_1.jsxs)("button", { type: "button", role: "menuitem", className: "crisp-tabletoolbar-menu-item crisp-tabletoolbar-menu-item--danger", onClick: () => removeFilter(cond.id), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 16, strokeWidth: 1.75 }), deleteFilterLabel] }) })), fieldOpen && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-menu", role: "dialog", "aria-label": filterFieldLabel, children: filterFieldPicker((key) => changeFilterField(cond.id, key)) })), opOpen && ((0, jsx_runtime_1.jsx)("div", { ref: opMenuRef, className: "crisp-tabletoolbar-menu crisp-tabletoolbar-menu--op", role: "menu", "aria-label": `${col?.label} ${crispMessages.condition ?? "condition"}`, onKeyDown: onOpKeyDown, children: opsFor(col).map((op) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "menuitem", className: "crisp-tabletoolbar-menu-item", "data-on": cond.op === op ? "" : undefined, onClick: () => pickOp(cond.id, op), children: [crispMessages[OP_LABELS[op]] ?? OP_LABELS[op], cond.op === op ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Check, { className: "crisp-tabletoolbar-menu-check", size: 15, strokeWidth: 1.75 })) : null] }, op))) })), valOpen && showValueSeg && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-menu crisp-tabletoolbar-menu--val", role: "dialog", "aria-label": `${col?.label} filter value`, children: cond.op === "isanyof" && col?.values ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("input", { className: "crisp-tabletoolbar-menu-input", placeholder: filterValuePlaceholder, "aria-label": `${col?.label} filter values`,
783
+ : filterValuePlaceholder })), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-tabletoolbar-fcond-seg crisp-tabletoolbar-fcond-seg--kebab", "data-menu-trigger": true, "aria-haspopup": "menu", "aria-expanded": kebabOpen, "aria-label": `${col?.label} ${filterOptionsLabel}`, onClick: () => setOpenMenu(kebabOpen ? null : `fkebab:${cond.id}`), children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreVertical, { size: 13, strokeWidth: 2 }) })] }), kebabOpen && ((0, jsx_runtime_1.jsx)("div", { ref: kebabMenuRef, className: "crisp-tabletoolbar-menu crisp-tabletoolbar-menu--right crisp-tabletoolbar-menu--hdr", role: "menu", "aria-label": `${col?.label} ${filterOptionsLabel}`, onKeyDown: onKebabKeyDown, children: (0, jsx_runtime_1.jsxs)("button", { type: "button", role: "menuitem", className: "crisp-tabletoolbar-menu-item crisp-tabletoolbar-menu-item--danger", onClick: () => removeFilter(cond.id), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 16, strokeWidth: 1.75 }), deleteFilterLabel] }) })), fieldOpen && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-menu", role: "dialog", "aria-label": filterFieldLabel, children: nestedFieldPicker(filterColumns, (key) => changeFilterField(cond.id, key), filterFieldPlaceholder, filterFieldLabel) })), opOpen && ((0, jsx_runtime_1.jsx)("div", { ref: opMenuRef, className: "crisp-tabletoolbar-menu crisp-tabletoolbar-menu--op", role: "menu", "aria-label": `${col?.label} ${crispMessages.condition ?? "condition"}`, onKeyDown: onOpKeyDown, children: opsFor(col).map((op) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "menuitem", className: "crisp-tabletoolbar-menu-item", "data-on": cond.op === op ? "" : undefined, onClick: () => pickOp(cond.id, op), children: [crispMessages[OP_LABELS[op]] ?? OP_LABELS[op], cond.op === op ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Check, { className: "crisp-tabletoolbar-menu-check", size: 15, strokeWidth: 1.75 })) : null] }, op))) })), valOpen && showValueSeg && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-menu crisp-tabletoolbar-menu--val", role: "dialog", "aria-label": `${col?.label} filter value`, children: cond.op === "isanyof" && col?.values ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("input", { className: "crisp-tabletoolbar-menu-input", placeholder: filterValuePlaceholder, "aria-label": `${col?.label} filter values`,
687
784
  // biome-ignore lint/a11y/noAutofocus: focus the search field
688
785
  autoFocus: true, value: anyOfQuery, onChange: (e) => setAnyOfQuery(e.target.value) }), col.values
689
786
  .filter((v) => v
@@ -739,44 +836,43 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
739
836
  }, children: label }, label))) })] })) : ((0, jsx_runtime_1.jsx)("input", { className: "crisp-tabletoolbar-menu-input", type: col?.type === "number" ? "number" : "text", placeholder: filterValuePlaceholder, "aria-label": `${col?.label} filter value`,
740
837
  // biome-ignore lint/a11y/noAutofocus: focus the value field
741
838
  autoFocus: true, value: cond.value, onChange: (e) => patchFilter(cond.id, { value: e.target.value }) })) }))] }, cond.id));
742
- }), showViewSettings && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-divider", "aria-hidden": "true" })), showViewSettings && ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-toolgroup", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-tabletoolbar-tool crisp-tabletoolbar-tool--ghost", onClick: () => {
743
- if (openMenu === "viewsettings") {
744
- setOpenMenu(null);
745
- }
746
- else {
747
- setAddingAttribute(false);
748
- setAddAttrQuery("");
749
- setOpenMenu("viewsettings");
750
- }
751
- }, "aria-haspopup": "dialog", "aria-expanded": openMenu === "viewsettings", "data-menu-trigger": true, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.SlidersHorizontal, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" }), viewSettingsLabel] }), openMenu === "viewsettings" &&
752
- (addingAttribute ? ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-tabletoolbar-menu", role: "dialog", "aria-label": addAttributeToViewLabel, children: [(0, jsx_runtime_1.jsx)("input", { className: "crisp-tabletoolbar-menu-input", placeholder: searchAttributesPlaceholder, "aria-label": searchAttributesPlaceholder,
753
- // biome-ignore lint/a11y/noAutofocus: focus the search box on open, same as Filter's field picker
754
- autoFocus: true, value: addAttrQuery, onChange: (e) => setAddAttrQuery(e.target.value) }), hiddenAttrs
755
- .filter((col) => col.label
756
- .toLowerCase()
757
- .includes(addAttrQuery.trim().toLowerCase()))
758
- .map((col) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-tabletoolbar-menu-item", onClick: () => showAttr(col.key), children: [col.icon ? ((0, jsx_runtime_1.jsx)(col.icon, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)("span", { style: { width: 15 } })), col.label] }, col.key)))] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-tabletoolbar-menu crisp-tabletoolbar-sortpop", role: "dialog", "aria-label": viewSettingsLabel, children: [shownAttrs.map((col, i) => ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-tabletoolbar-sort-row", onDragOver: (e) => {
759
- if (dragAttr !== null)
760
- e.preventDefault();
761
- }, onDrop: () => {
762
- if (dragAttr !== null)
763
- moveAttr(dragAttr, i);
764
- setDragAttr(null);
765
- }, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-tabletoolbar-sort-grip", "aria-label": reorderAttributeLabel, draggable: true, onDragStart: () => setDragAttr(i), onDragEnd: () => setDragAttr(null), children: (0, jsx_runtime_1.jsx)(lucide_react_1.GripVertical, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-sort-optlabel crisp-tabletoolbar-sort-field", children: [col.icon ? ((0, jsx_runtime_1.jsx)(col.icon, { size: 15, strokeWidth: 1.75 })) : null, col.label] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-tabletoolbar-sort-remove", onClick: () => hideAttr(col.key), "aria-label": hideAttributeLabel?.(col.label) ??
766
- `${crispMessages.Hide ?? "Hide"} ${col.label} ${crispMessages["from view"] ?? "from view"}`, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 15, strokeWidth: 1.75 }) })] }, col.key))), (0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-sort-addrow", children: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-tabletoolbar-sort-add", onClick: () => setAddingAttribute(true), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), addAttributeToViewLabel] }) })] })))] })), (onImportCsv ||
839
+ }), showViewSettings && !viewSettingsTarget && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-divider", "aria-hidden": "true" })), showViewSettings && ((0, jsx_runtime_1.jsx)(ViewBarSlot, { target: viewSettingsTarget, children: (0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-toolgroup", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-tabletoolbar-tool crisp-tabletoolbar-tool--raised", onClick: () => {
840
+ if (openMenu === "viewsettings") {
841
+ setOpenMenu(null);
842
+ }
843
+ else {
844
+ setAddingAttribute(false);
845
+ setFieldPickerPath([]);
846
+ setFilterQuery("");
847
+ setOpenMenu("viewsettings");
848
+ }
849
+ }, "aria-haspopup": "dialog", "aria-expanded": openMenu === "viewsettings", "data-menu-trigger": true, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.SlidersHorizontal, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" }), viewSettingsLabel, (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" })] }), openMenu === "viewsettings" &&
850
+ (addingAttribute ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-menu", role: "dialog", "aria-label": addAttributeToViewLabel, children: nestedFieldPicker(hiddenAttrs, showAttr, searchAttributesPlaceholder, searchAttributesPlaceholder) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-tabletoolbar-menu crisp-tabletoolbar-sortpop", role: "dialog", "aria-label": viewSettingsLabel, children: [shownAttrs.map((col, i) => ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-tabletoolbar-sort-row", onDragOver: (e) => {
851
+ if (dragAttr !== null)
852
+ e.preventDefault();
853
+ }, onDrop: () => {
854
+ if (dragAttr !== null)
855
+ moveAttr(dragAttr, i);
856
+ setDragAttr(null);
857
+ }, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-tabletoolbar-sort-grip", "aria-label": reorderAttributeLabel, draggable: true, onDragStart: () => setDragAttr(i), onDragEnd: () => setDragAttr(null), children: (0, jsx_runtime_1.jsx)(lucide_react_1.GripVertical, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-sort-optlabel crisp-tabletoolbar-sort-field", children: [col.icon ? ((0, jsx_runtime_1.jsx)(col.icon, { size: 15, strokeWidth: 1.75 })) : null, col.label] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-tabletoolbar-sort-remove", onClick: () => hideAttr(col.key), "aria-label": hideAttributeLabel?.(col.label) ??
858
+ `${crispMessages.Hide ?? "Hide"} ${col.label} ${crispMessages["from view"] ?? "from view"}`, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 15, strokeWidth: 1.75 }) })] }, col.key))), (0, jsx_runtime_1.jsx)("div", { className: "crisp-tabletoolbar-sort-addrow", children: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-tabletoolbar-sort-add", onClick: () => {
859
+ setAddingAttribute(true);
860
+ setFieldPickerPath([]);
861
+ setFilterQuery("");
862
+ }, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), addAttributeToViewLabel] }) })] })))] }) })), (onImportCsv ||
767
863
  onExportCsv ||
768
864
  onExportExcel ||
769
- importExportHelpHref) && ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-toolgroup", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-tabletoolbar-tool crisp-tabletoolbar-tool--raised", onClick: () => setOpenMenu(openMenu === "importexport" ? null : "importexport"), "aria-haspopup": "menu", "aria-expanded": openMenu === "importexport", "data-menu-trigger": true, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Upload, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" }), importExportLabel, (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" })] }), openMenu === "importexport" && ((0, jsx_runtime_1.jsxs)("div", { ref: importExportMenuRef, className: "crisp-tabletoolbar-menu", role: "menu", "aria-label": importExportLabel, onKeyDown: onImportExportKeyDown, children: [onImportCsv && ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "menuitem", className: "crisp-tabletoolbar-menu-item", onClick: () => {
770
- onImportCsv();
771
- setOpenMenu(null);
772
- }, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Upload, { size: 15, strokeWidth: 1.75 }), importCsvLabel] })), onImportCsv && (onExportCsv || onExportExcel) && ((0, jsx_runtime_1.jsx)("hr", { className: "crisp-tabletoolbar-menu-sep" })), onExportCsv && ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "menuitem", className: "crisp-tabletoolbar-menu-item", onClick: () => {
773
- onExportCsv();
774
- setOpenMenu(null);
775
- }, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Download, { size: 15, strokeWidth: 1.75 }), exportCsvLabel] })), onExportExcel && ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "menuitem", className: "crisp-tabletoolbar-menu-item", onClick: () => {
776
- onExportExcel();
777
- setOpenMenu(null);
778
- }, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Download, { size: 15, strokeWidth: 1.75 }), exportExcelLabel] })), importExportHelpHref &&
779
- (onImportCsv || onExportCsv || onExportExcel) && ((0, jsx_runtime_1.jsx)("hr", { className: "crisp-tabletoolbar-menu-sep" })), importExportHelpHref && ((0, jsx_runtime_1.jsxs)("a", { className: "crisp-tabletoolbar-menu-item", role: "menuitem", href: importExportHelpHref, target: "_blank", rel: "noreferrer", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CircleHelp, { size: 15, strokeWidth: 1.75 }), learnImportExportLabel] }))] }))] })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-spacer" }), count != null && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-count", children: count })), children] }) }));
865
+ importExportHelpHref) && ((0, jsx_runtime_1.jsx)(ViewBarSlot, { target: importExportTarget, children: (0, jsx_runtime_1.jsxs)("span", { className: "crisp-tabletoolbar-toolgroup", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-tabletoolbar-tool crisp-tabletoolbar-tool--raised", onClick: () => setOpenMenu(openMenu === "importexport" ? null : "importexport"), "aria-haspopup": "menu", "aria-expanded": openMenu === "importexport", "data-menu-trigger": true, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Upload, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" }), importExportLabel, (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { size: 14, strokeWidth: 1.75, "aria-hidden": "true" })] }), openMenu === "importexport" && ((0, jsx_runtime_1.jsxs)("div", { ref: importExportMenuRef, className: "crisp-tabletoolbar-menu", role: "menu", "aria-label": importExportLabel, onKeyDown: onImportExportKeyDown, children: [onImportCsv && ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "menuitem", className: "crisp-tabletoolbar-menu-item", onClick: () => {
866
+ onImportCsv();
867
+ setOpenMenu(null);
868
+ }, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Upload, { size: 15, strokeWidth: 1.75 }), importCsvLabel] })), onImportCsv && (onExportCsv || onExportExcel) && ((0, jsx_runtime_1.jsx)("hr", { className: "crisp-tabletoolbar-menu-sep" })), onExportCsv && ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "menuitem", className: "crisp-tabletoolbar-menu-item", onClick: () => {
869
+ onExportCsv();
870
+ setOpenMenu(null);
871
+ }, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Download, { size: 15, strokeWidth: 1.75 }), exportCsvLabel] })), onExportExcel && ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "menuitem", className: "crisp-tabletoolbar-menu-item", onClick: () => {
872
+ onExportExcel();
873
+ setOpenMenu(null);
874
+ }, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Download, { size: 15, strokeWidth: 1.75 }), exportExcelLabel] })), importExportHelpHref &&
875
+ (onImportCsv || onExportCsv || onExportExcel) && ((0, jsx_runtime_1.jsx)("hr", { className: "crisp-tabletoolbar-menu-sep" })), importExportHelpHref && ((0, jsx_runtime_1.jsxs)("a", { className: "crisp-tabletoolbar-menu-item", role: "menuitem", href: importExportHelpHref, target: "_blank", rel: "noreferrer", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CircleHelp, { size: 15, strokeWidth: 1.75 }), learnImportExportLabel] }))] }))] }) })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-spacer" }), count != null && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-tabletoolbar-count", children: count })), children] }) }));
780
876
  }
781
877
  /**
782
878
  * The Sort/Filter chip's own chrome (`.crisp-tabletoolbar-tool`), standalone
@@ -56,19 +56,39 @@ const filterChipChrome = `
56
56
  & .crisp-tabletoolbar-fcond-seg--val { font-weight: ${tokens_1.contract.weight.medium}; max-width: 140px; overflow: hidden; text-overflow: ellipsis; }
57
57
  & .crisp-tabletoolbar-fcond-seg--kebab { background: ${tokens_1.contract.bgSurface}; justify-content: center; width: 28px; padding: 0; border-radius: 0 ${tokens_1.contract.radius.md} ${tokens_1.contract.radius.md} 0; color: ${tokens_1.contract.fgMuted}; }
58
58
  & .crisp-tabletoolbar-fcond-seg--kebab:hover { color: ${tokens_1.contract.fgPrimary}; }
59
+ /* #754: the sort row's own field trigger, replacing a plain Select
60
+ with the same nested-drill-down popover Filter's field picker
61
+ already has — reuses Select's own already-measured trigger chrome
62
+ verbatim (its class is scoped under Select's own root class, so it
63
+ can't be reused as a bare class name outside an actual Select tree;
64
+ these values are copied, not re-measured). */
65
+ & .crisp-tabletoolbar-sort-field-picker { position: relative; display: inline-flex; flex: 1; min-width: 0; }
66
+ & .crisp-tabletoolbar-sort-field-trigger { box-sizing: border-box; display: inline-flex; align-items: center; gap: ${tokens_1.contract.space["1.5"]}; height: ${tokens_1.contract.size.menuRow}; width: 100%; min-width: 0; margin: 0; padding: 0 ${tokens_1.contract.space["1.5"]} 0 ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.md}; background: transparent; box-shadow: inset 0 0 0 1px color-mix(in srgb, ${tokens_1.contract.fgPrimary} 7%, transparent); font-family: inherit; font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; cursor: pointer; transition: background-color .12s ease, box-shadow .12s ease; }
67
+ & .crisp-tabletoolbar-sort-field-trigger:hover { background: ${tokens_1.contract.bgRaised}; }
68
+ & .crisp-tabletoolbar-sort-field-trigger[aria-expanded="true"],
69
+ & .crisp-tabletoolbar-sort-field-trigger:focus-visible { outline: none; box-shadow: inset 0 0 0 1px ${tokens_1.contract.bgBrandSolid}; background: ${tokens_1.contract.bgSurface}; }
70
+ & .crisp-tabletoolbar-sort-field-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: start; }
71
+ & .crisp-tabletoolbar-sort-field-picker .crisp-tabletoolbar-menu { min-width: 200px; }
59
72
  & .crisp-tabletoolbar-menu--val { min-width: 134px; }
60
73
  & .crisp-tabletoolbar-datepop { width: 300px; }
61
74
  & .crisp-tabletoolbar-datepop-presets { display: flex; flex-wrap: wrap; gap: ${tokens_1.contract.space["1"]}; margin-top: ${tokens_1.contract.space["2"]}; padding: 0 ${tokens_1.contract.space["1"]}; }
62
75
  & .crisp-tabletoolbar-datepop-preset { height: ${tokens_1.contract.size.chip}; padding: 0 ${tokens_1.contract.space["2"]}; border: none; border-radius: ${tokens_1.contract.radius.chip}; background: ${tokens_1.contract.bgRaised}; color: ${tokens_1.contract.fgPrimary}; font-family: inherit; font-size: ${tokens_1.contract.text.sm}; cursor: pointer; }
63
76
  & .crisp-tabletoolbar-datepop-preset:hover { background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 8%, transparent); }`;
64
- // #595: the Import/Export trigger — measured live, `app.attio.com`'s own
65
- // view bar: `28px` tall, `radius.md` (8px), background `bgSurfaceMuted`
66
- // (`rgb(246,247,247)`, exact match) and `elevation.field`'s exact 3-layer
67
- // shadow (`inset 0 0 0 1px transparent, 0 0 2px rgba(28,40,64,.18), 0 1px 3px
68
- // rgba(0,0,0,.04)`) — a "raised chrome button" distinct from Sort/Filter/View
69
- // settings' plain ringed `.tool` (no background, no elevation shadow), and
70
- // the only trigger of the four with a trailing chevron (2 icons total,
71
- // confirmed live). Overrides `.tool`'s own base background/shadow by cascade
77
+ // #595, corrected #772 (re-measured live 2026-09-25): the view bar's raised
78
+ // trigger chrome — `app.attio.com`'s own view bar: `28px` tall, `radius.md`
79
+ // (8px), background `bgSurface` (white, `rgb(255,255,255)` exact match — the
80
+ // #595 pass originally measured `bgSurfaceMuted`/`rgb(246,247,247)`, which
81
+ // re-measuring live this pass shows was wrong, not a later Attio change: ALL
82
+ // THREE of the switcher, View settings and Import/Export read pure white)
83
+ // and `elevation.field`'s exact 3-layer shadow (`inset 0 0 0 1px transparent,
84
+ // 0 0 2px rgba(28,40,64,.18), 0 1px 3px rgba(0,0,0,.04)`) — distinct from
85
+ // Sort/Filter's plain ringed `.tool` (no elevation shadow; see `--dashed` in
86
+ // `tabletoolbar.chrome.ts` for their own OWN empty-state chrome). Originally
87
+ // built for Import/Export alone ("the only trigger... with a trailing
88
+ // chevron") — that was also wrong: View settings and the view switcher both
89
+ // carry one too, confirmed live (3 children each: icon, label, chevron).
90
+ // Now shared by View settings' own trigger (`tabletoolbar.tsx`) as well as
91
+ // Import/Export's. Overrides `.tool`'s own base background/shadow by cascade
72
92
  // order (this block is appended after `toolbarChromeBody`, which defines
73
93
  // them), the same way `.tool--ghost` already does. `border`/`font-family`/
74
94
  // `cursor` are repeated here too, even though `.tool`'s own base rule (in
@@ -78,7 +98,18 @@ const filterChipChrome = `
78
98
  // behind `chrome.ts`'s function call is invisible to it; harmless repeats,
79
99
  // not a real gap.
80
100
  const importExportChrome = `
81
- & .crisp-tabletoolbar-tool--raised { border: none; background: ${tokens_1.contract.bgSurfaceMuted}; box-shadow: ${tokens_1.elevation.field}; font-family: inherit; cursor: pointer; }`;
101
+ & .crisp-tabletoolbar-tool--raised { border: none; background: ${tokens_1.contract.bgSurface}; box-shadow: ${tokens_1.elevation.field}; font-family: inherit; cursor: pointer; }`;
102
+ // crisp/#788: the Sort trigger's own "Sorted by X (+N)" label, measured live
103
+ // against Attio's own chip -- three parts, not one flat string, and NOT a
104
+ // font-weight split (all three read 500/medium): "Sorted by" is muted (63%
105
+ // black), the resolved field name is full-strength near-black, and a
106
+ // trailing "+N" (when more than one sort is active) is both smaller (12px
107
+ // vs 14px) and its own mid-grey, distinct from the "Sorted by" muted tone.
108
+ // TableToolbar-only, same reasoning as `filterChipChrome` above (RecordsTable
109
+ // keeps its own older Sort label markup, not touched here).
110
+ const sortedLabelChrome = `
111
+ & .crisp-tabletoolbar-sorted-prefix { color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 63%, transparent); }
112
+ & .crisp-tabletoolbar-sorted-count { font-size: ${tokens_1.contract.text.sm}; color: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 73%, transparent); }`;
82
113
  // The table toolbar, measured: 28px controls, the Sort/Filter buttons and
83
114
  // the menus they open, sort-condition rows, and the filter chips. The chrome
84
115
  // itself lives in ./tabletoolbar.chrome.ts because RecordsTable renders the
@@ -97,6 +128,7 @@ ${(0, tabletoolbar_chrome_1.toolbarChromeHead)("tabletoolbar")}
97
128
  ${(0, tabletoolbar_chrome_1.toolbarChromeBody)("tabletoolbar")}
98
129
  ${filterChipChrome}
99
130
  ${importExportChrome}
131
+ ${sortedLabelChrome}
100
132
  ${core_1.rtlFlipCss}
101
133
  `,
102
134
  });
@@ -13,13 +13,23 @@ const tokens_1 = require("../../tokens");
13
13
  // the same reason (see its own doc).
14
14
  const spec = (0, core_1.defineSpec)({
15
15
  name: "text",
16
- // `display: inline` -- a span's own default, stated rather than left
17
- // implicit: an EMPTY base compiles to an empty string, and
18
- // `core/resolve.ts`'s `if (base) classes.push(prefixedName)` treats that
19
- // falsy string as "no base rule", which drops the `crisp-text` class
20
- // itself, silently, from every instance (caught by this file's own
21
- // tests going red on that exact class).
22
- base: { display: "inline" },
16
+ // Needs a real, always-present declaration so `resolveRecipe` emits the
17
+ // `crisp-text` class at all -- an EMPTY base compiles to an empty string,
18
+ // and `core/resolve.ts`'s `if (base) classes.push(prefixedName)` treats
19
+ // that falsy string as "no base rule", dropping the class itself,
20
+ // silently, from every instance (this file's own tests catch that).
21
+ // `display: "inline"` filled that role until a real bug: `asChild`
22
+ // (Primitive.span -> Radix Slot) merges this class onto WHATEVER element
23
+ // the caller passes, not a `<span>` -- a `<div>`/`<p>`/`<li>` child's own
24
+ // block default lost to `.crisp-text`'s class-specificity `display:
25
+ // inline`, silently collapsing its layout (internal/grc's own Settings.tsx
26
+ // ran two rows onto one line this way). `vertical-align: baseline` fills
27
+ // the same "always-present, never empty" role without that risk: it's a
28
+ // span's own already-inherited default (so nothing changes for the plain,
29
+ // non-asChild case `Primitive.span` renders), and it has NO effect at all
30
+ // on a block-level box, so an `asChild` div/p/li keeps its own display
31
+ // exactly as its own tag already gives it.
32
+ base: { verticalAlign: "baseline" },
23
33
  variants: {
24
34
  tone: {
25
35
  default: { color: tokens_1.contract.fgPrimary },
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tagTone = tagTone;
4
+ // deterministic pastel colour per tag value (a select option keeps its colour)
5
+ const TAG_TONES = [
6
+ "brand",
7
+ "success",
8
+ "warning",
9
+ "danger",
10
+ "purple",
11
+ "cyan",
12
+ "orange",
13
+ ];
14
+ function tagTone(t) {
15
+ let h = 0;
16
+ for (let i = 0; i < t.length; i++)
17
+ h = (h * 31 + t.charCodeAt(i)) >>> 0;
18
+ return TAG_TONES[h % TAG_TONES.length];
19
+ }
@@ -47,7 +47,8 @@ const spinner_1 = require("../../components/spinner");
47
47
  const switch_1 = require("../../components/switch");
48
48
  const tabs_1 = require("../../components/tabs");
49
49
  const core_1 = require("../../core");
50
- const recordstable_1 = require("../recordstable");
50
+ const column_1 = require("./column");
51
+ const editable_field_1 = require("./editable-field");
51
52
  const recordpage_recipe_1 = require("./recordpage.recipe");
52
53
  function valueEmpty(v) {
53
54
  return v == null || v === "" || (Array.isArray(v) && v.length === 0);
@@ -212,7 +213,7 @@ function TagsValue({ values }) {
212
213
  const [expanded, setExpanded] = React.useState(false);
213
214
  const overflow = values.length - 1;
214
215
  const shown = expanded ? values : values.slice(0, 1);
215
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [shown.map((t) => ((0, jsx_runtime_1.jsx)("span", { className: "crisp-recordstable-tag", "data-tone": (0, recordstable_1.tagTone)(t), children: t }, t))), !expanded && overflow > 0 && ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-morevalues", onClick: () => setExpanded(true), children: ["+", overflow] }))] }));
216
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [shown.map((t) => ((0, jsx_runtime_1.jsx)("span", { className: "crisp-recordstable-tag", "data-tone": (0, column_1.tagTone)(t), children: t }, t))), !expanded && overflow > 0 && ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-morevalues", onClick: () => setExpanded(true), children: ["+", overflow] }))] }));
216
217
  }
217
218
  function FieldValue({ col, row, labels, }) {
218
219
  const v = row[col.key];
@@ -316,7 +317,7 @@ function EmptyCard({ icon, children, }) {
316
317
  */
317
318
  function RecordDetails({ record, columns, sections, onEdit, labels, className, ...rest }) {
318
319
  const t = useRecordPageLabels(labels);
319
- const { editingKey, pendingKey, error, openEditing, closeEditing, commit } = (0, recordstable_1.useEditableField)(onEdit);
320
+ const { editingKey, pendingKey, error, openEditing, closeEditing, commit } = (0, editable_field_1.useEditableField)(onEdit);
320
321
  const [detailsOpen, setDetailsOpen] = React.useState(true);
321
322
  const [searchOpen, setSearchOpen] = React.useState(false);
322
323
  const [fieldQuery, setFieldQuery] = React.useState("");
@@ -406,7 +407,7 @@ function RecordDetails({ record, columns, sections, onEdit, labels, className, .
406
407
  }
407
408
  if (canEdit && editingKey === col.key) {
408
409
  const value = record[col.key];
409
- const editor = (0, recordstable_1.editableInputType)(col.type);
410
+ const editor = (0, editable_field_1.editableInputType)(col.type);
410
411
  return ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-field", children: [label, (0, jsx_runtime_1.jsxs)("span", { className: "crisp-recordpage-field-value", children: [(0, jsx_runtime_1.jsx)("input", { className: "crisp-recordpage-edit",
411
412
  // biome-ignore lint/a11y/noAutofocus: focus the field the moment it opens
412
413
  autoFocus: true, ...editor, disabled: isPending, defaultValue: value == null ? "" : String(value), "aria-label": `Edit ${col.label}`, onKeyDown: (e) => {