@crisp-ui-kit/crisp 0.54.10 → 0.55.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.
Files changed (77) hide show
  1. package/dist/cjs/components/datatable/datatable.js +249 -46
  2. package/dist/cjs/components/datatable/datatable.recipe.js +24 -0
  3. package/dist/cjs/components/resizablepanel/resizablepanel.js +10 -1
  4. package/dist/cjs/components/table/table.js +8 -1
  5. package/dist/cjs/components/tabletoolbar/tabletoolbar.chrome.js +25 -2
  6. package/dist/cjs/components/tabletoolbar/tabletoolbar.js +176 -43
  7. package/dist/cjs/components/tabletoolbar/tabletoolbar.recipe.js +28 -9
  8. package/dist/cjs/index.js +0 -2
  9. package/dist/cjs/product/recordpage/column.js +19 -0
  10. package/dist/cjs/product/recordpage/index.js +6 -1
  11. package/dist/cjs/product/recordpage/recordpage.js +25 -8
  12. package/dist/cjs/product/recordpage/test-fixtures.js +55 -0
  13. package/dist/cjs/product/savedviews/savedviews.recipe.js +13 -11
  14. package/dist/datatable.css +14 -0
  15. package/dist/datatable.layered.css +14 -0
  16. package/dist/esm/components/datatable/datatable.js +250 -47
  17. package/dist/esm/components/datatable/datatable.recipe.js +24 -0
  18. package/dist/esm/components/resizablepanel/resizablepanel.js +10 -1
  19. package/dist/esm/components/table/table.js +8 -1
  20. package/dist/esm/components/tabletoolbar/tabletoolbar.chrome.js +25 -2
  21. package/dist/esm/components/tabletoolbar/tabletoolbar.js +177 -44
  22. package/dist/esm/components/tabletoolbar/tabletoolbar.recipe.js +28 -9
  23. package/dist/esm/index.js +0 -2
  24. package/dist/esm/product/recordpage/column.js +16 -0
  25. package/dist/esm/product/recordpage/index.js +2 -0
  26. package/dist/esm/product/recordpage/recordpage.js +22 -5
  27. package/dist/esm/product/recordpage/test-fixtures.js +52 -0
  28. package/dist/esm/product/savedviews/savedviews.recipe.js +13 -11
  29. package/dist/savedviews.css +6 -18
  30. package/dist/savedviews.layered.css +6 -18
  31. package/dist/styles.css +43 -276
  32. package/dist/styles.layered.css +43 -276
  33. package/dist/tabletoolbar.css +23 -3
  34. package/dist/tabletoolbar.layered.css +23 -3
  35. package/dist/types/components/datatable/datatable.d.ts +30 -3
  36. package/dist/types/components/table/table.d.ts +14 -0
  37. package/dist/types/components/tabletoolbar/tabletoolbar.d.ts +26 -1
  38. package/dist/types/index.d.ts +0 -2
  39. package/dist/types/product/recordpage/column.d.ts +112 -0
  40. package/dist/types/product/recordpage/index.d.ts +2 -0
  41. package/dist/types/product/recordpage/recordpage.d.ts +1 -1
  42. package/dist/types/product/recordpage/test-fixtures.d.ts +3 -0
  43. package/dist/types/product/recordpanel/recordpanel.d.ts +1 -1
  44. package/package.json +2 -12
  45. package/dist/cjs/product/recordstable/company-logos.js +0 -29
  46. package/dist/cjs/product/recordstable/index.js +0 -13
  47. package/dist/cjs/product/recordstable/recordstable.js +0 -1357
  48. package/dist/cjs/product/recordstable/recordstable.recipe.js +0 -175
  49. package/dist/cjs/product/recordstable/recordstable.tag.js +0 -26
  50. package/dist/cjs/product/taskstable/index.js +0 -7
  51. package/dist/cjs/product/taskstable/taskstable.js +0 -27
  52. package/dist/cjs/product/taskstable/taskstable.recipe.js +0 -56
  53. package/dist/esm/product/recordstable/company-logos.js +0 -26
  54. package/dist/esm/product/recordstable/index.js +0 -3
  55. package/dist/esm/product/recordstable/recordstable.js +0 -1317
  56. package/dist/esm/product/recordstable/recordstable.recipe.js +0 -172
  57. package/dist/esm/product/recordstable/recordstable.tag.js +0 -23
  58. package/dist/esm/product/taskstable/index.js +0 -2
  59. package/dist/esm/product/taskstable/taskstable.js +0 -24
  60. package/dist/esm/product/taskstable/taskstable.recipe.js +0 -53
  61. package/dist/recordstable.css +0 -223
  62. package/dist/recordstable.d.ts +0 -7
  63. package/dist/recordstable.layered.css +0 -225
  64. package/dist/taskstable.css +0 -30
  65. package/dist/taskstable.d.ts +0 -7
  66. package/dist/taskstable.layered.css +0 -32
  67. package/dist/types/product/recordstable/company-logos.d.ts +0 -1
  68. package/dist/types/product/recordstable/index.d.ts +0 -3
  69. package/dist/types/product/recordstable/recordstable.d.ts +0 -289
  70. package/dist/types/product/recordstable/recordstable.recipe.d.ts +0 -5
  71. package/dist/types/product/recordstable/recordstable.tag.d.ts +0 -15
  72. package/dist/types/product/taskstable/index.d.ts +0 -2
  73. package/dist/types/product/taskstable/taskstable.d.ts +0 -54
  74. package/dist/types/product/taskstable/taskstable.recipe.d.ts +0 -3
  75. /package/dist/cjs/product/{recordstable → recordpage}/editable-field.js +0 -0
  76. /package/dist/esm/product/{recordstable → recordpage}/editable-field.js +0 -0
  77. /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,25 @@ 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]);
454
+ const rootRef = React.useRef(null);
455
+ const viewSettingsTriggerRef = React.useRef(null);
456
+ const viewSettingsContentRef = React.useRef(null);
457
+ const [viewSettingsPos, setViewSettingsPos] = React.useState({});
458
+ const importExportTriggerRef = React.useRef(null);
459
+ const [importExportPos, setImportExportPos] = React.useState({});
411
460
  const [openMenu, setOpenMenu] = React.useState(null);
412
461
  const [dragSort, setDragSort] = React.useState(null);
413
462
  const [filterQuery, setFilterQuery] = React.useState("");
@@ -435,6 +484,65 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
435
484
  // built here -- hiding an attribute is a trailing control instead, see
436
485
  // the hide button below).
437
486
  const [addingAttribute, setAddingAttribute] = React.useState(false);
487
+ // crisp/#807: `viewSettingsRef`/`importExportRef` (#766) relocate the
488
+ // TRIGGER out of this toolbar's own row, but their POPOVERS stayed
489
+ // `position: absolute` inside the (now relocated) trigger's own
490
+ // `.crisp-tabletoolbar-toolgroup` -- correct chrome-wise (#772 already
491
+ // fixed that), but its stacking is trapped inside whatever DOM branch the
492
+ // consumer's own `viewSettingsRef` slot lives in. A consumer header
493
+ // sitting in an EARLIER sibling branch than the toolbar/grid below it
494
+ // (GRC's own layout) has that later branch simply paint over the popover
495
+ // regardless of its own z-index: 30, because z-index only orders siblings
496
+ // WITHIN the same stacking context, and the two branches aren't one.
497
+ // Fixed the same way `Menu`/`Select`/`Popover` already solve this: the
498
+ // popover content itself portals to `document.body` (`FloatingPortal`),
499
+ // positioned with `placeFloating` against the trigger's own rect (a real
500
+ // `position: fixed` box, anchored by viewport coordinates, escapes ANY
501
+ // ancestor's stacking context) -- not just relocated alongside the
502
+ // trigger. Wrapped in its own `tabletoolbarRecipe()` span (the same
503
+ // reason `ViewBarSlot` wraps the trigger) so every nested
504
+ // `.crisp-tabletoolbar-*` class inside the popover still resolves once
505
+ // portaled outside the toolbar's own root. Sort/Filter's own popovers
506
+ // are untouched -- they never relocate, so they were never trapped.
507
+ const placeViewSettingsMenu = () => {
508
+ const rect = viewSettingsTriggerRef.current?.getBoundingClientRect();
509
+ if (!rect)
510
+ return;
511
+ const { style } = (0, core_1.placeFloating)({
512
+ rect,
513
+ gap: 4,
514
+ flipBelow: 280,
515
+ anchor: viewSettingsTriggerRef.current,
516
+ });
517
+ setViewSettingsPos(style);
518
+ };
519
+ // biome-ignore lint/correctness/useExhaustiveDependencies: reposition each time it opens (and when its own screen changes, since the two screens differ in height)
520
+ React.useLayoutEffect(() => {
521
+ if (openMenu === "viewsettings")
522
+ placeViewSettingsMenu();
523
+ }, [openMenu, addingAttribute]);
524
+ React.useEffect(() => {
525
+ if (openMenu !== "viewsettings" || !viewSettingsContentRef.current)
526
+ return;
527
+ return (0, core_1.registerFloatingLayer)(viewSettingsContentRef.current);
528
+ }, [openMenu]);
529
+ const placeImportExportMenu = () => {
530
+ const rect = importExportTriggerRef.current?.getBoundingClientRect();
531
+ if (!rect)
532
+ return;
533
+ const { style } = (0, core_1.placeFloating)({
534
+ rect,
535
+ gap: 4,
536
+ flipBelow: 280,
537
+ anchor: importExportTriggerRef.current,
538
+ });
539
+ setImportExportPos(style);
540
+ };
541
+ // biome-ignore lint/correctness/useExhaustiveDependencies: reposition each time it opens
542
+ React.useLayoutEffect(() => {
543
+ if (openMenu === "importexport")
544
+ placeImportExportMenu();
545
+ }, [openMenu]);
438
546
  // close any open menu on outside click (anything not inside a menu or its
439
547
  // trigger) or Escape
440
548
  React.useEffect(() => {
@@ -585,6 +693,13 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
585
693
  close: () => setOpenMenu(null),
586
694
  contentRef: importExportMenuRef,
587
695
  });
696
+ // crisp/#807: registers the (now-portaled) Import/Export menu on the
697
+ // shared floating-layer stack, the same reason `Menu` itself does.
698
+ React.useEffect(() => {
699
+ if (openMenu !== "importexport" || !importExportMenuRef.current)
700
+ return;
701
+ return (0, core_1.registerFloatingLayer)(importExportMenuRef.current);
702
+ }, [openMenu]);
588
703
  // #754: generalized from the Filter-only `filterFieldPicker` (#592) to
589
704
  // also drive Sort's own field picker and View settings' add-attribute
590
705
  // screen — all three offer the identical nested-drill-down construct on
@@ -641,16 +756,23 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
641
756
  // worse than an imperfect word order); `crispMessages` rather than a
642
757
  // second `useCrispMessage` call, since this only fires on the branch that
643
758
  // needs it.
759
+ // crisp/#788: "Sorted by" and the field name are NOT a font-weight split
760
+ // (both measure 500/medium live) -- the difference is colour/opacity only:
761
+ // "Sorted by" at 63% black, the field name at full-strength near-black
762
+ // (rgb(16,17,18)). The "+N" suffix is smaller (12px vs 14px) and its own
763
+ // mid-grey (rgb(80,81,85)), not muted-63%-black either -- three distinct
764
+ // treatments, not two. `sortField` isolates the resolved label so the
765
+ // default (non-`sortTriggerLabel`) render can wrap each part in its own
766
+ // span; `sortedLabel` stays a single string for the `sortTriggerLabel`
767
+ // escape hatch (a caller-supplied formatter can't be split, by definition)
768
+ // and the empty-state `sortLabel`.
769
+ const sortField = resolveColumnPath(sortColumns, sorts[0]?.key ?? "").at(-1)?.label;
644
770
  const sortedLabel = sortTriggerLabel
645
771
  ? sortTriggerLabel(sorts, sortColumns)
646
772
  : sorts.length
647
- ? `${crispMessages["Sorted by"] ?? "Sorted by"} ${
648
- // #754: sorts[0].key may be a dot-joined nested path
649
- // ("team.jobTitle") — resolve it the same way the chip and sort
650
- // row do, rather than a flat find that fails on a nested key.
651
- resolveColumnPath(sortColumns, sorts[0].key).at(-1)?.label}${sorts.length > 1 ? ` +${sorts.length - 1}` : ""}`
773
+ ? `${crispMessages["Sorted by"] ?? "Sorted by"} ${sortField}${sorts.length > 1 ? ` +${sorts.length - 1}` : ""}`
652
774
  : sortLabel;
653
- 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) => {
775
+ return ((0, jsx_runtime_1.jsx)("div", { ref: rootRef, 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) => {
654
776
  if (dragSort !== null)
655
777
  e.preventDefault();
656
778
  }, onDrop: () => {
@@ -687,7 +809,7 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
687
809
  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] })),
688
810
  keywords: descendingLabel,
689
811
  },
690
- ], "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: () => {
812
+ ], "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: () => {
691
813
  setFieldPickerPath([]);
692
814
  setOpenMenu(openMenu === "filter" ? null : "filter");
693
815
  }, "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
@@ -786,43 +908,54 @@ function TableToolbar({ columns, sortColumns: sortColumnsProp, filterColumns: fi
786
908
  }, 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`,
787
909
  // biome-ignore lint/a11y/noAutofocus: focus the value field
788
910
  autoFocus: true, value: cond.value, onChange: (e) => patchFilter(cond.id, { value: e.target.value }) })) }))] }, cond.id));
789
- }), 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: () => {
790
- if (openMenu === "viewsettings") {
791
- setOpenMenu(null);
792
- }
793
- else {
794
- setAddingAttribute(false);
795
- setFieldPickerPath([]);
796
- setFilterQuery("");
797
- setOpenMenu("viewsettings");
798
- }
799
- }, "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" &&
800
- (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) => {
801
- if (dragAttr !== null)
802
- e.preventDefault();
803
- }, onDrop: () => {
804
- if (dragAttr !== null)
805
- moveAttr(dragAttr, i);
806
- setDragAttr(null);
807
- }, 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) ??
808
- `${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: () => {
809
- setAddingAttribute(true);
810
- setFieldPickerPath([]);
811
- setFilterQuery("");
812
- }, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), addAttributeToViewLabel] }) })] })))] })), (onImportCsv ||
911
+ }), 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", { ref: viewSettingsTriggerRef, type: "button", className: "crisp-tabletoolbar-tool crisp-tabletoolbar-tool--raised", onClick: () => {
912
+ if (openMenu === "viewsettings") {
913
+ setOpenMenu(null);
914
+ }
915
+ else {
916
+ setAddingAttribute(false);
917
+ setFieldPickerPath([]);
918
+ setFilterQuery("");
919
+ setOpenMenu("viewsettings");
920
+ }
921
+ }, "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" && ((0, jsx_runtime_1.jsx)(core_1.FloatingPortal, { sourceRef: rootRef, children: (0, jsx_runtime_1.jsx)("span", { className: (0, tabletoolbar_recipe_1.tabletoolbarRecipe)(), children: addingAttribute ? ((0, jsx_runtime_1.jsx)("div", { ref: viewSettingsContentRef, className: "crisp-tabletoolbar-menu", role: "dialog", "aria-label": addAttributeToViewLabel, style: {
922
+ position: "fixed",
923
+ zIndex: 70,
924
+ ...viewSettingsPos,
925
+ }, children: nestedFieldPicker(hiddenAttrs, showAttr, searchAttributesPlaceholder, searchAttributesPlaceholder) })) : ((0, jsx_runtime_1.jsxs)("div", { ref: viewSettingsContentRef, className: "crisp-tabletoolbar-menu crisp-tabletoolbar-sortpop", role: "dialog", "aria-label": viewSettingsLabel, style: {
926
+ position: "fixed",
927
+ zIndex: 70,
928
+ ...viewSettingsPos,
929
+ }, children: [shownAttrs.map((col, i) => ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-tabletoolbar-sort-row", onDragOver: (e) => {
930
+ if (dragAttr !== null)
931
+ e.preventDefault();
932
+ }, onDrop: () => {
933
+ if (dragAttr !== null)
934
+ moveAttr(dragAttr, i);
935
+ setDragAttr(null);
936
+ }, 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) ??
937
+ `${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: () => {
938
+ setAddingAttribute(true);
939
+ setFieldPickerPath([]);
940
+ setFilterQuery("");
941
+ }, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), addAttributeToViewLabel] }) })] })) }) }))] }) })), (onImportCsv ||
813
942
  onExportCsv ||
814
943
  onExportExcel ||
815
- 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: () => {
816
- onImportCsv();
817
- setOpenMenu(null);
818
- }, 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: () => {
819
- onExportCsv();
820
- setOpenMenu(null);
821
- }, 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: () => {
822
- onExportExcel();
823
- setOpenMenu(null);
824
- }, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Download, { size: 15, strokeWidth: 1.75 }), exportExcelLabel] })), importExportHelpHref &&
825
- (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] }) }));
944
+ 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", { ref: importExportTriggerRef, 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.jsx)(core_1.FloatingPortal, { sourceRef: rootRef, children: (0, jsx_runtime_1.jsx)("span", { className: (0, tabletoolbar_recipe_1.tabletoolbarRecipe)(), children: (0, jsx_runtime_1.jsxs)("div", { ref: importExportMenuRef, className: "crisp-tabletoolbar-menu", role: "menu", "aria-label": importExportLabel, onKeyDown: onImportExportKeyDown, style: {
945
+ position: "fixed",
946
+ zIndex: 70,
947
+ ...importExportPos,
948
+ }, children: [onImportCsv && ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "menuitem", className: "crisp-tabletoolbar-menu-item", onClick: () => {
949
+ onImportCsv();
950
+ setOpenMenu(null);
951
+ }, 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: () => {
952
+ onExportCsv();
953
+ setOpenMenu(null);
954
+ }, 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: () => {
955
+ onExportExcel();
956
+ setOpenMenu(null);
957
+ }, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Download, { size: 15, strokeWidth: 1.75 }), exportExcelLabel] })), importExportHelpHref &&
958
+ (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] }) }));
826
959
  }
827
960
  /**
828
961
  * The Sort/Filter chip's own chrome (`.crisp-tabletoolbar-tool`), standalone
@@ -74,14 +74,21 @@ const filterChipChrome = `
74
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"]}; }
75
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; }
76
76
  & .crisp-tabletoolbar-datepop-preset:hover { background: color-mix(in srgb, ${tokens_1.contract.fgPrimary} 8%, transparent); }`;
77
- // #595: the Import/Export trigger — measured live, `app.attio.com`'s own
78
- // view bar: `28px` tall, `radius.md` (8px), background `bgSurfaceMuted`
79
- // (`rgb(246,247,247)`, exact match) and `elevation.field`'s exact 3-layer
80
- // shadow (`inset 0 0 0 1px transparent, 0 0 2px rgba(28,40,64,.18), 0 1px 3px
81
- // rgba(0,0,0,.04)`) — a "raised chrome button" distinct from Sort/Filter/View
82
- // settings' plain ringed `.tool` (no background, no elevation shadow), and
83
- // the only trigger of the four with a trailing chevron (2 icons total,
84
- // 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
85
92
  // order (this block is appended after `toolbarChromeBody`, which defines
86
93
  // them), the same way `.tool--ghost` already does. `border`/`font-family`/
87
94
  // `cursor` are repeated here too, even though `.tool`'s own base rule (in
@@ -91,7 +98,18 @@ const filterChipChrome = `
91
98
  // behind `chrome.ts`'s function call is invisible to it; harmless repeats,
92
99
  // not a real gap.
93
100
  const importExportChrome = `
94
- & .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); }`;
95
113
  // The table toolbar, measured: 28px controls, the Sort/Filter buttons and
96
114
  // the menus they open, sort-condition rows, and the filter chips. The chrome
97
115
  // itself lives in ./tabletoolbar.chrome.ts because RecordsTable renders the
@@ -110,6 +128,7 @@ ${(0, tabletoolbar_chrome_1.toolbarChromeHead)("tabletoolbar")}
110
128
  ${(0, tabletoolbar_chrome_1.toolbarChromeBody)("tabletoolbar")}
111
129
  ${filterChipChrome}
112
130
  ${importExportChrome}
131
+ ${sortedLabelChrome}
113
132
  ${core_1.rtlFlipCss}
114
133
  `,
115
134
  });
package/dist/cjs/index.js CHANGED
@@ -102,7 +102,6 @@ __exportStar(require("./product/objectsettings"), exports);
102
102
  __exportStar(require("./product/onboarding"), exports);
103
103
  __exportStar(require("./product/recordpage"), exports);
104
104
  __exportStar(require("./product/recordpanel"), exports);
105
- __exportStar(require("./product/recordstable"), exports);
106
105
  __exportStar(require("./product/richtext"), exports);
107
106
  __exportStar(require("./product/savedviews"), exports);
108
107
  __exportStar(require("./product/settingssection"), exports);
@@ -110,7 +109,6 @@ __exportStar(require("./product/settingsshell"), exports);
110
109
  __exportStar(require("./product/sidebar"), exports);
111
110
  __exportStar(require("./product/statlist"), exports);
112
111
  __exportStar(require("./product/tasklist"), exports);
113
- __exportStar(require("./product/taskstable"), exports);
114
112
  __exportStar(require("./product/themepicker"), exports);
115
113
  __exportStar(require("./product/trialbanner"), exports);
116
114
  __exportStar(require("./product/viewtoggle"), exports);
@@ -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
+ }
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.recordpageRecipe = exports.recordPageLabels = exports.RecordPage = exports.RecordDetails = void 0;
3
+ exports.recordpageRecipe = exports.recordPageLabels = exports.RecordPage = exports.RecordDetails = exports.useEditableField = exports.editableInputType = exports.tagTone = void 0;
4
+ var column_1 = require("./column");
5
+ Object.defineProperty(exports, "tagTone", { enumerable: true, get: function () { return column_1.tagTone; } });
6
+ var editable_field_1 = require("./editable-field");
7
+ Object.defineProperty(exports, "editableInputType", { enumerable: true, get: function () { return editable_field_1.editableInputType; } });
8
+ Object.defineProperty(exports, "useEditableField", { enumerable: true, get: function () { return editable_field_1.useEditableField; } });
4
9
  var recordpage_1 = require("./recordpage");
5
10
  Object.defineProperty(exports, "RecordDetails", { enumerable: true, get: function () { return recordpage_1.RecordDetails; } });
6
11
  Object.defineProperty(exports, "RecordPage", { enumerable: true, get: function () { return recordpage_1.RecordPage; } });
@@ -47,8 +47,23 @@ 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");
53
+ // crisp/#798: the details column's own drag clamp -- re-measured live on
54
+ // Attio's own record page (a real drag test, not a source read): min 619px,
55
+ // max 1170px, default (also the double-click-reset target) 734px. These
56
+ // replace an earlier, much narrower 300/560/320 that was never actually
57
+ // checked against Attio and turned out roughly half the real max. Confirmed
58
+ // live these are literal px, not a viewport ratio: at a narrower emulated
59
+ // width the already-dragged-to-max column shrank below 1170px, but its OWN
60
+ // `getComputedStyle(...).width` still read a plain px number the whole
61
+ // time (not a `%`) — that shrink is ordinary flex-shrink (both panels
62
+ // share `flex: 1 1 auto` and can't both keep their preferred width once the
63
+ // window is too narrow), not the clamp itself changing with viewport width.
64
+ const DETAILS_MIN_W = 619;
65
+ const DETAILS_MAX_W = 1170;
66
+ const DETAILS_DEFAULT_W = 734;
52
67
  function valueEmpty(v) {
53
68
  return v == null || v === "" || (Array.isArray(v) && v.length === 0);
54
69
  }
@@ -212,7 +227,7 @@ function TagsValue({ values }) {
212
227
  const [expanded, setExpanded] = React.useState(false);
213
228
  const overflow = values.length - 1;
214
229
  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] }))] }));
230
+ 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
231
  }
217
232
  function FieldValue({ col, row, labels, }) {
218
233
  const v = row[col.key];
@@ -316,7 +331,7 @@ function EmptyCard({ icon, children, }) {
316
331
  */
317
332
  function RecordDetails({ record, columns, sections, onEdit, labels, className, ...rest }) {
318
333
  const t = useRecordPageLabels(labels);
319
- const { editingKey, pendingKey, error, openEditing, closeEditing, commit } = (0, recordstable_1.useEditableField)(onEdit);
334
+ const { editingKey, pendingKey, error, openEditing, closeEditing, commit } = (0, editable_field_1.useEditableField)(onEdit);
320
335
  const [detailsOpen, setDetailsOpen] = React.useState(true);
321
336
  const [searchOpen, setSearchOpen] = React.useState(false);
322
337
  const [fieldQuery, setFieldQuery] = React.useState("");
@@ -406,7 +421,7 @@ function RecordDetails({ record, columns, sections, onEdit, labels, className, .
406
421
  }
407
422
  if (canEdit && editingKey === col.key) {
408
423
  const value = record[col.key];
409
- const editor = (0, recordstable_1.editableInputType)(col.type);
424
+ const editor = (0, editable_field_1.editableInputType)(col.type);
410
425
  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
426
  // biome-ignore lint/a11y/noAutofocus: focus the field the moment it opens
412
427
  autoFocus: true, ...editor, disabled: isPending, defaultValue: value == null ? "" : String(value), "aria-label": `Edit ${col.label}`, onKeyDown: (e) => {
@@ -456,7 +471,7 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
456
471
  const tasks = tasksProp ?? internalTasks;
457
472
  const [showAllActivity, setShowAllActivity] = React.useState(false);
458
473
  // Drag-resizable left details column.
459
- const [detailsW, setDetailsW] = React.useState(320);
474
+ const [detailsW, setDetailsW] = React.useState(DETAILS_DEFAULT_W);
460
475
  const [resizing, setResizing] = React.useState(false);
461
476
  const dragRef = React.useRef(null);
462
477
  const onResizeDown = (e) => {
@@ -474,7 +489,7 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
474
489
  if (!dragRef.current)
475
490
  return;
476
491
  const next = dragRef.current.w + dragRef.current.dir * (e.clientX - dragRef.current.x);
477
- setDetailsW(Math.max(300, Math.min(560, next)));
492
+ setDetailsW(Math.max(DETAILS_MIN_W, Math.min(DETAILS_MAX_W, next)));
478
493
  };
479
494
  const onResizeUp = (e) => {
480
495
  dragRef.current = null;
@@ -659,7 +674,7 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
659
674
  const effectivePanel = tabsProp
660
675
  ? (active) => tabsProp.find((tb) => tb.id === active)?.render()
661
676
  : builtinPanel;
662
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, recordpage_recipe_1.recordpageRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-topbar", children: [(0, jsx_runtime_1.jsxs)("nav", { className: "crisp-recordpage-crumbs", "aria-label": t.breadcrumb, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-crumb", onClick: onBack, "aria-label": `Back to ${collection}`, children: collection }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-sep", children: "/" }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-name", children: name })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-actions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--ghost", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Sparkles, { size: 14, strokeWidth: 1.75, color: "var(--crisp-bg-brand-solid)" }), t.askAttio] }), onToggleFull && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", onClick: onToggleFull, "aria-label": full ? t.exitFullScreen : t.fullScreen, children: full ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Minimize2, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Maximize2, { size: 15, strokeWidth: 1.75 })) })), (0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: "end", "aria-label": t.recordActions, trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", "aria-label": t.recordActions, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75 }) }), children: [(0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }), shortcut: "\u2318C", children: t.copyRecordLink }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), children: t.addToList }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }), onSelect: () => setFavorite((f) => !f), children: favorite ? t.removeFromFavourites : t.addToFavourites }), (0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 15, strokeWidth: 1.75 }), danger: true, shortcut: "\u232B", children: t.deleteRecord })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-body", children: [(0, jsx_runtime_1.jsxs)("aside", { className: "crisp-recordpage-details", style: { width: detailsW }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-entity", children: [entity?.avatar ? ((0, jsx_runtime_1.jsx)("img", { className: "crisp-recordpage-entity-logo", src: entity.avatar, alt: "" })) : ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "lg", shape: "rounded", tone: "brand", children: name.charAt(0) })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-entity-name", children: name }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "aria-label": t.editRecord, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "data-active": favorite ? "" : undefined, "aria-pressed": favorite, onClick: () => setFavorite((f) => !f), "aria-label": favorite ? t.removeFromFavourites : t.addToFavourites, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-quickactions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-compose", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Mail, { size: 16, strokeWidth: 1.75 }), t.composeEmail] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.copyRecordLink, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.logANote, children: (0, jsx_runtime_1.jsx)(lucide_react_1.FileText, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.linkRecords, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Share2, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.createATask, children: (0, jsx_runtime_1.jsx)(lucide_react_1.SquareCheck, { size: 15, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsx)(RecordDetails, { record: record, columns: columns, sections: sections, onEdit: onEdit, labels: labels }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-section", children: [(0, jsx_runtime_1.jsx)(SectionHead, { title: t.tabs.lists, action: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-addbtn", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 14, strokeWidth: 2 }), t.addToList] }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-emptystate", children: t.noLists })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-resizer", "data-active": resizing ? "" : undefined, role: "separator", "aria-orientation": "vertical", "aria-label": t.resizeDetails, "aria-valuenow": Math.round(detailsW), "aria-valuemin": 300, "aria-valuemax": 560, tabIndex: 0, onPointerDown: onResizeDown, onPointerMove: onResizeMove, onPointerUp: onResizeUp, onKeyDown: (e) => {
677
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, recordpage_recipe_1.recordpageRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-topbar", children: [(0, jsx_runtime_1.jsxs)("nav", { className: "crisp-recordpage-crumbs", "aria-label": t.breadcrumb, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-crumb", onClick: onBack, "aria-label": `Back to ${collection}`, children: collection }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-sep", children: "/" }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-name", children: name })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-actions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--ghost", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Sparkles, { size: 14, strokeWidth: 1.75, color: "var(--crisp-bg-brand-solid)" }), t.askAttio] }), onToggleFull && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", onClick: onToggleFull, "aria-label": full ? t.exitFullScreen : t.fullScreen, children: full ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Minimize2, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Maximize2, { size: 15, strokeWidth: 1.75 })) })), (0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: "end", "aria-label": t.recordActions, trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", "aria-label": t.recordActions, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75 }) }), children: [(0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }), shortcut: "\u2318C", children: t.copyRecordLink }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), children: t.addToList }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }), onSelect: () => setFavorite((f) => !f), children: favorite ? t.removeFromFavourites : t.addToFavourites }), (0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 15, strokeWidth: 1.75 }), danger: true, shortcut: "\u232B", children: t.deleteRecord })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-body", children: [(0, jsx_runtime_1.jsxs)("aside", { className: "crisp-recordpage-details", style: { width: detailsW }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-entity", children: [entity?.avatar ? ((0, jsx_runtime_1.jsx)("img", { className: "crisp-recordpage-entity-logo", src: entity.avatar, alt: "" })) : ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "lg", shape: "rounded", tone: "brand", children: name.charAt(0) })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-entity-name", children: name }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "aria-label": t.editRecord, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "data-active": favorite ? "" : undefined, "aria-pressed": favorite, onClick: () => setFavorite((f) => !f), "aria-label": favorite ? t.removeFromFavourites : t.addToFavourites, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-quickactions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-compose", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Mail, { size: 16, strokeWidth: 1.75 }), t.composeEmail] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.copyRecordLink, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.logANote, children: (0, jsx_runtime_1.jsx)(lucide_react_1.FileText, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.linkRecords, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Share2, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.createATask, children: (0, jsx_runtime_1.jsx)(lucide_react_1.SquareCheck, { size: 15, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsx)(RecordDetails, { record: record, columns: columns, sections: sections, onEdit: onEdit, labels: labels }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-section", children: [(0, jsx_runtime_1.jsx)(SectionHead, { title: t.tabs.lists, action: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-addbtn", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 14, strokeWidth: 2 }), t.addToList] }) }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-emptystate", children: t.noLists })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-resizer", "data-active": resizing ? "" : undefined, role: "separator", "aria-orientation": "vertical", "aria-label": t.resizeDetails, "aria-valuenow": Math.round(detailsW), "aria-valuemin": DETAILS_MIN_W, "aria-valuemax": DETAILS_MAX_W, tabIndex: 0, onPointerDown: onResizeDown, onPointerMove: onResizeMove, onPointerUp: onResizeUp, onKeyDown: (e) => {
663
678
  if (e.key !== "ArrowLeft" && e.key !== "ArrowRight")
664
679
  return;
665
680
  // The pointer drag learned its direction in #212; this did not.
@@ -668,7 +683,9 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
668
683
  // half-conversion the drag had, one handler away (#255).
669
684
  const rtl = (0, core_1.isRtlElement)(e.currentTarget);
670
685
  const grow = e.key === (rtl ? "ArrowLeft" : "ArrowRight");
671
- setDetailsW((w) => grow ? Math.min(560, w + 16) : Math.max(300, w - 16));
686
+ setDetailsW((w) => grow
687
+ ? Math.min(DETAILS_MAX_W, w + 16)
688
+ : Math.max(DETAILS_MIN_W, w - 16));
672
689
  } }), (0, jsx_runtime_1.jsx)("main", { className: "crisp-recordpage-main", children: (0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: effectiveTabs, defaultValue: tabsProp ? defaultTab : "overview", "aria-label": `${name} record`, children: effectivePanel }) })] })] }));
673
690
  }
674
691
  RecordPage.displayName = "RecordPage";