@crispy-seed/data-table 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ function __insertCSS(code) {
10
10
 
11
11
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
12
12
  import * as React from 'react';
13
- import React__default, { forwardRef, useCallback, useMemo, useState, useRef, useEffect, createContext, useContext } from 'react';
13
+ import React__default, { forwardRef, useCallback, useMemo, useState, useRef, useEffect, createContext, useContext, useId } from 'react';
14
14
  import { dataAttr, elementProps, ariaAttr, mergeProps as mergeProps$1 } from '@seed-design/dom-utils';
15
15
  import { checkbox } from '@seed-design/css/recipes/checkbox';
16
16
  import { checkmark } from '@seed-design/css/recipes/checkmark';
@@ -36,7 +36,7 @@ import { menu } from '@seed-design/css/recipes/menu';
36
36
  import { menuItem } from '@seed-design/css/recipes/menu-item';
37
37
 
38
38
  // src/IconArrowUpLine.tsx
39
- var Icon$f = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
39
+ var Icon$h = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
40
40
  viewBox: "0 0 24 24",
41
41
  fill: "none",
42
42
  xmlns: "http://www.w3.org/2000/svg",
@@ -54,11 +54,11 @@ var Icon$f = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
54
54
  })
55
55
  })
56
56
  });
57
- var IconArrowUpLine = /*#__PURE__*/ forwardRef(Icon$f);
57
+ var IconArrowUpLine = /*#__PURE__*/ forwardRef(Icon$h);
58
58
  var IconArrowUpLine_default = IconArrowUpLine;
59
59
 
60
60
  // src/IconArrowDownLine.tsx
61
- var Icon$e = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
61
+ var Icon$g = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
62
62
  viewBox: "0 0 24 24",
63
63
  fill: "none",
64
64
  xmlns: "http://www.w3.org/2000/svg",
@@ -76,11 +76,33 @@ var Icon$e = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
76
76
  })
77
77
  })
78
78
  });
79
- var IconArrowDownLine = /*#__PURE__*/ forwardRef(Icon$e);
79
+ var IconArrowDownLine = /*#__PURE__*/ forwardRef(Icon$g);
80
80
  var IconArrowDownLine_default = IconArrowDownLine;
81
81
 
82
+ // src/IconArrowUpRightLine.tsx
83
+ var Icon$f = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
84
+ viewBox: "0 0 24 24",
85
+ fill: "none",
86
+ xmlns: "http://www.w3.org/2000/svg",
87
+ "data-seed-icon": "true",
88
+ width: size,
89
+ height: size,
90
+ ref,
91
+ ...props,
92
+ children: /* @__PURE__ */ jsx("g", {
93
+ children: /* @__PURE__ */ jsx("path", {
94
+ fillRule: "evenodd",
95
+ clipRule: "evenodd",
96
+ d: "M20.0005 19C20.5505 19 21.0005 18.55 21.0005 18V4C21.0005 3.45 20.5505 3 20.0005 3H6.00055C5.45055 3 5.00055 3.45 5.00055 4C5.00055 4.55 5.45055 5 6.00055 5H17.6005L3.29055 19.29C2.90055 19.68 2.90055 20.31 3.29055 20.7C3.68055 21.09 4.31055 21.09 4.70055 20.7L19.0005 6.43V18C19.0005 18.55 19.4505 19 20.0005 19Z",
97
+ fill: "currentColor"
98
+ })
99
+ })
100
+ });
101
+ var IconArrowUpRightLine = /*#__PURE__*/ forwardRef(Icon$f);
102
+ var IconArrowUpRightLine_default = IconArrowUpRightLine;
103
+
82
104
  // src/IconArrowUpArrowDownLine.tsx
83
- var Icon$d = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
105
+ var Icon$e = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
84
106
  viewBox: "0 0 24 24",
85
107
  fill: "none",
86
108
  xmlns: "http://www.w3.org/2000/svg",
@@ -104,11 +126,11 @@ var Icon$d = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
104
126
  })
105
127
  })
106
128
  });
107
- var IconArrowUpArrowDownLine = /*#__PURE__*/ forwardRef(Icon$d);
129
+ var IconArrowUpArrowDownLine = /*#__PURE__*/ forwardRef(Icon$e);
108
130
  var IconArrowUpArrowDownLine_default = IconArrowUpArrowDownLine;
109
131
 
110
132
  // src/IconChevronDownLine.tsx
111
- var Icon$c = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
133
+ var Icon$d = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
112
134
  viewBox: "0 0 24 24",
113
135
  fill: "none",
114
136
  xmlns: "http://www.w3.org/2000/svg",
@@ -126,11 +148,11 @@ var Icon$c = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
126
148
  })
127
149
  })
128
150
  });
129
- var IconChevronDownLine = /*#__PURE__*/ forwardRef(Icon$c);
151
+ var IconChevronDownLine = /*#__PURE__*/ forwardRef(Icon$d);
130
152
  var IconChevronDownLine_default = IconChevronDownLine;
131
153
 
132
154
  // src/IconChevronUpLine.tsx
133
- var Icon$b = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
155
+ var Icon$c = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
134
156
  viewBox: "0 0 24 24",
135
157
  fill: "none",
136
158
  xmlns: "http://www.w3.org/2000/svg",
@@ -148,11 +170,11 @@ var Icon$b = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
148
170
  })
149
171
  })
150
172
  });
151
- var IconChevronUpLine = /*#__PURE__*/ forwardRef(Icon$b);
173
+ var IconChevronUpLine = /*#__PURE__*/ forwardRef(Icon$c);
152
174
  var IconChevronUpLine_default = IconChevronUpLine;
153
175
 
154
176
  // src/IconDot3HorizontalLine.tsx
155
- var Icon$a = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
177
+ var Icon$b = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
156
178
  viewBox: "0 0 24 24",
157
179
  fill: "none",
158
180
  xmlns: "http://www.w3.org/2000/svg",
@@ -180,9 +202,37 @@ var Icon$a = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
180
202
  })
181
203
  })
182
204
  });
183
- var IconDot3HorizontalLine = /*#__PURE__*/ forwardRef(Icon$a);
205
+ var IconDot3HorizontalLine = /*#__PURE__*/ forwardRef(Icon$b);
184
206
  var IconDot3HorizontalLine_default = IconDot3HorizontalLine;
185
207
 
208
+ // src/IconEyeLine.tsx
209
+ var Icon$a = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
210
+ viewBox: "0 0 24 24",
211
+ fill: "none",
212
+ xmlns: "http://www.w3.org/2000/svg",
213
+ "data-seed-icon": "true",
214
+ width: size,
215
+ height: size,
216
+ ref,
217
+ ...props,
218
+ children: /* @__PURE__ */ jsx("g", {
219
+ children: /* @__PURE__ */ jsxs("g", {
220
+ children: [
221
+ /* @__PURE__ */ jsx("path", {
222
+ d: "M1.68785 14.0027C2.21223 14.1751 2.77712 13.8901 2.94996 13.3659C3.07236 13.0089 3.23163 12.663 3.39915 12.3254C3.7229 11.6731 4.22663 10.8054 4.94433 9.94191C6.3729 8.22305 8.6137 6.55273 12.0003 6.55273C15.3868 6.55273 17.6276 8.22305 19.0562 9.94191C19.7739 10.8054 20.2776 11.6731 20.6014 12.3254C20.7627 12.6505 20.8778 12.9189 20.9513 13.1024C21.0036 13.233 21.0295 13.302 21.0509 13.3669C21.2241 13.8904 21.7886 14.175 22.3127 14.0027C22.8373 13.8301 23.1225 13.264 22.9499 12.7394C22.9158 12.6366 22.8793 12.5369 22.8078 12.3586C22.717 12.1319 22.5805 11.8144 22.3929 11.4363C22.0187 10.6824 21.435 9.67502 20.5943 8.66356C18.9062 6.63242 16.147 4.55273 12.0003 4.55273C7.8535 4.55273 5.09431 6.63242 3.40621 8.66356C2.56557 9.67502 1.9818 10.6824 1.60765 11.4363C1.42001 11.8144 1.28353 12.1319 1.1927 12.3586C1.12106 12.5374 1.08448 12.6372 1.05033 12.7403C0.877781 13.2649 1.16321 13.8301 1.68785 14.0027Z",
223
+ fill: "currentColor"
224
+ }),
225
+ /* @__PURE__ */ jsx("path", {
226
+ d: "M12.576 9.10187C12.7569 9.46282 12.7029 9.89712 12.4393 10.2029C12.0675 10.634 11.8429 11.1792 11.8429 11.7727C11.8429 13.0923 12.9123 14.1613 14.2263 14.1613C14.8331 14.1613 15.3926 13.9188 15.8177 13.522C16.1163 13.2434 16.5544 13.1743 16.9243 13.3476C17.2941 13.5209 17.5214 13.9017 17.4984 14.3095C17.3348 17.2106 15.0545 19.5498 12.0068 19.5498C8.94739 19.5498 6.5 16.9571 6.5 14.0363C6.5 11.1187 8.76722 8.75104 11.6123 8.55225C12.015 8.52411 12.3952 8.74091 12.576 9.10187Z",
227
+ fill: "currentColor"
228
+ })
229
+ ]
230
+ })
231
+ })
232
+ });
233
+ var IconEyeLine = /*#__PURE__*/ forwardRef(Icon$a);
234
+ var IconEyeLine_default = IconEyeLine;
235
+
186
236
  // src/IconMagnifyingglassLine.tsx
187
237
  var Icon$9 = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsx("svg", {
188
238
  viewBox: "0 0 24 24",
@@ -859,18 +909,33 @@ function useDataTableColumnCalc(props) {
859
909
  return next;
860
910
  }
861
911
  /**
862
- * Drag-to-reorder: removes `dragKey` from `order` and reinserts it immediately before
863
- * `dropKey`'s CURRENT position (i.e. its position after the removal, so dropping a
864
- * column just after its own old slot doesn't appear to do nothing). A no-op (an
865
- * equal-valued copy) when either key is missing or they're the same key.
912
+ * Drag-to-reorder: moves `dragKey` to `dropKey`'s own ORIGINAL index (the standard
913
+ * `arrayMove` two-splice shape -- remove `dragKey`, then reinsert it at `dropKey`'s
914
+ * pre-removal index of the now-shorter array), the same semantics dnd-kit's own
915
+ * `arrayMove` uses. A no-op (an equal-valued copy) when either key is missing or
916
+ * they're the same key.
917
+ *
918
+ * An EARLIER version of this function instead reinserted `dragKey` immediately before
919
+ * `dropKey`'s post-removal position. That reads the same for a multi-column jump, but
920
+ * is a silent no-op for the single most common drag gesture there is: dragging a
921
+ * column onto its own immediate RIGHT neighbor. Concretely, for `["a","b"]`, dragging
922
+ * "a" onto "b": removing "a" leaves `["b"]`, and "immediately before b" is index 0 --
923
+ * exactly where "a" already was, so nothing moved even though a real drag-and-drop
924
+ * gesture happened (caught by `DataTable.columns.test.tsx`'s own end-to-end drag test,
925
+ * which fires a real `dragover` DOM event and asserts the header order actually
926
+ * changed -- it didn't). This version's two-splice shape lands the dragged column at
927
+ * the target's own original slot instead, which swaps immediate neighbors correctly in
928
+ * both directions and still matches the old multi-jump behavior for a LEFTWARD drag
929
+ * (only a RIGHTWARD multi-column jump now lands one slot further, after the drop
930
+ * target instead of before it -- see this file's own test for both directions).
866
931
  */ function reorderColumnKey(order, dragKey, dropKey) {
867
932
  if (dragKey === dropKey || !order.includes(dragKey) || !order.includes(dropKey)) {
868
933
  return [
869
934
  ...order
870
935
  ];
871
936
  }
937
+ const dropIndex = order.indexOf(dropKey);
872
938
  const withoutDrag = order.filter((key)=>key !== dragKey);
873
- const dropIndex = withoutDrag.indexOf(dropKey);
874
939
  return [
875
940
  ...withoutDrag.slice(0, dropIndex),
876
941
  dragKey,
@@ -882,6 +947,24 @@ function useDataTableColumnCalc(props) {
882
947
  * nor balloon past a sane cap from one fast mouse move). */ function clampColumnWidth(width, min = 80, max = 640) {
883
948
  return Math.min(max, Math.max(min, width));
884
949
  }
950
+ /**
951
+ * Reconciles a persisted/controlled PINNED set against the table's current column
952
+ * KEYS -- the same drop-what's-gone rule `reconcileColumnOrder` already applies to
953
+ * `columnOrder`, but pins never need the "append what's new" half of that: an unpinned
954
+ * column simply isn't in the set, appending it here would silently pin every brand-new
955
+ * column by accident. A key no longer in `keys` (hidden isn't "gone" -- only removed
956
+ * from `columns` entirely) is dropped; everything else keeps its order.
957
+ */ function reconcilePinnedColumns(pinned, keys) {
958
+ const keySet = new Set(keys);
959
+ return pinned.filter((key)=>keySet.has(key));
960
+ }
961
+ /** Pin/unpin: adds `key` if absent, removes it if present -- column-menu.tsx's own
962
+ * "Pin column"/"Unpin column" toggle is one call of this, the same shape
963
+ * `toggleMembership` already gives row selection. Kept as its own named function
964
+ * (rather than reusing `toggleMembership` directly) so a pin-specific doc comment and
965
+ * call sites aren't reading a generically-named helper for a column-specific concern. */ function togglePinnedColumn(pinned, key) {
966
+ return toggleMembership(pinned, key);
967
+ }
885
968
  /**
886
969
  * Infinite scroll's own gate: fire `onLoadMore` only when the sentinel is ACTUALLY
887
970
  * intersecting (not e.g. an observer's initial `false` callback, which fires once on
@@ -895,19 +978,90 @@ function useDataTableColumnCalc(props) {
895
978
  */ function shouldTriggerLoadMore(isIntersecting, hasMore, loadingMore) {
896
979
  return hasMore && !loadingMore;
897
980
  }
981
+ function isPlainObject(value) {
982
+ return typeof value === "object" && value !== null && !Array.isArray(value);
983
+ }
984
+ /** Structural validation for ONE parsed view -- every field of `DataTableViewState` is
985
+ * optional, so this only rejects a field that's actually PRESENT but the wrong shape
986
+ * (a consumer's storage from a future/older version of this shape), not a field that's
987
+ * simply missing. */ function isValidDataTableView(value) {
988
+ if (!isPlainObject(value)) return false;
989
+ if (typeof value["id"] !== "string" || typeof value["name"] !== "string") return false;
990
+ if (!isPlainObject(value["state"])) return false;
991
+ const state = value["state"];
992
+ if (state["columnOrder"] !== undefined && !isStringArray(state["columnOrder"])) return false;
993
+ if (state["hiddenColumnKeys"] !== undefined && !isStringArray(state["hiddenColumnKeys"])) return false;
994
+ if (state["pinnedColumnKeys"] !== undefined && !isStringArray(state["pinnedColumnKeys"])) return false;
995
+ if (state["columnWidths"] !== undefined && !isPlainObject(state["columnWidths"])) return false;
996
+ if (state["toolbarSorts"] !== undefined && !Array.isArray(state["toolbarSorts"])) return false;
997
+ if (state["toolbarFilters"] !== undefined && !Array.isArray(state["toolbarFilters"])) return false;
998
+ return true;
999
+ }
1000
+ function isStringArray(value) {
1001
+ return Array.isArray(value) && value.every((entry)=>typeof entry === "string");
1002
+ }
1003
+ /** JSON-serializes a saved-views list for the default localStorage store -- pure so it
1004
+ * can be unit- and mutation-tested without touching `window.localStorage` at all (the
1005
+ * hook's own effect, `useDataTableViews.ts`, is the only thing that actually touches
1006
+ * storage; this is just the byte-for-byte shape it writes/reads). */ function serializeDataTableViews(views) {
1007
+ return JSON.stringify(views);
1008
+ }
1009
+ /**
1010
+ * Parses a saved-views blob back into a `DataTableView[]`, defensively: malformed JSON,
1011
+ * a non-array root, or any single malformed entry drops just that problem (an empty
1012
+ * list, or that one entry) rather than throwing -- a consumer's localStorage can hold a
1013
+ * PRIOR version's shape after this ships a new field, and one bad/stale entry shouldn't
1014
+ * cost every other saved view.
1015
+ */ function deserializeDataTableViews(raw) {
1016
+ if (!raw) return [];
1017
+ let parsed;
1018
+ try {
1019
+ parsed = JSON.parse(raw);
1020
+ } catch {
1021
+ return [];
1022
+ }
1023
+ if (!Array.isArray(parsed)) return [];
1024
+ return parsed.filter(isValidDataTableView);
1025
+ }
1026
+ /** Inserts `view` (by `id`), or replaces the existing entry with the same `id` in
1027
+ * place -- "Save" (new view) and "update the currently loaded view" are both one call
1028
+ * of this, matching `moveColumnKey`/`reorderColumnKey`'s own "one pure op per user
1029
+ * gesture" shape. */ function upsertDataTableView(views, view) {
1030
+ const index = views.findIndex((existing)=>existing.id === view.id);
1031
+ if (index === -1) return [
1032
+ ...views,
1033
+ view
1034
+ ];
1035
+ const next = [
1036
+ ...views
1037
+ ];
1038
+ next[index] = view;
1039
+ return next;
1040
+ }
1041
+ /** Renames the view with this `id` -- a no-op (an equal-valued copy) if no view has
1042
+ * that id. */ function renameDataTableView(views, id, name) {
1043
+ return views.map((view)=>view.id === id ? {
1044
+ ...view,
1045
+ name
1046
+ } : view);
1047
+ }
1048
+ /** Removes the view with this `id`. */ function removeDataTableView(views, id) {
1049
+ return views.filter((view)=>view.id !== id);
1050
+ }
898
1051
  const EMPTY_STRINGS = [];
899
1052
  const EMPTY_RECORD = {};
900
1053
  /**
901
1054
  * Owns everything DATATABLE-ATTIO-SPEC.md's column menu + reorder + resize tranche
902
- * needs -- order, visibility, a per-column label override, and a per-column width --
903
- * the way useDataTableSelection owns the one selected-id SET rather than one hook per
904
- * row. All four are "one value per column key" maps/lists a consumer may want to
905
- * persist (a saved view), so they share this hook instead of splitting into four
906
- * separate ones; drag-to-reorder and drag-to-resize (below) are the two INTERACTIONS
907
- * built on top of the order/width state this hook already owns, not independent state
1055
+ * needs -- order, visibility, a per-column label override, a per-column width, and
1056
+ * (Attio's "Pin column") a per-column left-pinned flag -- the way useDataTableSelection
1057
+ * owns the one selected-id SET rather than one hook per row. All five are "one value
1058
+ * per column key" maps/lists/sets a consumer may want to persist (a saved view), so
1059
+ * they share this hook instead of splitting into five separate ones; drag-to-reorder
1060
+ * and drag-to-resize (below) are the two INTERACTIONS built on top of the order/width
1061
+ * state this hook already owns, not independent state
908
1062
  * of their own.
909
1063
  */ function useDataTableColumns(props) {
910
- const { columnKeys = EMPTY_STRINGS, columnOrder: columnOrderProp, defaultColumnOrder, onColumnOrderChange, hiddenColumnKeys: hiddenProp, defaultHiddenColumnKeys = EMPTY_STRINGS, onHiddenColumnKeysChange, columnWidths: widthsProp, defaultColumnWidths = EMPTY_RECORD, onColumnWidthsChange, columnLabels: labelsProp, defaultColumnLabels = EMPTY_RECORD, onColumnLabelsChange } = props;
1064
+ const { columnKeys = EMPTY_STRINGS, columnOrder: columnOrderProp, defaultColumnOrder, onColumnOrderChange, hiddenColumnKeys: hiddenProp, defaultHiddenColumnKeys = EMPTY_STRINGS, onHiddenColumnKeysChange, columnWidths: widthsProp, defaultColumnWidths = EMPTY_RECORD, onColumnWidthsChange, columnLabels: labelsProp, defaultColumnLabels = EMPTY_RECORD, onColumnLabelsChange, pinnedColumnKeys: pinnedProp, defaultPinnedColumnKeys = EMPTY_STRINGS, onPinnedColumnKeysChange } = props;
911
1065
  const [rawOrder, setRawOrder] = useControllableState$1({
912
1066
  prop: columnOrderProp,
913
1067
  defaultProp: defaultColumnOrder ?? columnKeys,
@@ -944,6 +1098,36 @@ const EMPTY_RECORD = {};
944
1098
  columnOrder,
945
1099
  hiddenSet
946
1100
  ]);
1101
+ const [rawPinnedColumnKeys, setRawPinnedColumnKeys] = useControllableState$1({
1102
+ prop: pinnedProp,
1103
+ defaultProp: defaultPinnedColumnKeys,
1104
+ onChange: onPinnedColumnKeysChange
1105
+ });
1106
+ // Reconciled against `columnKeys` every render, the same way `columnOrder` is above --
1107
+ // a controlled `pinnedColumnKeys` a consumer persisted (e.g. a saved view) before a
1108
+ // column was removed from `columns` must not keep pinning a ghost key.
1109
+ const pinnedColumnKeys = useMemo(()=>reconcilePinnedColumns(rawPinnedColumnKeys ?? EMPTY_STRINGS, columnKeys), [
1110
+ rawPinnedColumnKeys,
1111
+ columnKeys
1112
+ ]);
1113
+ const pinnedSet = useMemo(()=>new Set(pinnedColumnKeys), [
1114
+ pinnedColumnKeys
1115
+ ]);
1116
+ const isColumnPinned = useCallback((key)=>pinnedSet.has(key), [
1117
+ pinnedSet
1118
+ ]);
1119
+ const pinColumn = useCallback((key)=>setRawPinnedColumnKeys((current = EMPTY_STRINGS)=>current.includes(key) ? current : [
1120
+ ...current,
1121
+ key
1122
+ ]), [
1123
+ setRawPinnedColumnKeys
1124
+ ]);
1125
+ const unpinColumn = useCallback((key)=>setRawPinnedColumnKeys((current = EMPTY_STRINGS)=>current.filter((existing)=>existing !== key)), [
1126
+ setRawPinnedColumnKeys
1127
+ ]);
1128
+ const togglePinColumn = useCallback((key)=>setRawPinnedColumnKeys((current = EMPTY_STRINGS)=>togglePinnedColumn(current, key)), [
1129
+ setRawPinnedColumnKeys
1130
+ ]);
947
1131
  const isColumnHidden = useCallback((key)=>hiddenSet.has(key), [
948
1132
  hiddenSet
949
1133
  ]);
@@ -988,22 +1172,30 @@ const EMPTY_RECORD = {};
988
1172
  columnKeys
989
1173
  ]);
990
1174
  // -- drag-to-reorder ---------------------------------------------------------------
991
- // Live state only (which column is currently being dragged) -- the styled layer
992
- // drives it by calling `dragOverColumn` as the pointer crosses OTHER header cells
993
- // (via `document.elementFromPoint`, since a captured pointer stops native
994
- // `pointerenter` from firing on siblings), which reorders immediately rather than
995
- // waiting for a drop. That is exactly what Attio's own header drag does (the column
996
- // being passed visibly swaps live), and it means `endColumnDrag` never has to also
997
- // commit a move -- there is nothing left to commit.
1175
+ // Live state only (which column is currently being dragged) -- the styled layer's
1176
+ // header cells are natively `draggable`, so `dragOverColumn` is driven straight off
1177
+ // each cell's own `onDragOver` (one real browser event per column the pointer
1178
+ // crosses), which reorders immediately rather than waiting for a drop. That is
1179
+ // exactly what Attio's own header drag does (the column being passed visibly swaps
1180
+ // live), and it means `endColumnDrag` never has to also commit a move -- there is
1181
+ // nothing left to commit.
998
1182
  const [draggingColumnKey, setDraggingColumnKey] = useState(null);
999
1183
  const beginColumnDrag = useCallback((key)=>setDraggingColumnKey(key), []);
1184
+ // Reads `draggingColumnKey` straight from this render's own closure rather than via
1185
+ // `setDraggingColumnKey`'s functional-updater form (an earlier version of this hook
1186
+ // nested the `reorderColumn` call inside that updater, to read a "live" value --
1187
+ // `draggingColumnKey` never actually CHANGES during a drag, so that state update was
1188
+ // pure ceremony, and nesting one hook's setState inside another's updater callback is
1189
+ // exactly what silently dropped the reorder in DataTable.columns.test.tsx's own
1190
+ // end-to-end drag test: a REAL `dragover` DOM event fired, `dragOverColumn` fired with
1191
+ // the right key, but `columnOrder` never actually moved). Each `onDragOver` is its own
1192
+ // discrete browser event (not a tight synchronous loop within one render), so a plain
1193
+ // closure read is exactly as live as the updater trick was trying to be.
1000
1194
  const dragOverColumn = useCallback((hoverKey)=>{
1001
- setDraggingColumnKey((current)=>{
1002
- if (!current || current === hoverKey) return current;
1003
- reorderColumn(current, hoverKey);
1004
- return current;
1005
- });
1195
+ if (!draggingColumnKey || draggingColumnKey === hoverKey) return;
1196
+ reorderColumn(draggingColumnKey, hoverKey);
1006
1197
  }, [
1198
+ draggingColumnKey,
1007
1199
  reorderColumn
1008
1200
  ]);
1009
1201
  const endColumnDrag = useCallback(()=>setDraggingColumnKey(null), []);
@@ -1039,10 +1231,15 @@ const EMPTY_RECORD = {};
1039
1231
  hiddenColumnKeys,
1040
1232
  columnWidths,
1041
1233
  columnLabels,
1234
+ pinnedColumnKeys,
1042
1235
  isColumnHidden,
1043
1236
  hideColumn,
1044
1237
  showColumn,
1045
1238
  toggleColumnVisibility,
1239
+ isColumnPinned,
1240
+ pinColumn,
1241
+ unpinColumn,
1242
+ togglePinColumn,
1046
1243
  getColumnLabel,
1047
1244
  renameColumn,
1048
1245
  getColumnWidth,
@@ -1691,7 +1888,7 @@ function useDataTableRowContext({ strict = true } = {}) {
1691
1888
  return context;
1692
1889
  }
1693
1890
  const DataTableRoot = /*#__PURE__*/ forwardRef((props, ref)=>{
1694
- const { sort, defaultSort, onSortChange, rowIds, selectable, selectedIds, defaultSelectedIds, onSelectionChange, query, defaultQuery, onQueryChange, toolbarSorts, defaultToolbarSorts, onToolbarSortsChange, toolbarFilters, defaultToolbarFilters, onToolbarFiltersChange, columnKeys, columnOrder, defaultColumnOrder, onColumnOrderChange, hiddenColumnKeys, defaultHiddenColumnKeys, onHiddenColumnKeysChange, columnWidths, defaultColumnWidths, onColumnWidthsChange, columnLabels, defaultColumnLabels, onColumnLabelsChange, columnCalcOps, defaultColumnCalcOps, onColumnCalcOpsChange, onEdit, onLoadMore, hasMore, loadingMore, ...otherProps } = props;
1891
+ const { sort, defaultSort, onSortChange, rowIds, selectable, selectedIds, defaultSelectedIds, onSelectionChange, query, defaultQuery, onQueryChange, toolbarSorts, defaultToolbarSorts, onToolbarSortsChange, toolbarFilters, defaultToolbarFilters, onToolbarFiltersChange, columnKeys, columnOrder, defaultColumnOrder, onColumnOrderChange, hiddenColumnKeys, defaultHiddenColumnKeys, onHiddenColumnKeysChange, columnWidths, defaultColumnWidths, onColumnWidthsChange, columnLabels, defaultColumnLabels, onColumnLabelsChange, pinnedColumnKeys, defaultPinnedColumnKeys, onPinnedColumnKeysChange, columnCalcOps, defaultColumnCalcOps, onColumnCalcOpsChange, onEdit, onLoadMore, hasMore, loadingMore, ...otherProps } = props;
1695
1892
  const api = useDataTable({
1696
1893
  sort,
1697
1894
  defaultSort,
@@ -1723,6 +1920,9 @@ const DataTableRoot = /*#__PURE__*/ forwardRef((props, ref)=>{
1723
1920
  columnLabels,
1724
1921
  defaultColumnLabels,
1725
1922
  onColumnLabelsChange,
1923
+ pinnedColumnKeys,
1924
+ defaultPinnedColumnKeys,
1925
+ onPinnedColumnKeysChange,
1726
1926
  columnCalcOps,
1727
1927
  defaultColumnCalcOps,
1728
1928
  onColumnCalcOpsChange,
@@ -1810,6 +2010,132 @@ const DataTableCell$1 = /*#__PURE__*/ forwardRef((props, ref)=>{
1810
2010
  });
1811
2011
  DataTableCell$1.displayName = "DataTableCell";
1812
2012
 
2013
+ const EMPTY_VIEWS = [];
2014
+ function readStoredViews(storageKey) {
2015
+ if (!storageKey || typeof window === "undefined") return EMPTY_VIEWS;
2016
+ try {
2017
+ return deserializeDataTableViews(window.localStorage.getItem(storageKey));
2018
+ } catch {
2019
+ // A private-browsing tab / blocked storage throws on access, not just on quota --
2020
+ // this hook degrades to in-memory-only rather than crash the table over it.
2021
+ return EMPTY_VIEWS;
2022
+ }
2023
+ }
2024
+ /** A reasonably unique id for a newly created view -- `crypto.randomUUID` where it
2025
+ * exists (every real browser + modern Node), a plain timestamp+random fallback
2026
+ * otherwise (older jsdom/test environments) so this hook never throws just because a
2027
+ * test runner's `crypto` is a stub. */ function generateViewId() {
2028
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
2029
+ return crypto.randomUUID();
2030
+ }
2031
+ return `view-${Date.now()}-${Math.random().toString(36).slice(2)}`;
2032
+ }
2033
+ /**
2034
+ * Owns the saved-views LIST (create/rename/delete/select) and its default persistence
2035
+ * (localStorage, pluggable away by controlling `views`/`onViewsChange` instead) -- the
2036
+ * same controllable shape every other DataTable state hook already uses
2037
+ * (`useDataTableColumns`, `useDataTableToolbarSort`, ...). Read `DataTableViewsControl`
2038
+ * (`views.tsx`, the styled layer) for how a consumer wires `captureState`/`applyState`
2039
+ * around this to actually save/restore column + sort + filter state.
2040
+ */ function useDataTableViews(props) {
2041
+ const { views: viewsProp, defaultViews = EMPTY_VIEWS, onViewsChange, activeViewId: activeViewIdProp, defaultActiveViewId = null, onActiveViewIdChange, storageKey } = props;
2042
+ // Lazy, ONE-TIME read of localStorage as this render's default -- re-reading it on
2043
+ // every render (rather than a lazy ref) would clobber whatever the user just did in
2044
+ // THIS tab with whatever another tab most recently wrote. Only fires at all when this
2045
+ // hook truly owns persistence: `views` is uncontrolled AND a `storageKey` was given.
2046
+ const initialViewsRef = useRef(null);
2047
+ if (initialViewsRef.current === null) {
2048
+ if (viewsProp !== undefined) {
2049
+ initialViewsRef.current = defaultViews;
2050
+ } else {
2051
+ const stored = readStoredViews(storageKey);
2052
+ // Nothing in storage yet (first run, or no `storageKey` at all) -- seed from
2053
+ // `defaultViews` instead of an empty list, matching every other hook's own
2054
+ // `defaultProp` semantics.
2055
+ initialViewsRef.current = stored.length > 0 ? stored : defaultViews;
2056
+ }
2057
+ }
2058
+ const [views = EMPTY_VIEWS, setViews] = useControllableState$1({
2059
+ prop: viewsProp,
2060
+ defaultProp: initialViewsRef.current,
2061
+ onChange: onViewsChange
2062
+ });
2063
+ // Persists every change back to `storageKey` -- same "only when this hook owns
2064
+ // persistence" gate as the lazy read above. Skips the FIRST render (the effect would
2065
+ // otherwise immediately re-write back the exact bytes it just read, or stomp an
2066
+ // empty default over a controlled consumer's storage before it ever mounts).
2067
+ const skipFirstPersistRef = useRef(true);
2068
+ useEffect(()=>{
2069
+ if (viewsProp !== undefined || !storageKey || typeof window === "undefined") return;
2070
+ if (skipFirstPersistRef.current) {
2071
+ skipFirstPersistRef.current = false;
2072
+ return;
2073
+ }
2074
+ try {
2075
+ window.localStorage.setItem(storageKey, serializeDataTableViews(views));
2076
+ } catch {
2077
+ // Storage full/blocked -- the view still exists in memory for this session.
2078
+ }
2079
+ }, [
2080
+ views,
2081
+ viewsProp,
2082
+ storageKey
2083
+ ]);
2084
+ const [activeViewId = null, setActiveViewId] = useControllableState$1({
2085
+ prop: activeViewIdProp,
2086
+ defaultProp: defaultActiveViewId,
2087
+ onChange: onActiveViewIdChange
2088
+ });
2089
+ const activeView = views.find((view)=>view.id === activeViewId) ?? null;
2090
+ const createView = useCallback((name, state)=>{
2091
+ const id = generateViewId();
2092
+ setViews((current = EMPTY_VIEWS)=>upsertDataTableView(current, {
2093
+ id,
2094
+ name,
2095
+ state
2096
+ }));
2097
+ setActiveViewId(id);
2098
+ return id;
2099
+ }, [
2100
+ setViews,
2101
+ setActiveViewId
2102
+ ]);
2103
+ const updateView = useCallback((id, state)=>{
2104
+ setViews((current = EMPTY_VIEWS)=>{
2105
+ const existing = current.find((view)=>view.id === id);
2106
+ return existing ? upsertDataTableView(current, {
2107
+ ...existing,
2108
+ state
2109
+ }) : current;
2110
+ });
2111
+ }, [
2112
+ setViews
2113
+ ]);
2114
+ const renameView = useCallback((id, name)=>setViews((current = EMPTY_VIEWS)=>renameDataTableView(current, id, name)), [
2115
+ setViews
2116
+ ]);
2117
+ const deleteView = useCallback((id)=>{
2118
+ setViews((current = EMPTY_VIEWS)=>removeDataTableView(current, id));
2119
+ setActiveViewId((current)=>current === id ? null : current);
2120
+ }, [
2121
+ setViews,
2122
+ setActiveViewId
2123
+ ]);
2124
+ const selectView = useCallback((id)=>setActiveViewId(id), [
2125
+ setActiveViewId
2126
+ ]);
2127
+ return {
2128
+ views,
2129
+ activeViewId,
2130
+ activeView,
2131
+ createView,
2132
+ updateView,
2133
+ renameView,
2134
+ deleteView,
2135
+ selectView
2136
+ };
2137
+ }
2138
+
1813
2139
  function r(e) {
1814
2140
  var t, f, n = "";
1815
2141
  if ("string" == typeof e || "number" == typeof e) n += e;
@@ -2208,7 +2534,7 @@ function formatDateTimeCell(value, locale) {
2208
2534
  minute: "2-digit"
2209
2535
  }).format(date);
2210
2536
  }
2211
- function EntityCell({ value, className, nameClassName }) {
2537
+ function EntityCell({ value, className, nameClassName, actionsClassName, actionClassName, column, row, openPreviewLabel }) {
2212
2538
  const entity = typeof value === "object" && value !== null ? value : {
2213
2539
  name: String(value ?? "")
2214
2540
  };
@@ -2231,6 +2557,21 @@ function EntityCell({ value, className, nameClassName }) {
2231
2557
  /*#__PURE__*/ jsx("span", {
2232
2558
  className: nameClassName,
2233
2559
  children: entity.name
2560
+ }),
2561
+ column?.onOpenPreview && row !== undefined && /*#__PURE__*/ jsx("span", {
2562
+ className: actionsClassName,
2563
+ children: /*#__PURE__*/ jsx("button", {
2564
+ type: "button",
2565
+ className: actionClassName,
2566
+ "aria-label": openPreviewLabel ?? "Open preview",
2567
+ onClick: (event)=>{
2568
+ event.stopPropagation();
2569
+ column.onOpenPreview?.(row);
2570
+ },
2571
+ children: /*#__PURE__*/ jsx(IconEyeLine_default, {
2572
+ size: 16
2573
+ })
2574
+ })
2234
2575
  })
2235
2576
  ]
2236
2577
  });
@@ -2335,76 +2676,121 @@ function RatingCell({ value, maxRating = 5 }) {
2335
2676
  });
2336
2677
  }
2337
2678
 
2338
- /** The subset of `useDataTableContext()` every "resolve which columns to actually
2339
- * render, in what order, under what label/width" helper below needs -- narrowed so
2340
- * each helper's own signature documents exactly what it reads, rather than the whole
2341
- * table API. */ function useEffectiveColumns(columns) {
2342
- const { visibleColumnOrder, getColumnLabel, getColumnWidth } = useDataTableContext();
2679
+ /** Fallback width (px) used to compute a pinned column's cumulative sticky offset when
2680
+ * it has no explicit `width` and hasn't been drag-resized -- pinning needs a STATIC
2681
+ * number to put in an inline `insetInlineStart`, and `table-layout: fixed` only
2682
+ * decides how an unset column's share of the leftover width actually renders at paint
2683
+ * time (something no amount of JS math here can know ahead of it). Matches
2684
+ * `clampColumnWidth`'s own floor (react-headless's `dom.ts`) -- a real pinned column
2685
+ * narrower than this only needs its offset "wide enough not to overlap", not exact. */ const DEFAULT_PINNED_COLUMN_WIDTH = 180;
2686
+ /**
2687
+ * Every column this table actually renders, in RENDER order: any pinned columns first
2688
+ * (their own relative order preserved from `visibleColumnOrder`, not a separate pin-
2689
+ * order of their own), then everything else in normal order -- resolved label/width,
2690
+ * and this file's own sticky-left bookkeeping (`pinned`/`pinOffset`/`pinnedEdge`). Read
2691
+ * by the header, the body, the ColumnCalc footer AND the `<colgroup>` alike -- all four
2692
+ * must agree on this exact order, since a `<colgroup>`'s `<col>`s are matched
2693
+ * POSITIONALLY to every row's cells; splitting "order" (here) from "which one is
2694
+ * pinned" into two independently-ordered helpers would let a `<colgroup>` built from
2695
+ * one and a header row built from the other drift out of sync under `table-layout:
2696
+ * fixed`'s own column-to-cell matching.
2697
+ */ function useEffectiveColumns(columns, options) {
2698
+ const { visibleColumnOrder, getColumnLabel, getColumnWidth, pinnedColumnKeys } = useDataTableContext();
2699
+ const { selectable, stickyFirst } = options;
2343
2700
  return React.useMemo(()=>{
2344
2701
  const byKey = new Map(columns.map((column)=>[
2345
2702
  column.key,
2346
2703
  column
2347
2704
  ]));
2348
- return visibleColumnOrder.map((key)=>byKey.get(key)).filter((column)=>Boolean(column)).map((column)=>({
2705
+ const visibleKeySet = new Set(visibleColumnOrder);
2706
+ const explicitPins = new Set((pinnedColumnKeys ?? []).filter((key)=>byKey.has(key) && visibleKeySet.has(key)));
2707
+ // Legacy fallback (DataTable.columns.test.tsx's own `stickyFirst` tests, predating
2708
+ // per-column pin): no EXPLICIT pin at all, `stickyFirst` pins exactly the first
2709
+ // visible column -- the single-column behavior this file now generalizes to a
2710
+ // whole pinned GROUP.
2711
+ const pinnedSet = explicitPins.size > 0 ? explicitPins : stickyFirst && visibleColumnOrder.length > 0 ? new Set([
2712
+ visibleColumnOrder[0]
2713
+ ]) : explicitPins;
2714
+ // Stable partition: pinned columns first (their relative order among THEMSELVES
2715
+ // preserved from `visibleColumnOrder`), then every other column, also in its
2716
+ // existing relative order. `Array.prototype.sort` is spec-stable (ES2019+).
2717
+ const ordered = [
2718
+ ...visibleColumnOrder
2719
+ ].sort((a, b)=>{
2720
+ const aPinned = pinnedSet.has(a) ? 0 : 1;
2721
+ const bPinned = pinnedSet.has(b) ? 0 : 1;
2722
+ return aPinned - bPinned;
2723
+ });
2724
+ let cursor = selectable ? 40 : 0;
2725
+ let pinnedCount = 0;
2726
+ const entries = ordered.map((key)=>byKey.get(key)).filter((column)=>Boolean(column)).map((column)=>{
2727
+ const width = getColumnWidth(column.key) ?? column.width;
2728
+ const pinned = pinnedSet.has(column.key);
2729
+ const pinOffset = pinned ? cursor : 0;
2730
+ if (pinned) {
2731
+ cursor += width ?? DEFAULT_PINNED_COLUMN_WIDTH;
2732
+ pinnedCount += 1;
2733
+ }
2734
+ return {
2349
2735
  column,
2350
2736
  label: getColumnLabel(column.key, column.header),
2351
- width: getColumnWidth(column.key) ?? column.width
2352
- }));
2737
+ width,
2738
+ pinned,
2739
+ pinOffset,
2740
+ pinnedEdge: false
2741
+ };
2742
+ });
2743
+ if (pinnedCount > 0) entries[pinnedCount - 1].pinnedEdge = true;
2744
+ return entries;
2353
2745
  }, [
2354
2746
  columns,
2355
2747
  visibleColumnOrder,
2356
2748
  getColumnLabel,
2357
- getColumnWidth
2358
- ]);
2359
- }
2360
- /** Sticky positioning for the leading/trailing visible cell of a row (header, body, or
2361
- * footer) -- `stickyFirst` pins the SELECTION cell when the table has one, plus the
2362
- * first data column; `stickyLast` always pins the last VISIBLE data column. Only the
2363
- * OUTERMOST sticky cell on each side gets `data-sticky-edge(-end)` -- that's the one
2364
- * whose shadow should reveal on scroll, not every sticky cell.
2365
- *
2366
- * When both a selection column and a sticky first data column are present, the edge
2367
- * is the data column (e.g. Company), not the 40px selection cell: the data column is
2368
- * ALSO `position: sticky`, sitting immediately to its right, so a shadow cast from the
2369
- * selection cell's trailing edge would render directly underneath that opaque sticky
2370
- * cell and never actually be visible. Putting `data-sticky-edge` on the trailing-most
2371
- * sticky-left cell is what makes the shadow render somewhere unobstructed -- past the
2372
- * whole pinned group, not between two members of it. */ function stickyProps(options) {
2373
- const { selectable, stickyFirst, stickyLast, isSelectionCell, isFirst, isLast } = options;
2374
- if (stickyFirst && isSelectionCell) {
2375
- // Still sticky either way. The edge marker only belongs here when there is no
2376
- // sticky first DATA column to hand it to instead (i.e. no columns at all) --
2377
- // otherwise that data column is the true trailing edge of the pinned group.
2378
- return selectable ? {
2379
- "data-sticky": "",
2380
- style: {
2381
- insetInlineStart: 0
2382
- }
2383
- } : {
2384
- "data-sticky": "",
2385
- "data-sticky-edge": "",
2386
- style: {
2387
- insetInlineStart: 0
2388
- }
2389
- };
2390
- }
2391
- if (stickyFirst && isFirst && !selectable) {
2392
- return {
2393
- "data-sticky": "",
2394
- "data-sticky-edge": "",
2395
- style: {
2396
- insetInlineStart: 0
2397
- }
2398
- };
2399
- }
2400
- if (stickyFirst && isFirst && selectable) {
2401
- // The trailing edge of the pinned group -- past the 40px selection cell, so this
2402
- // is where the scroll shadow actually renders unobstructed.
2749
+ getColumnWidth,
2750
+ pinnedColumnKeys,
2751
+ selectable,
2752
+ stickyFirst
2753
+ ]);
2754
+ }
2755
+ /** The 40px selection column's own sticky-left state -- `stickyFirst` (the table-wide
2756
+ * prop) alone undercounts "should the checkbox column stick" the moment ANY per-column
2757
+ * pin is live, controlled or not, since the live pinned SET only exists once
2758
+ * `DataTablePrimitiveRoot`'s provider has mounted (an uncontrolled consumer never
2759
+ * hands its pinned columns back up as a prop for `DataTable.tsx` to read directly).
2760
+ * Mirrors `DataTable.tsx`'s own `resolvedStickyLast = stickyLast ||
2761
+ * columns.some(actions)` widening, just resolved one level down (live STATE, not
2762
+ * static column config) -- read via context from a component under the provider, not
2763
+ * computed above it. */ function useSelectionStickyFirst(stickyFirst) {
2764
+ const { pinnedColumnKeys } = useDataTableContext();
2765
+ return stickyFirst || (pinnedColumnKeys?.length ?? 0) > 0;
2766
+ }
2767
+ /** Sticky positioning for the 40px SELECTION cell only (header/body/footer) -- data
2768
+ * columns use their own `pinned`/`pinOffset`/`pinnedEdge` (`useEffectiveColumns`,
2769
+ * above) instead, via `pinnedCellProps` below. The selection cell is always the
2770
+ * leading edge of the pinned-left group when it's sticky at all, so it never itself
2771
+ * carries `data-sticky-edge` -- the trailing-most pinned DATA column does (its own
2772
+ * `pinnedEdge`), the same split the original single-column `stickyFirst` already drew
2773
+ * between the selection cell and Company/Name. */ function selectionStickyProps(stickyFirst) {
2774
+ return stickyFirst ? {
2775
+ "data-sticky": "",
2776
+ style: {
2777
+ insetInlineStart: 0
2778
+ }
2779
+ } : {};
2780
+ }
2781
+ /** Sticky positioning for one DATA cell (header, body, or ColumnCalc footer) -- pinned-
2782
+ * left (this column's own `pinOffset`, `data-sticky-edge` only on the group's
2783
+ * trailing-most member) takes priority over sticky-right (`stickyLast`, always just
2784
+ * the last VISIBLE column, e.g. an `actions` column) since a column can only stick to
2785
+ * one edge. */ function pinnedCellProps(entry, stickyLast, isLast) {
2786
+ if (entry.pinned) {
2403
2787
  return {
2404
2788
  "data-sticky": "",
2405
- "data-sticky-edge": "",
2789
+ ...entry.pinnedEdge ? {
2790
+ "data-sticky-edge": ""
2791
+ } : {},
2406
2792
  style: {
2407
- insetInlineStart: 40
2793
+ insetInlineStart: entry.pinOffset
2408
2794
  }
2409
2795
  };
2410
2796
  }
@@ -2744,7 +3130,7 @@ const TextFieldTextarea = /*#__PURE__*/ forwardRef(({ className, autoresize = tr
2744
3130
  });
2745
3131
  TextFieldTextarea.displayName = "TextFieldTextarea";
2746
3132
 
2747
- __insertCSS(".seed-data-table__root{box-sizing:border-box;display:flex;flex-direction:column;width:100%;border-width:1px;border-style:solid;font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.seed-data-table__table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.seed-data-table__headerCell{box-sizing:border-box;position:sticky;top:0;z-index:2;vertical-align:middle;text-align:start;padding:0;height:var(--seed-dimension-x10);background-color:var(--seed-color-bg-layer-default);border-top:1px solid var(--seed-color-stroke-neutral-muted);border-bottom:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-inline-start:none;color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-medium);letter-spacing:-.14px}.seed-data-table__headerCell:last-child{border-inline-end:none}.seed-data-table__headerCell[data-sortable]{cursor:pointer;user-select:none}.seed-data-table__headerCell [data-chevron]{opacity:0;transition:opacity .12s}.seed-data-table__headerCell[data-sortable]:hover [data-chevron]{opacity:.6}.seed-data-table__headerCell[data-sorted] [data-chevron]{opacity:1;color:var(--seed-color-fg-neutral)}.seed-data-table__headerCell:hover [data-column-menu]{opacity:1}.seed-data-table__headerCell [data-column-menu]:focus-visible,.seed-data-table__headerCell [data-column-menu][data-open]{opacity:1}.seed-data-table__headerCell[data-dragging]{opacity:.5}.seed-data-table__headerCell[data-sticky]{position:sticky;z-index:3;background-color:var(--seed-color-bg-layer-default)}.seed-data-table__headerCell{outline:var(--seed-dimension-x0_5) solid transparent;outline-offset:calc(var(--seed-dimension-x0_5) * -1)}.seed-data-table__headerCell:is(:focus-visible,[data-focus-visible]){outline:var(--seed-dimension-x0_5) solid var(--seed-color-stroke-focus-ring);outline-offset:calc(var(--seed-dimension-x0_5) * -1)}.seed-data-table__headerCell .seed-data-table-resize-handle{position:absolute;top:0;inset-inline-end:calc(7px / -2);width:7px;height:100%;z-index:4;display:flex;align-items:center;justify-content:center;cursor:col-resize;touch-action:none}.seed-data-table__headerCell .seed-data-table-resize-handle-inner{width:3px;height:100%;border-radius:3px;background-color:#0298d9;opacity:0;transition:opacity .1s}.seed-data-table__headerCell .seed-data-table-resize-handle:hover .seed-data-table-resize-handle-inner,.seed-data-table__headerCell .seed-data-table-resize-handle[data-resizing] .seed-data-table-resize-handle-inner{opacity:1}.seed-data-table__headerCellInner{box-sizing:border-box;display:flex;align-items:center;width:100%;height:100%;min-width:0;gap:var(--seed-dimension-x1_5);padding-inline:var(--seed-dimension-x3)}.seed-data-table__headerCellLabel{min-width:0;flex:1 1 0%;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__headerCellIcon{flex-shrink:0;margin-inline-start:auto;display:inline-flex;align-items:center;justify-content:center;width:var(--seed-dimension-x4);height:var(--seed-dimension-x4);color:var(--seed-color-fg-neutral-subtle);border:none;background:0 0;padding:0;font:inherit;cursor:pointer}.seed-data-table__headerCellIcon[data-active]{color:var(--seed-color-fg-neutral)}.seed-data-table__headerCellIcon[data-column-menu]{opacity:0;transition:opacity .12s}.seed-data-table__row{position:relative;background-color:var(--seed-color-bg-layer-default);--seed-data-table-row-bg:var(--seed-color-bg-layer-default)}.seed-data-table__row[data-clickable]{cursor:pointer}.seed-data-table__row:is([aria-selected=true],[data-selected]){background-color:color-mix(in srgb,#0298d9 10%,var(--seed-color-bg-layer-default));--seed-data-table-row-bg:color-mix(in srgb, #0298d9 10%, var(--seed-color-bg-layer-default))}.seed-data-table__row:is([aria-selected=true],[data-selected]):is(:hover,[data-hover]){background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 3%,color-mix(in srgb,#0298d9 10%,var(--seed-color-bg-layer-default)));--seed-data-table-row-bg:color-mix(in srgb, var(--seed-color-fg-neutral) 3%, color-mix(in srgb, #0298d9 10%, var(--seed-color-bg-layer-default)))}.seed-data-table__cell{box-sizing:border-box;position:relative;vertical-align:middle;text-align:start;height:var(--seed-dimension-x9);border-bottom:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-top:none;border-inline-start:none;padding-block:0;padding-inline:var(--seed-dimension-x3);color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-regular);letter-spacing:-.14px;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__cell:last-child{border-inline-end:none}tbody tr:last-child .seed-data-table__cell{border-bottom:none}.seed-data-table__cell[data-numeric]{text-align:end;font-variant-numeric:tabular-nums}.seed-data-table__cell[data-sticky]{position:sticky;z-index:1;background-color:var(--seed-data-table-row-bg)}.seed-data-table__cell[data-editable]{cursor:default}.seed-data-table__cell .seed-data-table-edit-picker{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);min-width:0}.seed-data-table__cell .seed-data-table-edit-pending{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);animation:rotate .6s linear infinite}.seed-data-table__cell .seed-data-table-edit-error{position:absolute;top:100%;inset-inline-start:var(--seed-dimension-x3);inset-inline-end:var(--seed-dimension-x3);z-index:2;padding-top:2px;font-size:12px;line-height:1.3;color:var(--seed-color-fg-critical);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__entity{display:flex;align-items:center;min-width:0;gap:var(--seed-dimension-x1_5)}.seed-data-table__entityName{min-width:0;font-weight:var(--seed-font-weight-medium);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__tagList{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);overflow:hidden;min-width:0}.seed-data-table__link{color:var(--seed-color-fg-neutral);text-decoration:none;min-width:0;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__link:is(:hover,[data-hover]){text-decoration:underline}.seed-data-table__toolbar{box-sizing:border-box;display:flex;align-items:center;width:100%;flex-shrink:0;min-height:49px;gap:var(--seed-dimension-x2);padding-inline:var(--seed-dimension-x3);border-top:1px solid var(--seed-color-stroke-neutral-muted)}.seed-data-table__search{position:relative;display:inline-flex;align-items:center;flex:1 1 0%;max-width:280px}.seed-data-table__search svg{position:absolute;inset-inline-start:var(--seed-dimension-x2);width:var(--seed-dimension-x4);height:var(--seed-dimension-x4);color:var(--seed-color-fg-neutral-muted);pointer-events:none}.seed-data-table__search input{width:100%;height:var(--seed-dimension-x8);padding-inline-start:var(--seed-dimension-x7);padding-inline-end:var(--seed-dimension-x2);border:none;border-radius:var(--seed-radius-r2);background-color:var(--seed-color-bg-layer-default);box-shadow:inset 0 0 0 1px var(--seed-color-stroke-neutral-weak);font-family:inherit;font-size:var(--seed-font-size-t4);color:var(--seed-color-fg-neutral);outline:0;transition:box-shadow .1s var(--seed-timing-function-easing)}.seed-data-table__search input::placeholder{color:var(--seed-color-fg-neutral-subtle)}.seed-data-table__search input:focus{box-shadow:inset 0 0 0 2px var(--seed-color-stroke-neutral-contrast)}.seed-data-table__count{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);font-size:var(--seed-font-size-t3);font-variant-numeric:tabular-nums}.seed-data-table__toolbarEnd{flex-shrink:0;margin-inline-start:auto;display:inline-flex;align-items:center;gap:var(--seed-dimension-x2)}.seed-data-table__scrollArea{position:relative;display:flex;flex-direction:column;width:100%;min-width:0;flex:1 1 auto;min-height:0;overflow-x:auto;overflow-y:auto}.seed-data-table__scrollArea[data-scrolled-start] [data-sticky-edge]{clip-path:inset(0 -38px 0 0);box-shadow:6px 0 16px 4px rgba(0,0,0,.12)}.seed-data-table__scrollArea[data-scrolled-end] [data-sticky-edge-end]{clip-path:inset(0 0 0 -38px);box-shadow:-6px 0 16px 4px rgba(0,0,0,.12)}.seed-data-table__footerCell{box-sizing:border-box;position:sticky;bottom:0;z-index:2;vertical-align:middle;padding:0;height:var(--seed-dimension-x9);background-color:var(--seed-color-bg-layer-default);border-top:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-inline-start:none}.seed-data-table__footerCell:last-child{border-inline-end:none}.seed-data-table__footerCell .seed-data-table-column-calc-trigger{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);width:100%;height:100%;min-width:0;margin:0;padding:0 var(--seed-dimension-x3);border:none;background:0 0;color:var(--seed-color-fg-neutral-subtle);font-family:inherit;font-size:var(--seed-font-size-t4);font-weight:var(--seed-font-weight-medium);white-space:nowrap;overflow:clip;cursor:pointer;transition:background-color .12s,color .12s}.seed-data-table__footerCell .seed-data-table-column-calc-trigger:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,transparent);color:var(--seed-color-fg-neutral)}.seed-data-table__footerCell .seed-data-table-column-calc-trigger[data-align=right]{justify-content:flex-end}.seed-data-table__footerCell .seed-data-table-column-calc-trigger svg{flex-shrink:0;opacity:.7}.seed-data-table__footerCell .seed-data-table-column-calc-placeholder{overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__footerCell .seed-data-table-column-calc-value{min-width:0;flex-shrink:1;color:var(--seed-color-fg-neutral);font-variant-numeric:tabular-nums;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__footerCell .seed-data-table-column-calc-op{min-width:0;flex-shrink:1;color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__emptyState{box-sizing:border-box;text-align:center;padding-block:var(--seed-dimension-x8);padding-inline:var(--seed-dimension-x3);color:var(--seed-color-fg-neutral-subtle);font-size:var(--seed-font-size-t4)}.seed-data-table__loadingState{box-sizing:border-box;display:flex;align-items:center;justify-content:center;gap:10px;padding-block:var(--seed-dimension-x8);padding-inline:var(--seed-dimension-x3);color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-medium)}.seed-data-table__loadingState[data-inline]{padding-block:0;padding-inline:0;height:var(--seed-dimension-x9)}.seed-data-table__loadingState .seed-data-table-loading-spinner{flex-shrink:0;color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);animation:rotate .6s linear infinite}.seed-data-table__addRowCell{box-sizing:border-box;padding:0;border-top:none}.seed-data-table__addRow{box-sizing:border-box;display:flex;align-items:center;width:100%;margin:0;border:none;border-top:1px solid var(--seed-color-stroke-neutral-muted);background-color:var(--seed-color-bg-layer-default);height:var(--seed-dimension-x9);gap:var(--seed-dimension-x2);padding-inline:var(--seed-dimension-x2);color:var(--seed-color-fg-neutral-subtle);font-family:inherit;font-size:var(--seed-font-size-t4);cursor:pointer;transition:background-color .12s,color .12s}.seed-data-table__addRow:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,var(--seed-color-bg-layer-default));color:var(--seed-color-fg-neutral)}.seed-data-table__addRow svg{flex-shrink:0}.seed-data-table__selectionCell{text-align:center;padding:0}.seed-data-table__root--surface_card{border-color:var(--seed-color-stroke-neutral-muted);background-color:var(--seed-color-bg-layer-default);border-radius:var(--seed-radius-r3)}.seed-data-table__root--surface_bleed{border-color:var(--seed-color-bg-transparent);background-color:var(--seed-color-bg-transparent)}.seed-data-table__row--interactive_true{transition:background-color .12s}.seed-data-table__row--interactive_true:is(:hover,[data-hover]){background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 3%,transparent);--seed-data-table-row-bg:color-mix(in srgb, var(--seed-color-fg-neutral) 3%, var(--seed-color-bg-layer-default))}");
3133
+ __insertCSS(".seed-data-table__root{box-sizing:border-box;display:flex;flex-direction:column;width:100%;border-width:1px;border-style:solid;font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.seed-data-table__table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.seed-data-table__headerCell{box-sizing:border-box;position:sticky;top:0;z-index:2;vertical-align:middle;text-align:start;padding:0;height:var(--seed-dimension-x10);background-color:var(--seed-color-bg-layer-default);border-top:1px solid var(--seed-color-stroke-neutral-muted);border-bottom:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-inline-start:none;color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-medium);letter-spacing:-.14px}.seed-data-table__headerCell:last-child{border-inline-end:none}.seed-data-table__headerCell[data-sortable]{cursor:pointer;user-select:none}.seed-data-table__headerCell [data-chevron]{opacity:0;transition:opacity .12s}.seed-data-table__headerCell[data-sortable]:hover [data-chevron]{opacity:.6}.seed-data-table__headerCell[data-sorted] [data-chevron]{opacity:1;color:var(--seed-color-fg-neutral)}.seed-data-table__headerCell:hover [data-column-menu]{opacity:1}.seed-data-table__headerCell [data-column-menu]:focus-visible,.seed-data-table__headerCell [data-column-menu][data-open]{opacity:1}.seed-data-table__headerCell[data-dragging]{opacity:.5}.seed-data-table__headerCell[data-sticky]{position:sticky;z-index:3;background-color:var(--seed-color-bg-layer-default)}.seed-data-table__headerCell{outline:var(--seed-dimension-x0_5) solid transparent;outline-offset:calc(var(--seed-dimension-x0_5) * -1)}.seed-data-table__headerCell:is(:focus-visible,[data-focus-visible]){outline:var(--seed-dimension-x0_5) solid var(--seed-color-stroke-focus-ring);outline-offset:calc(var(--seed-dimension-x0_5) * -1)}.seed-data-table__headerCell .seed-data-table-resize-handle{position:absolute;top:0;inset-inline-end:calc(7px / -2);width:7px;height:100%;z-index:4;display:flex;align-items:center;justify-content:center;cursor:col-resize;touch-action:none}.seed-data-table__headerCell .seed-data-table-resize-handle-inner{width:3px;height:100%;border-radius:3px;background-color:#0298d9;opacity:0;transition:opacity .1s}.seed-data-table__headerCell .seed-data-table-resize-handle:hover .seed-data-table-resize-handle-inner,.seed-data-table__headerCell .seed-data-table-resize-handle[data-resizing] .seed-data-table-resize-handle-inner{opacity:1}.seed-data-table__headerCellInner{box-sizing:border-box;display:flex;align-items:center;width:100%;height:100%;min-width:0;gap:var(--seed-dimension-x1_5);padding-inline:var(--seed-dimension-x3)}.seed-data-table__headerCellLabel{min-width:0;flex:1 1 0%;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__headerCellIcon{flex-shrink:0;margin-inline-start:auto;display:inline-flex;align-items:center;justify-content:center;width:var(--seed-dimension-x4);height:var(--seed-dimension-x4);color:var(--seed-color-fg-neutral-subtle);border:none;background:0 0;padding:0;font:inherit;cursor:pointer}.seed-data-table__headerCellIcon[data-active]{color:var(--seed-color-fg-neutral)}.seed-data-table__headerCellIcon[data-column-menu]{opacity:0;transition:opacity .12s}.seed-data-table__row{position:relative;background-color:var(--seed-color-bg-layer-default);--seed-data-table-row-bg:var(--seed-color-bg-layer-default)}.seed-data-table__row[data-clickable]{cursor:pointer}.seed-data-table__row:is([aria-selected=true],[data-selected]){background-color:color-mix(in srgb,#0298d9 10%,var(--seed-color-bg-layer-default));--seed-data-table-row-bg:color-mix(in srgb, #0298d9 10%, var(--seed-color-bg-layer-default))}.seed-data-table__row:is([aria-selected=true],[data-selected]):is(:hover,[data-hover]){background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 3%,color-mix(in srgb,#0298d9 10%,var(--seed-color-bg-layer-default)));--seed-data-table-row-bg:color-mix(in srgb, var(--seed-color-fg-neutral) 3%, color-mix(in srgb, #0298d9 10%, var(--seed-color-bg-layer-default)))}.seed-data-table__cell{box-sizing:border-box;position:relative;vertical-align:middle;text-align:start;height:var(--seed-dimension-x9);border-bottom:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-top:none;border-inline-start:none;padding-block:0;padding-inline:var(--seed-dimension-x3);color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-regular);letter-spacing:-.14px;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__cell:last-child{border-inline-end:none}tbody tr:last-child .seed-data-table__cell{border-bottom:none}.seed-data-table__cell[data-numeric]{text-align:end;font-variant-numeric:tabular-nums}.seed-data-table__cell[data-sticky]{position:sticky;z-index:1;background-color:var(--seed-data-table-row-bg)}.seed-data-table__cell[data-editable]{cursor:default}.seed-data-table__cell .seed-data-table-edit-picker{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);min-width:0}.seed-data-table__cell .seed-data-table-edit-pending{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);animation:rotate .6s linear infinite}.seed-data-table__cell .seed-data-table-edit-error{position:absolute;top:100%;inset-inline-start:var(--seed-dimension-x3);inset-inline-end:var(--seed-dimension-x3);z-index:2;padding-top:2px;font-size:12px;line-height:1.3;color:var(--seed-color-fg-critical);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__entity{display:flex;align-items:center;min-width:0;gap:var(--seed-dimension-x1_5)}.seed-data-table__entityName{min-width:0;font-weight:var(--seed-font-weight-medium);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__tagList{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);overflow:hidden;min-width:0}.seed-data-table__entityActions{display:flex;align-items:center;gap:6px;margin-inline-start:auto;flex-shrink:0;opacity:0}.seed-data-table__entityActions:focus-within,tr:hover .seed-data-table__entityActions{opacity:1}.seed-data-table__entityAction{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin:0;padding:0;border:none;border-radius:6px;background:0 0;font-family:inherit;color:color-mix(in srgb,var(--seed-color-fg-neutral) 55%,transparent);cursor:pointer;flex-shrink:0}.seed-data-table__entityAction:hover{background:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,transparent);color:var(--seed-color-fg-neutral)}.seed-data-table__link{color:var(--seed-color-fg-neutral);text-decoration:none;min-width:0;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__link:is(:hover,[data-hover]){text-decoration:underline}.seed-data-table__toolbar{box-sizing:border-box;display:flex;align-items:center;width:100%;flex-shrink:0;min-height:49px;gap:var(--seed-dimension-x2);padding-inline:var(--seed-dimension-x3);border-top:1px solid var(--seed-color-stroke-neutral-muted)}.seed-data-table__search{position:relative;display:inline-flex;align-items:center;flex:1 1 0%;max-width:280px}.seed-data-table__search svg{position:absolute;inset-inline-start:var(--seed-dimension-x2);width:var(--seed-dimension-x4);height:var(--seed-dimension-x4);color:var(--seed-color-fg-neutral-muted);pointer-events:none}.seed-data-table__search input{width:100%;height:var(--seed-dimension-x8);padding-inline-start:var(--seed-dimension-x7);padding-inline-end:var(--seed-dimension-x2);border:none;border-radius:var(--seed-radius-r2);background-color:var(--seed-color-bg-layer-default);box-shadow:inset 0 0 0 1px var(--seed-color-stroke-neutral-weak);font-family:inherit;font-size:var(--seed-font-size-t4);color:var(--seed-color-fg-neutral);outline:0;transition:box-shadow .1s var(--seed-timing-function-easing)}.seed-data-table__search input::placeholder{color:var(--seed-color-fg-neutral-subtle)}.seed-data-table__search input:focus{box-shadow:inset 0 0 0 2px var(--seed-color-stroke-neutral-contrast)}.seed-data-table__count{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);font-size:var(--seed-font-size-t3);font-variant-numeric:tabular-nums}.seed-data-table__toolbarEnd{flex-shrink:0;margin-inline-start:auto;display:inline-flex;align-items:center;gap:var(--seed-dimension-x2)}.seed-data-table__scrollArea{position:relative;display:flex;flex-direction:column;width:100%;min-width:0;flex:1 1 auto;min-height:0;overflow-x:auto;overflow-y:auto}.seed-data-table__scrollArea[data-scrolled-start] [data-sticky-edge]{clip-path:inset(0 -38px 0 0);box-shadow:6px 0 16px 4px rgba(0,0,0,.12)}.seed-data-table__scrollArea[data-scrolled-end] [data-sticky-edge-end]{clip-path:inset(0 0 0 -38px);box-shadow:-6px 0 16px 4px rgba(0,0,0,.12)}.seed-data-table__footerCell{box-sizing:border-box;position:sticky;bottom:0;z-index:2;vertical-align:middle;padding:0;height:var(--seed-dimension-x9);background-color:var(--seed-color-bg-layer-default);border-top:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-inline-start:none}.seed-data-table__footerCell:last-child{border-inline-end:none}.seed-data-table__footerCell .seed-data-table-column-calc-trigger{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);width:100%;height:100%;min-width:0;margin:0;padding:0 var(--seed-dimension-x3);border:none;background:0 0;color:var(--seed-color-fg-neutral-subtle);font-family:inherit;font-size:var(--seed-font-size-t4);font-weight:var(--seed-font-weight-medium);white-space:nowrap;overflow:clip;cursor:pointer;transition:background-color .12s,color .12s}.seed-data-table__footerCell .seed-data-table-column-calc-trigger:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,transparent);color:var(--seed-color-fg-neutral)}.seed-data-table__footerCell .seed-data-table-column-calc-trigger[data-align=right]{justify-content:flex-end}.seed-data-table__footerCell .seed-data-table-column-calc-trigger svg{flex-shrink:0;opacity:.7}.seed-data-table__footerCell .seed-data-table-column-calc-placeholder{overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__footerCell .seed-data-table-column-calc-value{min-width:0;flex-shrink:1;color:var(--seed-color-fg-neutral);font-variant-numeric:tabular-nums;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__footerCell .seed-data-table-column-calc-op{min-width:0;flex-shrink:1;color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__emptyState{box-sizing:border-box;text-align:center;padding-block:var(--seed-dimension-x8);padding-inline:var(--seed-dimension-x3);color:var(--seed-color-fg-neutral-subtle);font-size:var(--seed-font-size-t4)}.seed-data-table__loadingState{box-sizing:border-box;display:flex;align-items:center;justify-content:center;gap:10px;padding-block:var(--seed-dimension-x8);padding-inline:var(--seed-dimension-x3);color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-medium)}.seed-data-table__loadingState[data-inline]{padding-block:0;padding-inline:0;height:var(--seed-dimension-x9)}.seed-data-table__loadingState .seed-data-table-loading-spinner{flex-shrink:0;color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);animation:rotate .6s linear infinite}.seed-data-table__addRowCell{box-sizing:border-box;padding:0;border-top:none}.seed-data-table__addRow{box-sizing:border-box;display:flex;align-items:center;width:100%;margin:0;border:none;border-top:1px solid var(--seed-color-stroke-neutral-muted);background-color:var(--seed-color-bg-layer-default);height:var(--seed-dimension-x9);gap:var(--seed-dimension-x2);padding-inline:var(--seed-dimension-x2);color:var(--seed-color-fg-neutral-subtle);font-family:inherit;font-size:var(--seed-font-size-t4);cursor:pointer;transition:background-color .12s,color .12s}.seed-data-table__addRow:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,var(--seed-color-bg-layer-default));color:var(--seed-color-fg-neutral)}.seed-data-table__addRow svg{flex-shrink:0}.seed-data-table__selectionCell{text-align:center;padding:0}.seed-data-table__root--surface_card{border-color:var(--seed-color-stroke-neutral-muted);background-color:var(--seed-color-bg-layer-default);border-radius:var(--seed-radius-r3)}.seed-data-table__root--surface_bleed{border-color:var(--seed-color-bg-transparent);background-color:var(--seed-color-bg-transparent)}.seed-data-table__row--interactive_true{transition:background-color .12s}.seed-data-table__row--interactive_true:is(:hover,[data-hover]){background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 3%,transparent);--seed-data-table-row-bg:color-mix(in srgb, var(--seed-color-fg-neutral) 3%, var(--seed-color-bg-layer-default))}");
2748
3134
 
2749
3135
  const createClassName = (className, variants, compoundVariants = [])=>{
2750
3136
  const variantKeys = Object.keys(variants);
@@ -2839,6 +3225,14 @@ const dataTableSlotNames = [
2839
3225
  "link",
2840
3226
  "seed-data-table__link"
2841
3227
  ],
3228
+ [
3229
+ "entityActions",
3230
+ "seed-data-table__entityActions"
3231
+ ],
3232
+ [
3233
+ "entityAction",
3234
+ "seed-data-table__entityAction"
3235
+ ],
2842
3236
  [
2843
3237
  "toolbar",
2844
3238
  "seed-data-table__toolbar"
@@ -2888,11 +3282,11 @@ const dataTableSlotNames = [
2888
3282
  "seed-data-table__selectionCell"
2889
3283
  ]
2890
3284
  ];
2891
- const defaultVariant$4 = {
3285
+ const defaultVariant$6 = {
2892
3286
  "surface": "card",
2893
3287
  "interactive": false
2894
3288
  };
2895
- const compoundVariants$4 = [];
3289
+ const compoundVariants$6 = [];
2896
3290
  const dataTableVariantMap = {
2897
3291
  "surface": [
2898
3292
  "card",
@@ -2907,7 +3301,7 @@ function dataTable(props) {
2907
3301
  return Object.fromEntries(dataTableSlotNames.map(([slot, className])=>{
2908
3302
  return [
2909
3303
  slot,
2910
- createClassName(className, mergeVariants(defaultVariant$4, props), compoundVariants$4)
3304
+ createClassName(className, mergeVariants(defaultVariant$6, props), compoundVariants$6)
2911
3305
  ];
2912
3306
  }));
2913
3307
  }
@@ -3452,20 +3846,16 @@ function RatingEditor({ column, value, pending, onCommit }) {
3452
3846
  return column.editor === "switch" || column.type === "rating" || column.type === "checkbox";
3453
3847
  }
3454
3848
  function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyFirst, stickyLast }) {
3455
- const effective = useEffectiveColumns(columns);
3849
+ const effective = useEffectiveColumns(columns, {
3850
+ selectable,
3851
+ stickyFirst
3852
+ });
3456
3853
  const { startEdit } = useDataTableContext();
3457
3854
  return /*#__PURE__*/ jsx(Fragment, {
3458
- children: effective.map(({ column }, index)=>{
3459
- const isFirst = index === 0;
3855
+ children: effective.map((entry, index)=>{
3856
+ const { column } = entry;
3460
3857
  const isLast = index === effective.length - 1;
3461
- const sticky = stickyProps({
3462
- selectable,
3463
- stickyFirst,
3464
- stickyLast,
3465
- isSelectionCell: false,
3466
- isFirst,
3467
- isLast
3468
- });
3858
+ const sticky = pinnedCellProps(entry, stickyLast, isLast);
3469
3859
  // A gated `editable` column (everything except the always-live widgets)
3470
3860
  // opens on double-click -- Attio's own measured gesture (crisp's #411),
3471
3861
  // matched here rather than a single click, which stays "select this cell"
@@ -3591,7 +3981,12 @@ function DisplayCellContent({ column, row, value, classNames, locale }) {
3591
3981
  return /*#__PURE__*/ jsx(EntityCell, {
3592
3982
  value: value,
3593
3983
  className: classNames.entity,
3594
- nameClassName: classNames.entityName
3984
+ nameClassName: classNames.entityName,
3985
+ actionsClassName: classNames.entityActions,
3986
+ actionClassName: classNames.entityAction,
3987
+ column: column,
3988
+ row: row,
3989
+ openPreviewLabel: column.openPreviewLabel
3595
3990
  });
3596
3991
  case "url":
3597
3992
  case "email":
@@ -3701,19 +4096,15 @@ const MenuItemLabel = withItemContext(withItemStateProps(Primitive.span), "label
3701
4096
  withItemContext(withItemStateProps(Primitive.span), "description");
3702
4097
 
3703
4098
  function ColumnCalcCells({ columns, rows, selectable, stickyFirst, stickyLast }) {
3704
- const effective = useEffectiveColumns(columns);
4099
+ const effective = useEffectiveColumns(columns, {
4100
+ selectable,
4101
+ stickyFirst
4102
+ });
3705
4103
  return /*#__PURE__*/ jsx(Fragment, {
3706
- children: effective.map(({ column }, index)=>{
3707
- const isFirst = index === 0;
4104
+ children: effective.map((entry, index)=>{
4105
+ const { column } = entry;
3708
4106
  const isLast = index === effective.length - 1;
3709
- const sticky = stickyProps({
3710
- selectable,
3711
- stickyFirst,
3712
- stickyLast,
3713
- isSelectionCell: false,
3714
- isFirst,
3715
- isLast
3716
- });
4107
+ const sticky = pinnedCellProps(entry, stickyLast, isLast);
3717
4108
  return /*#__PURE__*/ jsx(DataTableFooterCell, {
3718
4109
  "data-sticky": sticky["data-sticky"],
3719
4110
  "data-sticky-edge": sticky["data-sticky-edge"],
@@ -3897,20 +4288,16 @@ const DEFAULT_SORT_ICON = {
3897
4288
  * `visibleColumnOrder`/labels/widths change, without also re-deriving `sortedData`'s
3898
4289
  * render above it. */ function ColumnHeaderCells({ columns, columnMenu, reorderable, resizable, sortIcon, selectable, stickyFirst, stickyLast }) {
3899
4290
  const { draggingColumnKey, beginColumnDrag, dragOverColumn, endColumnDrag } = useDataTableContext();
3900
- const effective = useEffectiveColumns(columns);
4291
+ const effective = useEffectiveColumns(columns, {
4292
+ selectable,
4293
+ stickyFirst
4294
+ });
3901
4295
  const [renamingKey, setRenamingKey] = React.useState(null);
3902
4296
  return /*#__PURE__*/ jsx(Fragment, {
3903
- children: effective.map(({ column, label, width }, index)=>{
3904
- const isFirst = index === 0;
4297
+ children: effective.map((entry, index)=>{
4298
+ const { column, label, width } = entry;
3905
4299
  const isLast = index === effective.length - 1;
3906
- const sticky = stickyProps({
3907
- selectable,
3908
- stickyFirst,
3909
- stickyLast,
3910
- isSelectionCell: false,
3911
- isFirst,
3912
- isLast
3913
- });
4300
+ const sticky = pinnedCellProps(entry, stickyLast, isLast);
3914
4301
  return /*#__PURE__*/ jsxs(DataTableHeaderCell, {
3915
4302
  columnKey: column.key,
3916
4303
  sortable: column.sortable,
@@ -4040,8 +4427,9 @@ function ColumnRenameInput({ column, initialLabel, onDone }) {
4040
4427
  * permanently, so this one carries its own marker attribute distinct from that
4041
4428
  * slot's OTHER occupants (the sort chevron, the filter trigger), which stay visible
4042
4429
  * under their own separate rules regardless of hover. */ function ColumnMenu({ column, onRename }) {
4043
- const { moveColumn, hideColumn } = useDataTableContext();
4430
+ const { moveColumn, hideColumn, isColumnPinned, togglePinColumn } = useDataTableContext();
4044
4431
  const columnLabel = typeof column.header === "string" ? column.header : column.key;
4432
+ const pinned = isColumnPinned(column.key);
4045
4433
  const stopPropagation = (event)=>event.stopPropagation();
4046
4434
  return /*#__PURE__*/ jsxs(MenuRoot, {
4047
4435
  children: [
@@ -4083,6 +4471,12 @@ function ColumnRenameInput({ column, initialLabel, onDone }) {
4083
4471
  children: "Move right"
4084
4472
  })
4085
4473
  }),
4474
+ /*#__PURE__*/ jsx(MenuItem, {
4475
+ onClick: ()=>togglePinColumn(column.key),
4476
+ children: /*#__PURE__*/ jsx(MenuItemLabel, {
4477
+ children: pinned ? "Unpin column" : "Pin column"
4478
+ })
4479
+ }),
4086
4480
  /*#__PURE__*/ jsx(MenuItem, {
4087
4481
  onClick: ()=>hideColumn(column.key),
4088
4482
  children: /*#__PURE__*/ jsx(MenuItemLabel, {
@@ -4205,12 +4599,12 @@ function ColumnRenameInput({ column, initialLabel, onDone }) {
4205
4599
 
4206
4600
  __insertCSS(".seed-action-button{display:inline-flex;position:relative;box-sizing:border-box;align-items:center;justify-content:center;cursor:pointer;border:none;text-transform:none;white-space:nowrap;vertical-align:middle;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-decoration:none;flex-shrink:0;font-family:inherit;--seed-box-flex-grow:initial;flex-grow:var(--seed-box-flex-grow);--seed-box-min-width:initial;min-width:var(--seed-box-min-width);--seed-box-padding-bottom:initial;--seed-box-padding-top:initial;--seed-box-padding-left:initial;--seed-box-padding-right:initial;padding-top:var(--seed-box-padding-top);padding-bottom:var(--seed-box-padding-bottom);padding-left:var(--seed-box-padding-left);padding-right:var(--seed-box-padding-right);--seed-box-bleed-bottom-base:0px;--seed-box-bleed-bottom-sm:var(--seed-box-bleed-bottom-base, initial);--seed-box-bleed-bottom-md:var(--seed-box-bleed-bottom-sm, initial);--seed-box-bleed-bottom-lg:var(--seed-box-bleed-bottom-md, initial);--seed-box-bleed-bottom-xl:var(--seed-box-bleed-bottom-lg, initial);--seed-box-bleed-bottom:var(--seed-box-bleed-bottom-base, initial);--seed-box-bleed-top-base:0px;--seed-box-bleed-top-sm:var(--seed-box-bleed-top-base, initial);--seed-box-bleed-top-md:var(--seed-box-bleed-top-sm, initial);--seed-box-bleed-top-lg:var(--seed-box-bleed-top-md, initial);--seed-box-bleed-top-xl:var(--seed-box-bleed-top-lg, initial);--seed-box-bleed-top:var(--seed-box-bleed-top-base, initial);--seed-box-bleed-left-base:0px;--seed-box-bleed-left-sm:var(--seed-box-bleed-left-base, initial);--seed-box-bleed-left-md:var(--seed-box-bleed-left-sm, initial);--seed-box-bleed-left-lg:var(--seed-box-bleed-left-md, initial);--seed-box-bleed-left-xl:var(--seed-box-bleed-left-lg, initial);--seed-box-bleed-left:var(--seed-box-bleed-left-base, initial);--seed-box-bleed-right-base:0px;--seed-box-bleed-right-sm:var(--seed-box-bleed-right-base, initial);--seed-box-bleed-right-md:var(--seed-box-bleed-right-sm, initial);--seed-box-bleed-right-lg:var(--seed-box-bleed-right-md, initial);--seed-box-bleed-right-xl:var(--seed-box-bleed-right-lg, initial);--seed-box-bleed-right:var(--seed-box-bleed-right-base, initial);margin-top:calc(var(--seed-box-bleed-top) * -1);margin-bottom:calc(var(--seed-box-bleed-bottom) * -1);margin-left:calc(var(--seed-box-bleed-left) * -1);margin-right:calc(var(--seed-box-bleed-right) * -1);outline:var(--seed-dimension-x0_5) solid transparent;outline-offset:var(--seed-dimension-x0_5)}.seed-action-button:is(:focus-visible,[data-focus-visible]){outline:var(--seed-dimension-x0_5) solid var(--seed-color-stroke-focus-ring);outline-offset:var(--seed-dimension-x0_5)}.seed-action-button:is(:disabled,[disabled],[data-disabled]){cursor:not-allowed}.seed-action-button:not(:is(:disabled,[disabled],[data-disabled])):is(:active,[data-active]){scale:var(--seed-feedback-scale)}.seed-action-button{transition:background-color var(--seed-duration-color-transition) var(--seed-timing-function-easing),scale var(--seed-duration-pressed-scale) var(--seed-timing-function-pressed-scale),outline-color var(--seed-duration-d3) var(--seed-timing-function-easing)}.seed-action-button--variant_brandSolid{background:var(--seed-color-bg-brand-solid);color:var(--seed-color-palette-static-white);font-weight:var(--seed-font-weight-bold);--seed-prefix-icon-color:var(--seed-color-palette-static-white);--seed-suffix-icon-color:var(--seed-color-palette-static-white);--seed-icon-color:var(--seed-color-palette-static-white);--track-color:var(--seed-color-palette-static-white-alpha-300);--range-color:var(--seed-color-palette-static-white)}@media (hover:hover) and (pointer:fine){.seed-action-button--variant_brandSolid:is(:hover,[data-hover]){background:var(--seed-color-bg-brand-solid-pressed)}}@media not all and (hover:hover) and (pointer:fine){.seed-action-button--variant_brandSolid:is(:active,[data-active]){background:var(--seed-color-bg-brand-solid-pressed)}}.seed-action-button--variant_brandSolid:is(:disabled,[disabled],[data-disabled]){background:var(--seed-color-bg-disabled);color:var(--seed-color-fg-disabled);--seed-prefix-icon-color:var(--seed-color-fg-disabled);--seed-suffix-icon-color:var(--seed-color-fg-disabled);--seed-icon-color:var(--seed-color-fg-disabled)}.seed-action-button--variant_brandSolid[data-loading]{background:var(--seed-color-bg-brand-solid-pressed)}.seed-action-button--variant_neutralSolid{background:var(--seed-color-bg-neutral-inverted);color:var(--seed-color-fg-neutral-inverted);font-weight:var(--seed-font-weight-bold);--seed-prefix-icon-color:var(--seed-color-fg-neutral-inverted);--seed-suffix-icon-color:var(--seed-color-fg-neutral-inverted);--seed-icon-color:var(--seed-color-fg-neutral-inverted);--track-color:var(--seed-color-palette-static-white-alpha-300);--range-color:var(--seed-color-palette-static-white)}@media (hover:hover) and (pointer:fine){.seed-action-button--variant_neutralSolid:is(:hover,[data-hover]){background:var(--seed-color-bg-neutral-inverted-pressed)}}@media not all and (hover:hover) and (pointer:fine){.seed-action-button--variant_neutralSolid:is(:active,[data-active]){background:var(--seed-color-bg-neutral-inverted-pressed)}}.seed-action-button--variant_neutralSolid:is(:disabled,[disabled],[data-disabled]){background:var(--seed-color-bg-disabled);color:var(--seed-color-fg-disabled);--seed-prefix-icon-color:var(--seed-color-fg-disabled);--seed-suffix-icon-color:var(--seed-color-fg-disabled);--seed-icon-color:var(--seed-color-fg-disabled)}.seed-action-button--variant_neutralSolid[data-loading]{background:var(--seed-color-bg-neutral-inverted-pressed)}.seed-action-button--variant_neutralWeak{background:var(--seed-color-bg-neutral-weak);color:var(--seed-color-fg-neutral);font-weight:var(--seed-font-weight-bold);--seed-prefix-icon-color:var(--seed-color-fg-neutral);--seed-suffix-icon-color:var(--seed-color-fg-neutral);--seed-icon-color:var(--seed-color-fg-neutral);--track-color:var(--seed-color-palette-gray-500);--range-color:var(--seed-color-fg-neutral)}@media (hover:hover) and (pointer:fine){.seed-action-button--variant_neutralWeak:is(:hover,[data-hover]){background:var(--seed-color-bg-neutral-weak-pressed)}}@media not all and (hover:hover) and (pointer:fine){.seed-action-button--variant_neutralWeak:is(:active,[data-active]){background:var(--seed-color-bg-neutral-weak-pressed)}}.seed-action-button--variant_neutralWeak:is(:disabled,[disabled],[data-disabled]){background:var(--seed-color-bg-disabled);color:var(--seed-color-fg-disabled);--seed-prefix-icon-color:var(--seed-color-fg-disabled);--seed-suffix-icon-color:var(--seed-color-fg-disabled);--seed-icon-color:var(--seed-color-fg-disabled)}.seed-action-button--variant_neutralWeak[data-loading]{background:var(--seed-color-bg-neutral-weak-pressed)}.seed-action-button--variant_criticalSolid{background:var(--seed-color-bg-critical-solid);color:var(--seed-color-palette-static-white);font-weight:var(--seed-font-weight-bold);--seed-prefix-icon-color:var(--seed-color-palette-static-white);--seed-suffix-icon-color:var(--seed-color-palette-static-white);--seed-icon-color:var(--seed-color-palette-static-white);--track-color:var(--seed-color-palette-static-white-alpha-300);--range-color:var(--seed-color-palette-static-white)}@media (hover:hover) and (pointer:fine){.seed-action-button--variant_criticalSolid:is(:hover,[data-hover]){background:var(--seed-color-bg-critical-solid-pressed)}}@media not all and (hover:hover) and (pointer:fine){.seed-action-button--variant_criticalSolid:is(:active,[data-active]){background:var(--seed-color-bg-critical-solid-pressed)}}.seed-action-button--variant_criticalSolid:is(:disabled,[disabled],[data-disabled]){background:var(--seed-color-bg-disabled);color:var(--seed-color-fg-disabled);--seed-prefix-icon-color:var(--seed-color-fg-disabled);--seed-suffix-icon-color:var(--seed-color-fg-disabled);--seed-icon-color:var(--seed-color-fg-disabled)}.seed-action-button--variant_criticalSolid[data-loading]{background:var(--seed-color-bg-critical-solid-pressed)}.seed-action-button--variant_brandOutline{border-style:solid;background:var(--seed-color-bg-transparent);border-width:1px;border-color:var(--seed-color-stroke-neutral-muted);color:var(--seed-color-fg-brand);font-weight:var(--seed-font-weight-bold);--seed-prefix-icon-color:var(--seed-color-fg-brand);--seed-suffix-icon-color:var(--seed-color-fg-brand);--seed-icon-color:var(--seed-color-fg-brand);--track-color:var(--seed-color-palette-carrot-200);--range-color:var(--seed-color-bg-brand-solid)}@media (hover:hover) and (pointer:fine){.seed-action-button--variant_brandOutline:is(:hover,[data-hover]){background:var(--seed-color-bg-transparent-pressed)}}@media not all and (hover:hover) and (pointer:fine){.seed-action-button--variant_brandOutline:is(:active,[data-active]){background:var(--seed-color-bg-transparent-pressed)}}.seed-action-button--variant_brandOutline:is(:disabled,[disabled],[data-disabled]){background:var(--seed-color-bg-transparent);border-color:var(--seed-color-stroke-neutral-muted);color:var(--seed-color-fg-disabled);--seed-prefix-icon-color:var(--seed-color-fg-disabled);--seed-suffix-icon-color:var(--seed-color-fg-disabled);--seed-icon-color:var(--seed-color-fg-disabled)}.seed-action-button--variant_brandOutline[data-loading]{background:var(--seed-color-bg-transparent)}.seed-action-button--variant_neutralOutline{border-style:solid;background:var(--seed-color-bg-transparent);border-width:1px;border-color:var(--seed-color-stroke-neutral-muted);color:var(--seed-color-fg-neutral);font-weight:var(--seed-font-weight-bold);--seed-prefix-icon-color:var(--seed-color-fg-neutral);--seed-suffix-icon-color:var(--seed-color-fg-neutral);--seed-icon-color:var(--seed-color-fg-neutral);--track-color:var(--seed-color-palette-gray-500);--range-color:var(--seed-color-fg-neutral)}@media (hover:hover) and (pointer:fine){.seed-action-button--variant_neutralOutline:is(:hover,[data-hover]){background:var(--seed-color-bg-transparent-pressed)}}@media not all and (hover:hover) and (pointer:fine){.seed-action-button--variant_neutralOutline:is(:active,[data-active]){background:var(--seed-color-bg-transparent-pressed)}}.seed-action-button--variant_neutralOutline:is(:disabled,[disabled],[data-disabled]){background:var(--seed-color-bg-transparent);border-color:var(--seed-color-stroke-neutral-muted);color:var(--seed-color-fg-disabled);--seed-prefix-icon-color:var(--seed-color-fg-disabled);--seed-suffix-icon-color:var(--seed-color-fg-disabled);--seed-icon-color:var(--seed-color-fg-disabled)}.seed-action-button--variant_neutralOutline[data-loading]{background:var(--seed-color-bg-transparent)}.seed-action-button--variant_ghost{background:#ffffff00;--seed-box-color:var(--seed-color-fg-neutral);color:var(--seed-box-color);--seed-prefix-icon-color:var(--seed-box-color);--seed-suffix-icon-color:var(--seed-box-color);--seed-icon-color:var(--seed-box-color);--seed-font-weight:var(--seed-font-weight-bold);font-weight:var(--seed-font-weight);--track-color:var(--seed-color-palette-gray-500);--range-color:var(--seed-color-fg-neutral)}@media (hover:hover) and (pointer:fine){.seed-action-button--variant_ghost:is(:hover,[data-hover]){background:var(--seed-color-bg-transparent-pressed)}}@media not all and (hover:hover) and (pointer:fine){.seed-action-button--variant_ghost:is(:active,[data-active]){background:var(--seed-color-bg-transparent-pressed)}}.seed-action-button--variant_ghost:is(:disabled,[disabled],[data-disabled]){background:#ffffff00;color:var(--seed-color-fg-disabled);--seed-prefix-icon-color:var(--seed-color-fg-disabled);--seed-suffix-icon-color:var(--seed-color-fg-disabled);--seed-icon-color:var(--seed-color-fg-disabled)}.seed-action-button--variant_ghost[data-loading]{background:var(--seed-color-bg-transparent-pressed)}.seed-action-button--size_xsmall{height:var(--seed-dimension-x8);border-radius:var(--seed-radius-full);--size:14px;--thickness:2px;--seed-prefix-icon-size:var(--seed-dimension-x3_5);--seed-suffix-icon-size:var(--seed-dimension-x3_5);--seed-icon-size:var(--seed-dimension-x3_5)}.seed-action-button--size_small{height:var(--seed-dimension-x9);border-radius:var(--seed-radius-r2);--size:14px;--thickness:2px;--seed-prefix-icon-size:var(--seed-dimension-x3_5);--seed-suffix-icon-size:var(--seed-dimension-x3_5);--seed-icon-size:var(--seed-dimension-x4)}.seed-action-button--size_medium{height:var(--seed-dimension-x10);border-radius:var(--seed-radius-r2);--size:16px;--thickness:2px;--seed-prefix-icon-size:var(--seed-dimension-x4);--seed-suffix-icon-size:var(--seed-dimension-x4);--seed-icon-size:18px}.seed-action-button--size_large{height:var(--seed-dimension-x13);border-radius:var(--seed-radius-r3);--size:18px;--thickness:2px;--seed-prefix-icon-size:22px;--seed-suffix-icon-size:22px;--seed-icon-size:22px}.seed-action-button--size_xsmall-layout_withText{gap:var(--seed-dimension-x1);--seed-box-padding-left:var(--seed-dimension-x3_5);--seed-box-padding-right:var(--seed-dimension-x3_5);--seed-box-padding-top:var(--seed-dimension-x1_5);--seed-box-padding-bottom:var(--seed-dimension-x1_5);font-size:var(--seed-font-size-t3);line-height:var(--seed-line-height-t3)}.seed-action-button--size_xsmall-layout_iconOnly{min-width:var(--seed-dimension-x8);--seed-box-padding-left:var(--seed-dimension-x1_5);--seed-box-padding-right:var(--seed-dimension-x1_5);--seed-box-padding-top:var(--seed-dimension-x1_5);--seed-box-padding-bottom:var(--seed-dimension-x1_5)}.seed-action-button--size_small-layout_withText{gap:var(--seed-dimension-x1);--seed-box-padding-left:var(--seed-dimension-x3_5);--seed-box-padding-right:var(--seed-dimension-x3_5);--seed-box-padding-top:var(--seed-dimension-x2);--seed-box-padding-bottom:var(--seed-dimension-x2);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4)}.seed-action-button--size_small-layout_iconOnly{min-width:var(--seed-dimension-x9);--seed-box-padding-left:var(--seed-dimension-x2);--seed-box-padding-right:var(--seed-dimension-x2);--seed-box-padding-top:var(--seed-dimension-x2);--seed-box-padding-bottom:var(--seed-dimension-x2)}.seed-action-button--size_medium-layout_withText{gap:var(--seed-dimension-x1_5);--seed-box-padding-left:var(--seed-dimension-x4);--seed-box-padding-right:var(--seed-dimension-x4);--seed-box-padding-top:var(--seed-dimension-x2_5);--seed-box-padding-bottom:var(--seed-dimension-x2_5);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4)}.seed-action-button--size_medium-layout_iconOnly{min-width:var(--seed-dimension-x10);--seed-box-padding-left:var(--seed-dimension-x2_5);--seed-box-padding-right:var(--seed-dimension-x2_5);--seed-box-padding-top:var(--seed-dimension-x2_5);--seed-box-padding-bottom:var(--seed-dimension-x2_5)}.seed-action-button--size_large-layout_withText{gap:var(--seed-dimension-x2);--seed-box-padding-left:var(--seed-dimension-x5);--seed-box-padding-right:var(--seed-dimension-x5);--seed-box-padding-top:var(--seed-dimension-x3_5);--seed-box-padding-bottom:var(--seed-dimension-x3_5);font-size:var(--seed-font-size-t6);line-height:var(--seed-line-height-t6)}.seed-action-button--size_large-layout_iconOnly{min-width:var(--seed-dimension-x13);--seed-box-padding-left:var(--seed-dimension-x3_5);--seed-box-padding-right:var(--seed-dimension-x3_5);--seed-box-padding-top:var(--seed-dimension-x3_5);--seed-box-padding-bottom:var(--seed-dimension-x3_5)}@media (min-width:480px){.seed-action-button{--seed-box-bleed-bottom:var(--seed-box-bleed-bottom-sm, initial);--seed-box-bleed-top:var(--seed-box-bleed-top-sm, initial);--seed-box-bleed-left:var(--seed-box-bleed-left-sm, initial);--seed-box-bleed-right:var(--seed-box-bleed-right-sm, initial)}}@media (min-width:768px){.seed-action-button{--seed-box-bleed-bottom:var(--seed-box-bleed-bottom-md, initial);--seed-box-bleed-top:var(--seed-box-bleed-top-md, initial);--seed-box-bleed-left:var(--seed-box-bleed-left-md, initial);--seed-box-bleed-right:var(--seed-box-bleed-right-md, initial)}}@media (min-width:1280px){.seed-action-button{--seed-box-bleed-bottom:var(--seed-box-bleed-bottom-lg, initial);--seed-box-bleed-top:var(--seed-box-bleed-top-lg, initial);--seed-box-bleed-left:var(--seed-box-bleed-left-lg, initial);--seed-box-bleed-right:var(--seed-box-bleed-right-lg, initial)}}@media (min-width:1440px){.seed-action-button{--seed-box-bleed-bottom:var(--seed-box-bleed-bottom-xl, initial);--seed-box-bleed-top:var(--seed-box-bleed-top-xl, initial);--seed-box-bleed-left:var(--seed-box-bleed-left-xl, initial);--seed-box-bleed-right:var(--seed-box-bleed-right-xl, initial)}}");
4207
4601
 
4208
- const defaultVariant$3 = {
4602
+ const defaultVariant$5 = {
4209
4603
  "variant": "brandSolid",
4210
4604
  "size": "medium",
4211
4605
  "layout": "withText"
4212
4606
  };
4213
- const compoundVariants$3 = [
4607
+ const compoundVariants$5 = [
4214
4608
  {
4215
4609
  "size": "xsmall",
4216
4610
  "layout": "withText"
@@ -4266,7 +4660,7 @@ const actionButtonVariantMap = {
4266
4660
  ]
4267
4661
  };
4268
4662
  function actionButton(props) {
4269
- return createClassName("seed-action-button", mergeVariants(defaultVariant$3, props), compoundVariants$3);
4663
+ return createClassName("seed-action-button", mergeVariants(defaultVariant$5, props), compoundVariants$5);
4270
4664
  }
4271
4665
  Object.assign(actionButton, {
4272
4666
  splitVariantProps: (props)=>splitVariantProps(props, actionButtonVariantMap)
@@ -5348,10 +5742,10 @@ const datePickerSlotNames = [
5348
5742
  "seed-date-picker__liveRegion"
5349
5743
  ]
5350
5744
  ];
5351
- const defaultVariant$2 = {
5745
+ const defaultVariant$4 = {
5352
5746
  "visibleRange": "month"
5353
5747
  };
5354
- const compoundVariants$2 = [];
5748
+ const compoundVariants$4 = [];
5355
5749
  const datePickerVariantMap = {
5356
5750
  "visibleRange": [
5357
5751
  "month",
@@ -5364,7 +5758,7 @@ function datePicker(props) {
5364
5758
  return Object.fromEntries(datePickerSlotNames.map(([slot, className])=>{
5365
5759
  return [
5366
5760
  slot,
5367
- createClassName(className, mergeVariants(defaultVariant$2, props), compoundVariants$2)
5761
+ createClassName(className, mergeVariants(defaultVariant$4, props), compoundVariants$4)
5368
5762
  ];
5369
5763
  }));
5370
5764
  }
@@ -7698,14 +8092,14 @@ const wheelPickerSlotNames = [
7698
8092
  "seed-wheel-picker__selectionIndicator"
7699
8093
  ]
7700
8094
  ];
7701
- const defaultVariant$1 = {};
7702
- const compoundVariants$1 = [];
8095
+ const defaultVariant$3 = {};
8096
+ const compoundVariants$3 = [];
7703
8097
  const wheelPickerVariantMap = {};
7704
8098
  function wheelPicker(props) {
7705
8099
  return Object.fromEntries(wheelPickerSlotNames.map(([slot, className])=>{
7706
8100
  return [
7707
8101
  slot,
7708
- createClassName(className, mergeVariants(defaultVariant$1, props), compoundVariants$1)
8102
+ createClassName(className, mergeVariants(defaultVariant$3, props), compoundVariants$3)
7709
8103
  ];
7710
8104
  }));
7711
8105
  }
@@ -8487,17 +8881,17 @@ var WheelPicker_namespace = {
8487
8881
 
8488
8882
  __insertCSS(".seed-scroll-fog{position:relative;overflow:auto;height:100%;width:100%;mask-image:linear-gradient(to bottom,#00000000 0,#00000003 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.08),#00000005 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.16),#0000000d calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.22),#00000014 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.29),#00000021 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.35),#0000002e calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.41),#00000040 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.47),#00000052 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.53),#00000066 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.59),#0000007a calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.65),#00000094 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.71),#000000ab calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.78),#000000c7 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.84),#000000e3 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.92),#000000ff calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 1)),linear-gradient(to top,#00000000 0,#00000003 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.08),#00000005 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.16),#0000000d calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.22),#00000014 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.29),#00000021 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.35),#0000002e calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.41),#00000040 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.47),#00000052 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.53),#00000066 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.59),#0000007a calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.65),#00000094 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.71),#000000ab calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.78),#000000c7 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.84),#000000e3 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.92),#000000ff calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 1)),linear-gradient(to right,#00000000 0,#00000003 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.08),#00000005 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.16),#0000000d calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.22),#00000014 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.29),#00000021 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.35),#0000002e calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.41),#00000040 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.47),#00000052 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.53),#00000066 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.59),#0000007a calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.65),#00000094 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.71),#000000ab calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.78),#000000c7 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.84),#000000e3 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.92),#000000ff calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 1)),linear-gradient(to left,#00000000 0,#00000003 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.08),#00000005 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.16),#0000000d calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.22),#00000014 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.29),#00000021 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.35),#0000002e calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.41),#00000040 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.47),#00000052 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.53),#00000066 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.59),#0000007a calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.65),#00000094 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.71),#000000ab calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.78),#000000c7 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.84),#000000e3 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.92),#000000ff calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 1));-webkit-mask-image:linear-gradient(to bottom,#00000000 0,#00000003 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.08),#00000005 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.16),#0000000d calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.22),#00000014 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.29),#00000021 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.35),#0000002e calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.41),#00000040 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.47),#00000052 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.53),#00000066 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.59),#0000007a calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.65),#00000094 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.71),#000000ab calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.78),#000000c7 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.84),#000000e3 calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 0.92),#000000ff calc(var(--scrollable-top) * var(--scroll-fog-size-top) * 1)),linear-gradient(to top,#00000000 0,#00000003 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.08),#00000005 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.16),#0000000d calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.22),#00000014 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.29),#00000021 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.35),#0000002e calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.41),#00000040 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.47),#00000052 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.53),#00000066 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.59),#0000007a calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.65),#00000094 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.71),#000000ab calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.78),#000000c7 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.84),#000000e3 calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 0.92),#000000ff calc(var(--scrollable-bottom) * var(--scroll-fog-size-bottom) * 1)),linear-gradient(to right,#00000000 0,#00000003 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.08),#00000005 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.16),#0000000d calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.22),#00000014 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.29),#00000021 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.35),#0000002e calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.41),#00000040 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.47),#00000052 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.53),#00000066 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.59),#0000007a calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.65),#00000094 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.71),#000000ab calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.78),#000000c7 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.84),#000000e3 calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 0.92),#000000ff calc(var(--scrollable-left) * var(--scroll-fog-size-left) * 1)),linear-gradient(to left,#00000000 0,#00000003 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.08),#00000005 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.16),#0000000d calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.22),#00000014 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.29),#00000021 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.35),#0000002e calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.41),#00000040 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.47),#00000052 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.53),#00000066 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.59),#0000007a calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.65),#00000094 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.71),#000000ab calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.78),#000000c7 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.84),#000000e3 calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 0.92),#000000ff calc(var(--scrollable-right) * var(--scroll-fog-size-right) * 1));mask-size:100% 100%,100% 100%,100% 100%,100% 100%;-webkit-mask-size:100% 100%,100% 100%,100% 100%,100% 100%;mask-repeat:no-repeat;-webkit-mask-repeat:no-repeat;mask-composite:intersect;-webkit-mask-composite:source-in}.seed-scroll-fog--hideScrollBar_true{scrollbar-width:none;-ms-overflow-style:none}.seed-scroll-fog--hideScrollBar_true::-webkit-scrollbar{display:none}");
8489
8883
 
8490
- const defaultVariant = {
8884
+ const defaultVariant$2 = {
8491
8885
  "hideScrollBar": false
8492
8886
  };
8493
- const compoundVariants = [];
8887
+ const compoundVariants$2 = [];
8494
8888
  const scrollFogVariantMap = {
8495
8889
  "hideScrollBar": [
8496
8890
  true
8497
8891
  ]
8498
8892
  };
8499
8893
  function scrollFog(props) {
8500
- return createClassName("seed-scroll-fog", mergeVariants(defaultVariant, props), compoundVariants);
8894
+ return createClassName("seed-scroll-fog", mergeVariants(defaultVariant$2, props), compoundVariants$2);
8501
8895
  }
8502
8896
  Object.assign(scrollFog, {
8503
8897
  splitVariantProps: (props)=>splitVariantProps(props, scrollFogVariantMap)
@@ -9303,7 +9697,7 @@ const fromDatePickerDate = (d)=>new Date(d.year, d.month - 1, d.day);
9303
9697
  "aria-label": "Move sort up",
9304
9698
  disabled: index === 0,
9305
9699
  onClick: ()=>moveToolbarSort(index, index - 1),
9306
- style: iconButtonStyle,
9700
+ style: iconButtonStyle$1,
9307
9701
  children: /*#__PURE__*/ jsx(IconArrowUpLine_default, {
9308
9702
  size: 13,
9309
9703
  strokeWidth: 1.75
@@ -9314,7 +9708,7 @@ const fromDatePickerDate = (d)=>new Date(d.year, d.month - 1, d.day);
9314
9708
  "aria-label": "Move sort down",
9315
9709
  disabled: index === toolbarSorts.length - 1,
9316
9710
  onClick: ()=>moveToolbarSort(index, index + 1),
9317
- style: iconButtonStyle,
9711
+ style: iconButtonStyle$1,
9318
9712
  children: /*#__PURE__*/ jsx(IconArrowDownLine_default, {
9319
9713
  size: 13,
9320
9714
  strokeWidth: 1.75
@@ -9324,7 +9718,7 @@ const fromDatePickerDate = (d)=>new Date(d.year, d.month - 1, d.day);
9324
9718
  type: "button",
9325
9719
  "aria-label": "Remove sort",
9326
9720
  onClick: ()=>removeToolbarSort(index),
9327
- style: iconButtonStyle,
9721
+ style: iconButtonStyle$1,
9328
9722
  children: /*#__PURE__*/ jsx(IconXmarkLine_default, {
9329
9723
  size: 13,
9330
9724
  strokeWidth: 1.75
@@ -9339,7 +9733,7 @@ const fromDatePickerDate = (d)=>new Date(d.year, d.month - 1, d.day);
9339
9733
  disabled: availableColumns.length === 0,
9340
9734
  onClick: ()=>availableColumns[0] && addToolbarSort(availableColumns[0].key),
9341
9735
  style: {
9342
- ...iconButtonStyle,
9736
+ ...iconButtonStyle$1,
9343
9737
  width: "auto",
9344
9738
  gap: 6,
9345
9739
  padding: "6px 8px",
@@ -9361,7 +9755,7 @@ const fromDatePickerDate = (d)=>new Date(d.year, d.month - 1, d.day);
9361
9755
  ]
9362
9756
  });
9363
9757
  }
9364
- const iconButtonStyle = {
9758
+ const iconButtonStyle$1 = {
9365
9759
  display: "inline-flex",
9366
9760
  alignItems: "center",
9367
9761
  justifyContent: "center",
@@ -9459,7 +9853,7 @@ const formatFilterDate = (iso)=>{
9459
9853
  type: "button",
9460
9854
  "aria-label": `Remove ${column ? columnLabel(column) : filter.key} filter`,
9461
9855
  onClick: ()=>removeToolbarFilter(filter.id),
9462
- style: iconButtonStyle,
9856
+ style: iconButtonStyle$1,
9463
9857
  children: /*#__PURE__*/ jsx(IconXmarkLine_default, {
9464
9858
  size: 12,
9465
9859
  strokeWidth: 1.75
@@ -9716,7 +10110,7 @@ const formatFilterDate = (iso)=>{
9716
10110
  type: "button",
9717
10111
  onClick: ()=>setPickingField(true),
9718
10112
  style: {
9719
- ...iconButtonStyle,
10113
+ ...iconButtonStyle$1,
9720
10114
  width: "auto",
9721
10115
  gap: 6,
9722
10116
  padding: "6px 8px",
@@ -9801,7 +10195,7 @@ function RowCount({ shown, total, countLabel }) {
9801
10195
  }
9802
10196
 
9803
10197
  function DataTableInner(props, ref) {
9804
- const { columns, data, surface, className, locale = "en-US", sort, defaultSort, onSortChange, sortIcon, selectable, selectedIds, defaultSelectedIds, onSelectionChange, selectAllLabel = "Select all rows", getRowSelectionLabel = ()=>"Select row", selectionCheckedIcon, selectionIndeterminateIcon, query, defaultQuery, onQueryChange, searchPlaceholder = "Search…", searchLabel = "Search table", toolbarSorts, defaultToolbarSorts, onToolbarSortsChange, toolbarFilters, defaultToolbarFilters, onToolbarFiltersChange, showCount = true, countLabel, toolbarActions, columnMenu = false, reorderable = true, resizable = true, columnOrder, defaultColumnOrder, onColumnOrderChange, hiddenColumnKeys, defaultHiddenColumnKeys, onHiddenColumnKeysChange, columnWidths, defaultColumnWidths, onColumnWidthsChange, columnLabels, defaultColumnLabels, onColumnLabelsChange, onColumnsChange, columnCalcOps, defaultColumnCalcOps, onColumnCalcOpsChange, stickyFirst = false, stickyLast = false, onEdit, interactive = false, onRowClick, onAddRow, addRowLabel = "New record", loading = false, loadingLabel = "Loading...", error, empty = "No results.", onLoadMore, hasMore, loadingMore, scrollProps, ...restProps } = props;
10198
+ const { columns, data, surface, className, locale = "en-US", sort, defaultSort, onSortChange, sortIcon, selectable, selectedIds, defaultSelectedIds, onSelectionChange, selectAllLabel = "Select all rows", getRowSelectionLabel = ()=>"Select row", selectionCheckedIcon, selectionIndeterminateIcon, query, defaultQuery, onQueryChange, searchPlaceholder = "Search…", searchLabel = "Search table", toolbarSorts, defaultToolbarSorts, onToolbarSortsChange, toolbarFilters, defaultToolbarFilters, onToolbarFiltersChange, showCount = true, countLabel, toolbarActions, columnMenu = false, reorderable = true, resizable = true, columnOrder, defaultColumnOrder, onColumnOrderChange, hiddenColumnKeys, defaultHiddenColumnKeys, onHiddenColumnKeysChange, columnWidths, defaultColumnWidths, onColumnWidthsChange, columnLabels, defaultColumnLabels, onColumnLabelsChange, pinnedColumnKeys, defaultPinnedColumnKeys, onPinnedColumnKeysChange, onColumnsChange, columnCalcOps, defaultColumnCalcOps, onColumnCalcOpsChange, stickyFirst = false, stickyLast = false, onEdit, interactive = false, onRowClick, onAddRow, addRowLabel = "New record", loading = false, loadingLabel = "Loading...", error, empty = "No results.", onLoadMore, hasMore, loadingMore, scrollProps, ...restProps } = props;
9805
10199
  const classNames = dataTable({
9806
10200
  surface,
9807
10201
  interactive
@@ -9937,6 +10331,9 @@ function DataTableInner(props, ref) {
9937
10331
  columnLabels: columnLabels,
9938
10332
  defaultColumnLabels: defaultColumnLabels,
9939
10333
  onColumnLabelsChange: onColumnLabelsChange,
10334
+ pinnedColumnKeys: pinnedColumnKeys,
10335
+ defaultPinnedColumnKeys: defaultPinnedColumnKeys,
10336
+ onPinnedColumnKeysChange: onPinnedColumnKeysChange,
9940
10337
  columnCalcOps: columnCalcOps,
9941
10338
  defaultColumnCalcOps: defaultColumnCalcOps,
9942
10339
  onColumnCalcOpsChange: onColumnCalcOpsChange,
@@ -9980,19 +10377,13 @@ function DataTableInner(props, ref) {
9980
10377
  children: [
9981
10378
  /*#__PURE__*/ jsx(DataTableColGroup, {
9982
10379
  columns: columns,
9983
- selectable: !!selectable
10380
+ selectable: !!selectable,
10381
+ stickyFirst: stickyFirst
9984
10382
  }),
9985
10383
  /*#__PURE__*/ jsxs(DataTableHeader, {
9986
10384
  children: [
9987
- selectable && /*#__PURE__*/ jsx(DataTableSelectionHeaderCell, {
9988
- ...stickyProps({
9989
- selectable,
9990
- stickyFirst,
9991
- stickyLast: resolvedStickyLast,
9992
- isSelectionCell: true,
9993
- isFirst: false,
9994
- isLast: false
9995
- }),
10385
+ selectable && /*#__PURE__*/ jsx(SelectionHeaderCell, {
10386
+ stickyFirst: stickyFirst,
9996
10387
  children: /*#__PURE__*/ jsx(SelectAllCheckbox, {
9997
10388
  label: selectAllLabel,
9998
10389
  checkedIcon: selectionCheckedIcon ?? DEFAULT_CHECKED_ICON,
@@ -10043,7 +10434,7 @@ function DataTableInner(props, ref) {
10043
10434
  "data-clickable": onRowClick ? "" : undefined,
10044
10435
  onClick: onRowClick ? ()=>onRowClick(row) : undefined,
10045
10436
  children: [
10046
- selectable && /*#__PURE__*/ jsx(DataTableSelectionCell, {
10437
+ selectable && /*#__PURE__*/ jsx(SelectionCell, {
10047
10438
  // The row itself carries `onClick={onRowClick}` above, and a
10048
10439
  // native click on this cell's checkbox bubbles up through it
10049
10440
  // (React attaches DataTableRow's handler on the <tr>, which
@@ -10051,14 +10442,7 @@ function DataTableInner(props, ref) {
10051
10442
  // it from at -- so this has to live here, not in the consumer).
10052
10443
  // Without this, checking a row's box also fires `onRowClick`.
10053
10444
  onClick: (event)=>event.stopPropagation(),
10054
- ...stickyProps({
10055
- selectable,
10056
- stickyFirst,
10057
- stickyLast: resolvedStickyLast,
10058
- isSelectionCell: true,
10059
- isFirst: false,
10060
- isLast: false
10061
- }),
10445
+ stickyFirst: stickyFirst,
10062
10446
  children: /*#__PURE__*/ jsx(RowCheckbox, {
10063
10447
  label: getRowSelectionLabel(row),
10064
10448
  checkedIcon: selectionCheckedIcon ?? DEFAULT_CHECKED_ICON
@@ -10090,15 +10474,8 @@ function DataTableInner(props, ref) {
10090
10474
  // is what makes every row's selection column line up now, not a matching
10091
10475
  // per-slot width formula, so there is no more reason for this cell to
10092
10476
  // borrow a different slot than its footer siblings.
10093
- /*#__PURE__*/ jsx(DataTableFooterCell, {
10094
- ...stickyProps({
10095
- selectable,
10096
- stickyFirst,
10097
- stickyLast: resolvedStickyLast,
10098
- isSelectionCell: true,
10099
- isFirst: false,
10100
- isLast: false
10101
- })
10477
+ /*#__PURE__*/ jsx(SelectionFooterCell, {
10478
+ stickyFirst: stickyFirst
10102
10479
  }),
10103
10480
  /*#__PURE__*/ jsx(ColumnCalcCells, {
10104
10481
  columns: columns,
@@ -10134,7 +10511,16 @@ DataTableInner.displayName = "DataTable";
10134
10511
  * `DataTableInner`) purely so it can call `useDataTableContext()` -- that context is
10135
10512
  * provided by the `DataTablePrimitiveRoot` this renders as a SIBLING of, one level
10136
10513
  * up from where `DataTableInner` itself sits. */ function ColumnsChangeEffect({ columns, onColumnsChange }) {
10137
- const effective = useEffectiveColumns(columns);
10514
+ // `selectable`/`stickyFirst` are both `false` here on purpose: this convenience blob
10515
+ // never renders a row of its own, so it needs neither the +40px selection offset nor
10516
+ // `stickyFirst`'s legacy "no explicit pin -> pin the first visible column" fallback.
10517
+ // An EXPLICIT per-column pin (`pinnedColumnKeys`) still reorders this list the same
10518
+ // way it reorders every rendered row -- this callback reports "what's showing now",
10519
+ // and a pinned column showing first IS what's showing now.
10520
+ const effective = useEffectiveColumns(columns, {
10521
+ selectable: false,
10522
+ stickyFirst: false
10523
+ });
10138
10524
  // A NEW array every time `effective` itself is a new array (its own `useMemo`
10139
10525
  // recomputes only when order/hidden/label/width actually change) -- `header`
10140
10526
  // resolves to the menu's rename override (falling back to the column's own static
@@ -10169,8 +10555,16 @@ const DataTableTable = withContext$1(DataTableTable$1, "table");
10169
10555
  * out of sync between the three. A column with no explicit width gets a bare `<col>`
10170
10556
  * (no `style`): `table-layout: fixed`'s own algorithm gives every such column an equal
10171
10557
  * share of whatever space is left, matching the old flex grid's `flex: 1 1 0%`
10172
- * default with no extra code needed here. */ function DataTableColGroup({ columns, selectable }) {
10173
- const effective = useEffectiveColumns(columns);
10558
+ * default with no extra code needed here. */ function DataTableColGroup({ columns, selectable, stickyFirst }) {
10559
+ // MUST use the same pinned-first ordering every OTHER row (header/body/footer)
10560
+ // renders in (`useEffectiveColumns`'s own doc comment) -- a `<colgroup>`'s `<col>`s
10561
+ // are matched positionally to each row's cells, so if a pinned column visually moves
10562
+ // to the front of the header/body but not here, every column's width applies to the
10563
+ // WRONG cell.
10564
+ const effective = useEffectiveColumns(columns, {
10565
+ selectable,
10566
+ stickyFirst
10567
+ });
10174
10568
  return /*#__PURE__*/ jsxs("colgroup", {
10175
10569
  children: [
10176
10570
  selectable && /*#__PURE__*/ jsx("col", {
@@ -10256,6 +10650,32 @@ function DataTableFooter({ children, ...props }) {
10256
10650
  });
10257
10651
  }
10258
10652
  const DataTableFooterCell = withContext$1(Primitive.td, "footerCell");
10653
+ // The selection column's OWN sticky wrappers -- one each for header/body/footer,
10654
+ // reading the live pinned set via `useSelectionStickyFirst` (column-layout.ts) instead
10655
+ // of the `stickyFirst` PROP alone, so the checkbox column sticks the moment ANY column
10656
+ // is pinned, uncontrolled or not (see that hook's own doc comment for why this can't
10657
+ // just be computed once, above, in `DataTableInner`).
10658
+ function SelectionHeaderCell({ stickyFirst, children }) {
10659
+ const resolvedStickyFirst = useSelectionStickyFirst(stickyFirst);
10660
+ return /*#__PURE__*/ jsx(DataTableSelectionHeaderCell, {
10661
+ ...selectionStickyProps(resolvedStickyFirst),
10662
+ children: children
10663
+ });
10664
+ }
10665
+ function SelectionCell({ stickyFirst, onClick, children }) {
10666
+ const resolvedStickyFirst = useSelectionStickyFirst(stickyFirst);
10667
+ return /*#__PURE__*/ jsx(DataTableSelectionCell, {
10668
+ onClick: onClick,
10669
+ ...selectionStickyProps(resolvedStickyFirst),
10670
+ children: children
10671
+ });
10672
+ }
10673
+ function SelectionFooterCell({ stickyFirst }) {
10674
+ const resolvedStickyFirst = useSelectionStickyFirst(stickyFirst);
10675
+ return /*#__PURE__*/ jsx(DataTableFooterCell, {
10676
+ ...selectionStickyProps(resolvedStickyFirst)
10677
+ });
10678
+ }
10259
10679
  ////////////////////////////////////////////////////////////////////////////////////
10260
10680
  // Fix (bug report): karrot icons default to a 24px intrinsic SVG attribute size
10261
10681
  // -- see column-menu.tsx's own `SORT_ICON_SIZE` comment for the full mechanism.
@@ -10311,4 +10731,943 @@ function SelectAllCheckbox({ label, checkedIcon, indeterminateIcon }) {
10311
10731
  });
10312
10732
  }
10313
10733
 
10314
- export { DataTable };
10734
+ const rowStyle = {
10735
+ display: "flex",
10736
+ alignItems: "center",
10737
+ gap: 4
10738
+ };
10739
+ const rowButtonStyle = {
10740
+ flex: 1,
10741
+ minWidth: 0,
10742
+ textAlign: "left",
10743
+ display: "flex",
10744
+ alignItems: "center",
10745
+ gap: 6,
10746
+ padding: "6px 8px",
10747
+ border: "none",
10748
+ borderRadius: 6,
10749
+ background: "transparent",
10750
+ color: "var(--seed-color-fg-neutral)",
10751
+ fontSize: 13,
10752
+ cursor: "pointer",
10753
+ overflow: "hidden",
10754
+ textOverflow: "ellipsis",
10755
+ whiteSpace: "nowrap"
10756
+ };
10757
+ const smallButtonStyle = {
10758
+ flexShrink: 0,
10759
+ border: "none",
10760
+ borderRadius: 6,
10761
+ background: "transparent",
10762
+ color: "var(--seed-color-fg-neutral-subtle)",
10763
+ fontSize: 12,
10764
+ padding: "4px 6px",
10765
+ cursor: "pointer"
10766
+ };
10767
+ const iconButtonStyle = {
10768
+ display: "inline-flex",
10769
+ alignItems: "center",
10770
+ justifyContent: "center",
10771
+ width: 22,
10772
+ height: 22,
10773
+ flexShrink: 0,
10774
+ border: "none",
10775
+ borderRadius: 6,
10776
+ background: "transparent",
10777
+ color: "var(--seed-color-fg-neutral-subtle)",
10778
+ cursor: "pointer"
10779
+ };
10780
+ /**
10781
+ * A compact saved-views switcher -- current view name (or `label`) as the trigger,
10782
+ * a popover listing every saved view (click to switch, inline Rename/Delete), a
10783
+ * trailing "Save as new view", and (once a view is active) "Update view" to overwrite
10784
+ * the loaded view with the table's current state.
10785
+ */ function DataTableViewsControl({ label = "Views", showClearRow = false, clearLabel, captureState, applyState, newViewLabel = "Save as new view", updateViewLabel = "Update view", renameLabel = "Rename", deleteLabel = "Delete", renameInputLabel = (name)=>`Rename ${name}`, ...viewsProps }) {
10786
+ const viewsApi = useDataTableViews(viewsProps);
10787
+ const { activeViewId, activeView } = viewsApi;
10788
+ const triggerLabel = activeView ? activeView.name : label;
10789
+ return /*#__PURE__*/ jsxs(MenuRoot, {
10790
+ children: [
10791
+ /*#__PURE__*/ jsx(MenuTrigger, {
10792
+ asChild: true,
10793
+ children: /*#__PURE__*/ jsxs(ActionButton, {
10794
+ variant: "neutralOutline",
10795
+ size: "xsmall",
10796
+ "data-active": activeViewId ? "" : undefined,
10797
+ children: [
10798
+ /*#__PURE__*/ jsx(IconArrowUpArrowDownLine_default, {
10799
+ size: 14,
10800
+ strokeWidth: 1.75
10801
+ }),
10802
+ triggerLabel,
10803
+ /*#__PURE__*/ jsx(IconChevronDownSmallLine_default, {
10804
+ size: 14,
10805
+ strokeWidth: 1.75
10806
+ })
10807
+ ]
10808
+ })
10809
+ }),
10810
+ /*#__PURE__*/ jsx(MenuPositioner, {
10811
+ children: /*#__PURE__*/ jsx(MenuContent, {
10812
+ style: {
10813
+ minWidth: 240
10814
+ },
10815
+ children: /*#__PURE__*/ jsx(MenuScrollArea, {
10816
+ children: /*#__PURE__*/ jsx(ViewsMenuBody, {
10817
+ viewsApi: viewsApi,
10818
+ captureState: captureState,
10819
+ applyState: applyState,
10820
+ label: label,
10821
+ showClearRow: showClearRow,
10822
+ clearLabel: clearLabel,
10823
+ newViewLabel: newViewLabel,
10824
+ updateViewLabel: updateViewLabel,
10825
+ renameLabel: renameLabel,
10826
+ deleteLabel: deleteLabel,
10827
+ renameInputLabel: renameInputLabel
10828
+ })
10829
+ })
10830
+ })
10831
+ })
10832
+ ]
10833
+ });
10834
+ }
10835
+ DataTableViewsControl.displayName = "DataTableViewsControl";
10836
+ /**
10837
+ * The popover's own body -- split out from `DataTableViewsControl` purely so it can
10838
+ * call `useMenuContext()` (`@seed-design/react-menu`), which only resolves for a
10839
+ * descendant of `MenuRoot`, not the component that RENDERS `MenuRoot` itself (the same
10840
+ * reason `column-layout.ts`'s `useSelectionStickyFirst` is its own component-level
10841
+ * hook rather than something computed in `DataTable.tsx` above its provider). Plain
10842
+ * `<button>` rows here (not seed `MenuItem`s -- `toolbar-conditions.tsx`'s own Sort/
10843
+ * Filter popovers make the same call) don't auto-close the menu on click the way a real
10844
+ * `MenuItem` does, so switching/creating/updating a view calls `setOpen(false)` here
10845
+ * explicitly; renaming and deleting deliberately do NOT close it, so a consumer can
10846
+ * clean up more than one view without reopening the popover each time.
10847
+ */ function ViewsMenuBody({ viewsApi, captureState, applyState, label, showClearRow, clearLabel, newViewLabel, updateViewLabel, renameLabel, deleteLabel, renameInputLabel }) {
10848
+ const { views, activeViewId, createView, updateView, renameView, deleteView, selectView } = viewsApi;
10849
+ const { setOpen } = useMenuContext();
10850
+ const [renamingId, setRenamingId] = React.useState(null);
10851
+ const [renameValue, setRenameValue] = React.useState("");
10852
+ // Same race `column-menu.tsx`'s own inline rename input already guards against:
10853
+ // starting a rename swaps the clicked "Rename" button for an input in the SAME
10854
+ // MenuContent this popover's own floating-ui focus management watches, and its
10855
+ // focus-guard spans can steal focus right back (to the content, or the trigger)
10856
+ // one frame after mount -- BEFORE this ref flips true -- so `onBlur` ignores that
10857
+ // one spurious blur and only commits a REAL blur (an actual click/tab away) after.
10858
+ const renameReadyRef = React.useRef(false);
10859
+ const renameInputRef = React.useRef(null);
10860
+ const handleSelect = (id)=>{
10861
+ selectView(id);
10862
+ if (id !== null) {
10863
+ const view = views.find((v)=>v.id === id);
10864
+ if (view) applyState(view.state);
10865
+ }
10866
+ setOpen(false);
10867
+ };
10868
+ const handleCreate = ()=>{
10869
+ createView(`View ${views.length + 1}`, captureState());
10870
+ setOpen(false);
10871
+ };
10872
+ const handleUpdate = ()=>{
10873
+ if (activeViewId) updateView(activeViewId, captureState());
10874
+ setOpen(false);
10875
+ };
10876
+ const startRename = (view)=>{
10877
+ renameReadyRef.current = false;
10878
+ setRenamingId(view.id);
10879
+ setRenameValue(view.name);
10880
+ };
10881
+ const commitRename = ()=>{
10882
+ if (renamingId && renameValue.trim()) renameView(renamingId, renameValue.trim());
10883
+ setRenamingId(null);
10884
+ };
10885
+ React.useEffect(()=>{
10886
+ if (!renamingId) return;
10887
+ // Re-grab focus (and select the text) one frame after mount, AFTER whatever
10888
+ // floating-ui's own focus-guard restore was going to do -- see this component's
10889
+ // own `renameReadyRef` doc comment above.
10890
+ const frame = requestAnimationFrame(()=>{
10891
+ renameReadyRef.current = true;
10892
+ renameInputRef.current?.focus();
10893
+ renameInputRef.current?.select();
10894
+ });
10895
+ return ()=>cancelAnimationFrame(frame);
10896
+ }, [
10897
+ renamingId
10898
+ ]);
10899
+ return /*#__PURE__*/ jsxs("div", {
10900
+ style: {
10901
+ display: "flex",
10902
+ flexDirection: "column",
10903
+ gap: 2,
10904
+ padding: "4px 8px"
10905
+ },
10906
+ children: [
10907
+ showClearRow && /*#__PURE__*/ jsx("button", {
10908
+ type: "button",
10909
+ onClick: ()=>handleSelect(null),
10910
+ "data-active": !activeViewId ? "" : undefined,
10911
+ style: rowButtonStyle,
10912
+ children: clearLabel ?? label
10913
+ }),
10914
+ views.length === 0 && /*#__PURE__*/ jsx("div", {
10915
+ style: {
10916
+ fontSize: 13,
10917
+ color: "var(--seed-color-fg-neutral-subtle)",
10918
+ padding: "4px 8px"
10919
+ },
10920
+ children: "No saved views yet."
10921
+ }),
10922
+ views.map((view)=>renamingId === view.id ? /*#__PURE__*/ jsx("div", {
10923
+ style: rowStyle,
10924
+ children: /*#__PURE__*/ jsx("input", {
10925
+ ref: renameInputRef,
10926
+ // biome-ignore lint/a11y/noAutofocus: opening this input IS the user's own "Rename" click a moment earlier, not an unannounced page-load autofocus (same call column-menu.tsx's own inline rename input makes).
10927
+ autoFocus: true,
10928
+ "aria-label": renameInputLabel(view.name),
10929
+ value: renameValue,
10930
+ onChange: (event)=>setRenameValue(event.target.value),
10931
+ onBlur: ()=>{
10932
+ if (renameReadyRef.current) commitRename();
10933
+ },
10934
+ onKeyDown: (event)=>{
10935
+ event.stopPropagation();
10936
+ if (event.key === "Enter") commitRename();
10937
+ if (event.key === "Escape") setRenamingId(null);
10938
+ },
10939
+ style: {
10940
+ flex: 1,
10941
+ minWidth: 0,
10942
+ font: "inherit",
10943
+ fontSize: 13,
10944
+ padding: "6px 8px",
10945
+ border: "1px solid var(--seed-color-border-neutral)",
10946
+ borderRadius: 6,
10947
+ background: "var(--seed-color-bg-surface)",
10948
+ color: "var(--seed-color-fg-neutral)"
10949
+ }
10950
+ })
10951
+ }, view.id) : /*#__PURE__*/ jsxs("div", {
10952
+ style: rowStyle,
10953
+ children: [
10954
+ /*#__PURE__*/ jsx("button", {
10955
+ type: "button",
10956
+ onClick: ()=>handleSelect(view.id),
10957
+ "data-active": view.id === activeViewId ? "" : undefined,
10958
+ style: rowButtonStyle,
10959
+ children: view.name
10960
+ }),
10961
+ /*#__PURE__*/ jsx("button", {
10962
+ type: "button",
10963
+ onClick: ()=>startRename(view),
10964
+ style: smallButtonStyle,
10965
+ children: renameLabel
10966
+ }),
10967
+ /*#__PURE__*/ jsx("button", {
10968
+ type: "button",
10969
+ "aria-label": `${deleteLabel} ${view.name}`,
10970
+ onClick: ()=>deleteView(view.id),
10971
+ style: iconButtonStyle,
10972
+ children: /*#__PURE__*/ jsx(IconXmarkLine_default, {
10973
+ size: 13,
10974
+ strokeWidth: 1.75
10975
+ })
10976
+ })
10977
+ ]
10978
+ }, view.id)),
10979
+ activeViewId && /*#__PURE__*/ jsx("button", {
10980
+ type: "button",
10981
+ onClick: handleUpdate,
10982
+ style: {
10983
+ ...rowButtonStyle,
10984
+ color: "var(--seed-color-fg-neutral-subtle)"
10985
+ },
10986
+ children: updateViewLabel
10987
+ }),
10988
+ /*#__PURE__*/ jsxs("button", {
10989
+ type: "button",
10990
+ onClick: handleCreate,
10991
+ style: rowButtonStyle,
10992
+ children: [
10993
+ /*#__PURE__*/ jsx(IconPlusLine_default, {
10994
+ size: 13,
10995
+ strokeWidth: 1.75
10996
+ }),
10997
+ newViewLabel
10998
+ ]
10999
+ })
11000
+ ]
11001
+ });
11002
+ }
11003
+
11004
+ __insertCSS(".seed-resizable-panel__root{position:relative;display:flex;height:100%}.seed-resizable-panel__spacer{flex:0 0 auto;height:100%;transition:width .14s}.seed-resizable-panel__panel{position:absolute;top:0;bottom:0;box-sizing:border-box;overflow:hidden;background:var(--seed-color-bg-layer-default)}.seed-resizable-panel__panel[data-side=left]{left:0}.seed-resizable-panel__panel[data-side=right]{right:0}.seed-resizable-panel__panel[data-floating=false]{border-radius:0;box-shadow:none}.seed-resizable-panel__panel[data-floating=false][data-side=left]{border-inline-end:1px solid var(--seed-color-stroke-neutral-muted)}.seed-resizable-panel__panel[data-floating=false][data-side=right]{border-inline-start:1px solid var(--seed-color-stroke-neutral-muted)}.seed-resizable-panel__panel[data-floating=true]{position:fixed;top:8px;bottom:8px;border-inline-end:none;border-inline-start:none;border-radius:10px;box-shadow:inset 0 0 0 1px transparent,0 0 0 1px rgba(28,40,64,.04),0 4px 8px -4px rgba(28,40,64,.12),0 4px 12px -2px rgba(24,41,75,.16);transform:none;transition:transform .14s,padding .14s}.seed-resizable-panel__panel[data-floating=true][data-side=left]{padding:8px 0 8px 8px}[data-floating=true]>.seed-resizable-panel__inner{transition:opacity .14s}.seed-resizable-panel__handle[data-side=left]{right:0}.seed-resizable-panel__handle[data-side=right]{left:0}.seed-resizable-panel__handle::before{content:\"\";position:absolute;top:0;width:1px;height:100%;background:var(--seed-color-stroke-neutral-muted);transition:background-color .16s,height .16s}.seed-resizable-panel__handle[data-side=left]::before{right:0}.seed-resizable-panel__handle[data-side=right]::before{left:0}.seed-resizable-panel__handle:hover::before,.seed-resizable-panel__handle[data-dragging]::before{width:2px;background:#0298d9}.seed-resizable-panel__handle.crisp-seed-resizable-panel-handle--column{display:flex;align-items:center;justify-content:center;width:7px;left:-3px;right:-3px;z-index:1;cursor:col-resize}.seed-resizable-panel__handle.crisp-seed-resizable-panel-handle--column::before{content:none}.seed-resizable-panel__handleInner{width:3px;height:100%;border-radius:3px;background:#0298d9;opacity:0;transition:opacity .1s .1s}.seed-resizable-panel__handle:hover .seed-resizable-panel__handleInner,.seed-resizable-panel__handle[data-dragging] .seed-resizable-panel__handleInner{opacity:1}");
11005
+
11006
+ const resizablePanelSlotNames = [
11007
+ [
11008
+ "root",
11009
+ "seed-resizable-panel__root"
11010
+ ],
11011
+ [
11012
+ "spacer",
11013
+ "seed-resizable-panel__spacer"
11014
+ ],
11015
+ [
11016
+ "panel",
11017
+ "seed-resizable-panel__panel"
11018
+ ],
11019
+ [
11020
+ "inner",
11021
+ "seed-resizable-panel__inner"
11022
+ ],
11023
+ [
11024
+ "handle",
11025
+ "seed-resizable-panel__handle"
11026
+ ],
11027
+ [
11028
+ "handleInner",
11029
+ "seed-resizable-panel__handleInner"
11030
+ ]
11031
+ ];
11032
+ const defaultVariant$1 = {};
11033
+ const compoundVariants$1 = [];
11034
+ const resizablePanelVariantMap = {};
11035
+ function resizablePanel(props) {
11036
+ return Object.fromEntries(resizablePanelSlotNames.map(([slot, className])=>{
11037
+ return [
11038
+ slot,
11039
+ createClassName(className, mergeVariants(defaultVariant$1, props), compoundVariants$1)
11040
+ ];
11041
+ }));
11042
+ }
11043
+ Object.assign(resizablePanel, {
11044
+ splitVariantProps: (props)=>splitVariantProps(props, resizablePanelVariantMap)
11045
+ }); // @recipe(seed): resizable-panel
11046
+
11047
+ // Pure geometry + persistence helpers for ResizablePanel -- isolated from React so
11048
+ // they're unit-testable without a DOM, the same split `useDataTable`'s own dom.ts
11049
+ // draws for its column-layout math. Ported from your-moon/crisp's
11050
+ // `components/resizablepanel/resizablepanel.tsx` (computeDragWidth/widthToPercent/
11051
+ // percentToWidth/readStoredPercent/writeStoredPercent), unchanged in behavior.
11052
+ /**
11053
+ * Drag delta -> next width, in px, signed by which edge of the panel the handle
11054
+ * drags from. A left-side panel's handle sits at its *right* edge, so dragging
11055
+ * right (positive dx) grows it; a right-side panel's handle sits at its *left*
11056
+ * edge, so dragging right shrinks it.
11057
+ */ function computeDragWidth(startWidth, startX, clientX, side) {
11058
+ const dx = clientX - startX;
11059
+ return side === "left" ? startWidth + dx : startWidth - dx;
11060
+ }
11061
+ /** width (px) -> percentage of the container's width. Pure, unrounded. */ function widthToPercent(width, containerWidth) {
11062
+ if (!(containerWidth > 0)) return 0;
11063
+ return width / containerWidth * 100;
11064
+ }
11065
+ /** percentage of the container's width -> width (px). Pure, unrounded. */ function percentToWidth(percent, containerWidth) {
11066
+ return percent / 100 * containerWidth;
11067
+ }
11068
+ /**
11069
+ * Reads a persisted width percentage, wrapped in try/catch: `localStorage` can
11070
+ * throw (private browsing, storage disabled), and a resizable panel failing to
11071
+ * *render* over a persistence error would be worse than the panel simply
11072
+ * forgetting its width. `storage` defaults to `window.localStorage` and exists
11073
+ * as a seam for tests -- dropping the try/catch here is the exact failure this
11074
+ * must catch.
11075
+ */ function readStoredPercent(key, storage = window.localStorage) {
11076
+ try {
11077
+ const raw = storage.getItem(key);
11078
+ if (raw == null) return null;
11079
+ const n = Number(raw);
11080
+ return Number.isFinite(n) ? n : null;
11081
+ } catch {
11082
+ // private mode / storage disabled -- behave as if nothing is stored
11083
+ return null;
11084
+ }
11085
+ }
11086
+ /** Writes a persisted width percentage, wrapped in try/catch -- see {@link readStoredPercent}. */ function writeStoredPercent(key, percent, storage = window.localStorage) {
11087
+ try {
11088
+ storage.setItem(key, String(percent));
11089
+ } catch {
11090
+ // private mode / quota exceeded -- persistence is best-effort
11091
+ }
11092
+ }
11093
+ /**
11094
+ * Owns ResizablePanel's width state and pointer-drag handling -- the same
11095
+ * split `useDataTableSort` draws between the state it owns and the DOM
11096
+ * ref/style/recipe-class assembly a styled component does on top. Ported
11097
+ * from your-moon/crisp's `resizablepanel.tsx`; ONLY the state/behavior moved
11098
+ * here, not the DOM -- `ResizablePanel.tsx` (react package) still renders
11099
+ * the spacer/panel/handle and reads back the panel's actual rendered rect,
11100
+ * because crisp's own comment matters just as much in this split: constraints
11101
+ * are CSS `min-width`/`max-width`, never re-clamped in JS. This hook only
11102
+ * ever writes an UNclamped drag width; the caller's own panel ref is what
11103
+ * gets read back after layout on pointerup.
11104
+ */ function useResizablePanel(props) {
11105
+ const { side = "left", size, defaultSize = 280, onSizeChange, storageKey } = props;
11106
+ const controlled = size != null;
11107
+ const [width, setWidth] = useControllableState$1({
11108
+ prop: size,
11109
+ defaultProp: defaultSize,
11110
+ onChange: onSizeChange
11111
+ });
11112
+ const containerRef = React.useRef(null);
11113
+ const panelRef = React.useRef(null);
11114
+ const dragRef = React.useRef(null);
11115
+ const [dragging, setDragging] = React.useState(false);
11116
+ // Restore a persisted percentage on mount (uncontrolled + storageKey only).
11117
+ // biome-ignore lint/correctness/useExhaustiveDependencies: restore the persisted width once, on mount only
11118
+ React.useEffect(()=>{
11119
+ if (controlled || !storageKey) return;
11120
+ const percent = readStoredPercent(storageKey);
11121
+ if (percent == null) return;
11122
+ const containerWidth = containerRef.current?.getBoundingClientRect().width;
11123
+ if (!containerWidth) return;
11124
+ setWidth(percentToWidth(percent, containerWidth));
11125
+ }, []);
11126
+ const commitSize = React.useCallback((next)=>{
11127
+ setWidth(next);
11128
+ if (!controlled && storageKey) {
11129
+ const containerWidth = containerRef.current?.getBoundingClientRect().width;
11130
+ if (containerWidth) {
11131
+ writeStoredPercent(storageKey, widthToPercent(next, containerWidth));
11132
+ }
11133
+ }
11134
+ }, [
11135
+ controlled,
11136
+ setWidth,
11137
+ storageKey
11138
+ ]);
11139
+ const onHandlePointerDown = React.useCallback((event)=>{
11140
+ event.preventDefault();
11141
+ event.target.setPointerCapture?.(event.pointerId);
11142
+ dragRef.current = {
11143
+ startX: event.clientX,
11144
+ startWidth: width,
11145
+ moved: false
11146
+ };
11147
+ }, [
11148
+ width
11149
+ ]);
11150
+ const onHandlePointerMove = React.useCallback((event)=>{
11151
+ const drag = dragRef.current;
11152
+ if (!drag) return;
11153
+ if (!drag.moved) {
11154
+ drag.moved = true;
11155
+ setDragging(true);
11156
+ }
11157
+ const next = computeDragWidth(drag.startWidth, drag.startX, event.clientX, side);
11158
+ setWidth(next);
11159
+ }, [
11160
+ side,
11161
+ setWidth
11162
+ ]);
11163
+ const onHandlePointerUp = React.useCallback((event)=>{
11164
+ const drag = dragRef.current;
11165
+ dragRef.current = null;
11166
+ setDragging(false);
11167
+ event.target.releasePointerCapture?.(event.pointerId);
11168
+ if (!drag) return;
11169
+ // Never re-clamp here: read back the panel's actual, CSS-clamped
11170
+ // rendered width after layout, and commit *that* value.
11171
+ const rect = panelRef.current?.getBoundingClientRect();
11172
+ const finalWidth = rect ? Math.round(rect.width) : width;
11173
+ commitSize(finalWidth);
11174
+ }, [
11175
+ width,
11176
+ commitSize
11177
+ ]);
11178
+ // your-moon/crisp#795: double-click resets to `defaultSize`, confirmed
11179
+ // live on Attio's own record-page divider. Reuses `commitSize`, the same
11180
+ // commit path a drag already uses, so persistence (`storageKey`) picks up
11181
+ // the reset the same way it picks up a drag.
11182
+ const onHandleDoubleClick = React.useCallback(()=>{
11183
+ commitSize(defaultSize);
11184
+ }, [
11185
+ commitSize,
11186
+ defaultSize
11187
+ ]);
11188
+ return {
11189
+ width,
11190
+ dragging,
11191
+ containerRef,
11192
+ panelRef,
11193
+ handleHandlers: {
11194
+ onPointerDown: onHandlePointerDown,
11195
+ onPointerMove: onHandlePointerMove,
11196
+ onPointerUp: onHandlePointerUp,
11197
+ onDoubleClick: onHandleDoubleClick
11198
+ }
11199
+ };
11200
+ }
11201
+
11202
+ // The "column" handle variant's own wider hit-target class -- a literal
11203
+ // class name (not a recipe slot) the same way the recipe itself keys off it
11204
+ // (`resizable-panel.ts`'s own `.crisp-seed-resizable-panel-handle--column`
11205
+ // selector), so this component and that recipe stay in lockstep without a
11206
+ // second source of truth for the string.
11207
+ const COLUMN_HANDLE_CLASS = "crisp-seed-resizable-panel-handle--column";
11208
+ /**
11209
+ * An adjustable-panel primitive: a spacer that reserves layout width plus a
11210
+ * panel that overlays it, so the panel can move between docked (in-flow) and
11211
+ * floating (`position: fixed`, an overlay) without a reflow glitch. Drag the
11212
+ * edge handle to resize; constraints are CSS `min-width`/`max-width`, never
11213
+ * re-clamped in JS. Ported from your-moon/crisp's `ResizablePanel`
11214
+ * (`components/resizablepanel/`); state/drag behavior lives in
11215
+ * `useResizablePanel` (`@seed-design/react-resizable-panel`), this component
11216
+ * owns the DOM + recipe classes on top of it.
11217
+ */ const ResizablePanel = /*#__PURE__*/ forwardRef(({ side = "left", width: sizeProp, defaultSize = 280, onWidthChange, min = 200, max, floating = false, handleVariant = "panel", resizable = true, storageKey, className, children, ...rest }, forwardedRef)=>{
11218
+ const { width, dragging, containerRef, panelRef, handleHandlers } = useResizablePanel({
11219
+ side,
11220
+ size: sizeProp,
11221
+ defaultSize,
11222
+ onSizeChange: onWidthChange,
11223
+ storageKey
11224
+ });
11225
+ const classNames = resizablePanel();
11226
+ const maxStyle = max == null ? undefined : typeof max === "number" ? `${max}px` : max;
11227
+ const panelSizeStyle = {
11228
+ width,
11229
+ minWidth: min,
11230
+ maxWidth: maxStyle
11231
+ };
11232
+ return /*#__PURE__*/ jsxs(Primitive.div, {
11233
+ ref: (node)=>{
11234
+ containerRef.current = node;
11235
+ if (typeof forwardedRef === "function") forwardedRef(node);
11236
+ else if (forwardedRef) forwardedRef.current = node;
11237
+ },
11238
+ className: clsx(classNames.root, className),
11239
+ ...rest,
11240
+ children: [
11241
+ /*#__PURE__*/ jsx(Primitive.div, {
11242
+ className: classNames.spacer,
11243
+ style: floating ? {
11244
+ width: 0
11245
+ } : {
11246
+ width,
11247
+ minWidth: min,
11248
+ maxWidth: maxStyle
11249
+ }
11250
+ }),
11251
+ /*#__PURE__*/ jsxs(Primitive.div, {
11252
+ ref: panelRef,
11253
+ className: classNames.panel,
11254
+ "data-side": side,
11255
+ "data-floating": floating ? "true" : "false",
11256
+ style: panelSizeStyle,
11257
+ children: [
11258
+ /*#__PURE__*/ jsx(Primitive.div, {
11259
+ className: classNames.inner,
11260
+ children: children
11261
+ }),
11262
+ resizable && /*#__PURE__*/ jsx(Primitive.div, {
11263
+ className: clsx(classNames.handle, handleVariant === "column" && COLUMN_HANDLE_CLASS),
11264
+ "data-side": side,
11265
+ "data-dragging": dragging ? "true" : undefined,
11266
+ "data-handle": "",
11267
+ ...handleHandlers,
11268
+ children: handleVariant === "column" && /*#__PURE__*/ jsx(Primitive.span, {
11269
+ className: classNames.handleInner,
11270
+ "aria-hidden": "true"
11271
+ })
11272
+ })
11273
+ ]
11274
+ })
11275
+ ]
11276
+ });
11277
+ });
11278
+ ResizablePanel.displayName = "ResizablePanel";
11279
+
11280
+ __insertCSS(".seed-record-panel__root{display:flex;flex-direction:column;height:100%;overflow:hidden;background:var(--seed-color-bg-layer-default);font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.seed-record-panel__toolbar{display:flex;align-items:center;height:49px;flex-shrink:0;padding:8px 10px;border-bottom:1px solid var(--seed-color-stroke-neutral-muted)}.seed-record-panel__toolbarSpacer{flex:1}.seed-record-panel__pager{display:flex;align-items:center;gap:6px;margin-inline-start:12px}.seed-record-panel__counter{margin-inline-start:12px;font-size:12px;font-weight:500;color:var(--seed-color-fg-neutral-subtle);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.seed-record-panel__iconbtn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;flex-shrink:0;padding:0;border:none;border-radius:6px;background:0 0;color:var(--seed-color-fg-neutral-subtle);font-family:inherit;cursor:pointer;transition:background-color .12s}.seed-record-panel__iconbtn:hover{background:var(--seed-color-bg-layer-fill);color:var(--seed-color-fg-neutral)}.seed-record-panel__navbtn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;flex-shrink:0;padding:0;border:none;border-radius:6px;background:var(--seed-color-bg-layer-default);box-shadow:inset 0 0 0 1px rgba(0,0,0,.06),0 0 2px rgba(28,40,64,.18),0 1px 3px rgba(0,0,0,.04);color:var(--seed-color-fg-neutral);font-family:inherit;cursor:pointer}.seed-record-panel__navbtn:hover:not(:disabled){background:var(--seed-color-bg-layer-fill)}.seed-record-panel__navbtn:disabled{opacity:.4;cursor:not-allowed}.seed-record-panel__header{display:flex;align-items:center;gap:8px;height:52px;flex-shrink:0;padding:0 12px}.seed-record-panel__fav{width:22px;height:22px;border-radius:4px;flex-shrink:0;object-fit:cover;background:var(--seed-color-bg-layer-fill)}.seed-record-panel__title{flex:1;min-width:0;font-size:16px;font-weight:600;letter-spacing:-.2px;color:var(--seed-color-fg-neutral);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.seed-record-panel__body{flex:1;min-height:0;overflow-y:auto;padding:8px 12px}.seed-record-panel__section{padding:8px 4px 0}.seed-record-panel__sectionHead{display:flex;align-items:center;justify-content:space-between;gap:8px;height:20px;margin-bottom:8px}.seed-record-panel__sectionLabel{font-size:14px;font-weight:500;color:var(--seed-color-fg-neutral-subtle)}.seed-record-panel__sectionAction{border:none;background:0 0;padding:0;font-family:inherit;font-size:10px;font-weight:400;color:color-mix(in srgb,var(--seed-color-fg-neutral) 55%,transparent);cursor:pointer}.seed-record-panel__sectionAction:hover{color:var(--seed-color-fg-neutral)}.seed-record-panel__highlights{display:grid;grid-template-columns:1fr 1fr;gap:8px}.seed-record-panel__highlight{display:flex;flex-direction:column;gap:6px;min-width:0}.seed-record-panel__highlightLabel{display:flex;align-items:center;gap:4px;font-size:12px;font-weight:500;color:var(--seed-color-fg-neutral-subtle)}.seed-record-panel__highlightLabel span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.seed-record-panel__highlightLabel svg{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle)}.seed-record-panel__highlightValue{font-size:14px;font-weight:500;color:var(--seed-color-fg-neutral);overflow:hidden;text-overflow:ellipsis}.seed-record-panel__activity{font-size:14px}.seed-record-panel__sections{display:flex;flex-direction:column;padding-top:8px}.seed-record-panel__sectionTrigger{display:flex;align-items:center;gap:4px;width:100%;height:20px;padding:0 8px 0 12px;border:none;background:0 0;font-family:inherit;text-align:start;cursor:pointer}.seed-record-panel__sectionTrigger[data-inert]{cursor:default}.seed-record-panel__sectionRowLabel{font-size:14px;font-weight:500;color:var(--seed-color-fg-neutral)}.seed-record-panel__sectionRowCount{font-size:14px;color:var(--seed-color-fg-neutral-subtle)}.seed-record-panel__sectionChevron{margin-inline-start:auto;flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);transition:transform .15s ease}.seed-record-panel__sectionChevron[data-open]{transform:rotate(180deg)}.seed-record-panel__sectionContent{padding:8px 8px 8px 12px}.seed-record-panel__footer{flex-shrink:0;display:flex;align-items:center;gap:8px;padding:8px 12px;border-top:1px solid var(--seed-color-stroke-neutral-muted)}");
11281
+
11282
+ const recordPanelSlotNames = [
11283
+ [
11284
+ "root",
11285
+ "seed-record-panel__root"
11286
+ ],
11287
+ [
11288
+ "toolbar",
11289
+ "seed-record-panel__toolbar"
11290
+ ],
11291
+ [
11292
+ "toolbarSpacer",
11293
+ "seed-record-panel__toolbarSpacer"
11294
+ ],
11295
+ [
11296
+ "pager",
11297
+ "seed-record-panel__pager"
11298
+ ],
11299
+ [
11300
+ "counter",
11301
+ "seed-record-panel__counter"
11302
+ ],
11303
+ [
11304
+ "iconbtn",
11305
+ "seed-record-panel__iconbtn"
11306
+ ],
11307
+ [
11308
+ "navbtn",
11309
+ "seed-record-panel__navbtn"
11310
+ ],
11311
+ [
11312
+ "header",
11313
+ "seed-record-panel__header"
11314
+ ],
11315
+ [
11316
+ "fav",
11317
+ "seed-record-panel__fav"
11318
+ ],
11319
+ [
11320
+ "title",
11321
+ "seed-record-panel__title"
11322
+ ],
11323
+ [
11324
+ "body",
11325
+ "seed-record-panel__body"
11326
+ ],
11327
+ [
11328
+ "section",
11329
+ "seed-record-panel__section"
11330
+ ],
11331
+ [
11332
+ "sectionHead",
11333
+ "seed-record-panel__sectionHead"
11334
+ ],
11335
+ [
11336
+ "sectionLabel",
11337
+ "seed-record-panel__sectionLabel"
11338
+ ],
11339
+ [
11340
+ "sectionAction",
11341
+ "seed-record-panel__sectionAction"
11342
+ ],
11343
+ [
11344
+ "highlights",
11345
+ "seed-record-panel__highlights"
11346
+ ],
11347
+ [
11348
+ "highlight",
11349
+ "seed-record-panel__highlight"
11350
+ ],
11351
+ [
11352
+ "highlightLabel",
11353
+ "seed-record-panel__highlightLabel"
11354
+ ],
11355
+ [
11356
+ "highlightValue",
11357
+ "seed-record-panel__highlightValue"
11358
+ ],
11359
+ [
11360
+ "activity",
11361
+ "seed-record-panel__activity"
11362
+ ],
11363
+ [
11364
+ "sections",
11365
+ "seed-record-panel__sections"
11366
+ ],
11367
+ [
11368
+ "sectionTrigger",
11369
+ "seed-record-panel__sectionTrigger"
11370
+ ],
11371
+ [
11372
+ "sectionRowLabel",
11373
+ "seed-record-panel__sectionRowLabel"
11374
+ ],
11375
+ [
11376
+ "sectionRowCount",
11377
+ "seed-record-panel__sectionRowCount"
11378
+ ],
11379
+ [
11380
+ "sectionChevron",
11381
+ "seed-record-panel__sectionChevron"
11382
+ ],
11383
+ [
11384
+ "sectionContent",
11385
+ "seed-record-panel__sectionContent"
11386
+ ],
11387
+ [
11388
+ "footer",
11389
+ "seed-record-panel__footer"
11390
+ ]
11391
+ ];
11392
+ const defaultVariant = {};
11393
+ const compoundVariants = [];
11394
+ const recordPanelVariantMap = {};
11395
+ function recordPanel(props) {
11396
+ return Object.fromEntries(recordPanelSlotNames.map(([slot, className])=>{
11397
+ return [
11398
+ slot,
11399
+ createClassName(className, mergeVariants(defaultVariant, props), compoundVariants)
11400
+ ];
11401
+ }));
11402
+ }
11403
+ Object.assign(recordPanel, {
11404
+ splitVariantProps: (props)=>splitVariantProps(props, recordPanelVariantMap)
11405
+ }); // @recipe(seed): record-panel
11406
+
11407
+ const RESIZE_MIN_WIDTH = 360;
11408
+ const RESIZE_MAX_WIDTH = 720;
11409
+ /**
11410
+ * Right-side record peek panel -- Attio's own peek shows a Highlights card
11411
+ * area and an Activity feed (measured live). Ported from your-moon/crisp's
11412
+ * `RecordPanel` (`product/recordpanel/`), built ON `ResizablePanel`
11413
+ * (`side="right" floating`) rather than crisp's own duplicate absolute-
11414
+ * positioning/slide-in/resize-handle implementation -- the outer shell (the
11415
+ * `@starting-style` slide-in, the floating elevation, the drag handle
11416
+ * itself) all come from that primitive; this component only renders the
11417
+ * CONTENT inside it.
11418
+ */ function RecordPanel({ open, record, onClose, className, closeLabel = "Close panel", onOpenRecord, openRecordLabel = "Open record", onPrevious, previousRecordLabel = "Previous record", onNext, nextRecordLabel = "Next record", title, avatar, highlightsLabel = "Highlights", highlights, counterLabel, resizable = false, width, defaultWidth = 420, onWidthChange, minWidth = RESIZE_MIN_WIDTH, maxWidth = RESIZE_MAX_WIDTH, activityLabel = "Activity", viewAllActivityLabel = "View all", onViewAllActivity, activity, sections, footer, ...rest }) {
11419
+ const titleId = useId();
11420
+ const classNames = recordPanel();
11421
+ // Which sections (your-moon/crisp#413) are expanded -- uncontrolled and
11422
+ // independent (Attio's own Emails/Notes/Tasks open without closing one
11423
+ // another): a plain `Set`, reset whenever the record itself changes so a
11424
+ // stale open section doesn't carry over between two different records.
11425
+ const [openSections, setOpenSections] = useState(()=>new Set());
11426
+ // biome-ignore lint/correctness/useExhaustiveDependencies: `record` is read as a change TRIGGER, not a value the effect body needs -- reset whenever it changes identity, regardless of what it now points to.
11427
+ useEffect(()=>{
11428
+ setOpenSections(new Set());
11429
+ }, [
11430
+ record
11431
+ ]);
11432
+ const toggleSection = (key)=>setOpenSections((prev)=>{
11433
+ const next = new Set(prev);
11434
+ if (next.has(key)) next.delete(key);
11435
+ else next.add(key);
11436
+ return next;
11437
+ });
11438
+ // Close on Escape while open. Simpler than crisp's own version (crisp
11439
+ // additionally checks `hasOpenFloatingLayer()` so an Escape meant for a
11440
+ // nested Menu/Select/Popover doesn't also close this panel) -- crispy-seed
11441
+ // has no equivalent floating-stack registry to read, so a consumer nesting
11442
+ // its own floating layers inside `footer`/`sections` content should stop
11443
+ // propagation on its own Escape handler.
11444
+ useEffect(()=>{
11445
+ if (!open) return;
11446
+ const onKey = (event)=>{
11447
+ if (event.key === "Escape") onClose();
11448
+ };
11449
+ document.addEventListener("keydown", onKey);
11450
+ return ()=>document.removeEventListener("keydown", onKey);
11451
+ }, [
11452
+ open,
11453
+ onClose
11454
+ ]);
11455
+ if (!open || !record) return null;
11456
+ const heading = title ?? record.name ?? "Record";
11457
+ return /*#__PURE__*/ jsx(ResizablePanel, {
11458
+ side: "right",
11459
+ floating: true,
11460
+ resizable: resizable,
11461
+ width: width,
11462
+ defaultSize: defaultWidth,
11463
+ onWidthChange: onWidthChange,
11464
+ min: minWidth,
11465
+ max: maxWidth,
11466
+ children: /*#__PURE__*/ jsxs(Primitive.div, {
11467
+ className: clsx(classNames.root, className),
11468
+ ...rest,
11469
+ role: "dialog",
11470
+ "aria-labelledby": titleId,
11471
+ children: [
11472
+ /*#__PURE__*/ jsxs(Primitive.div, {
11473
+ className: classNames.toolbar,
11474
+ children: [
11475
+ /*#__PURE__*/ jsx(Primitive.button, {
11476
+ type: "button",
11477
+ className: classNames.iconbtn,
11478
+ "aria-label": closeLabel,
11479
+ onClick: onClose,
11480
+ children: /*#__PURE__*/ jsx(IconXmarkLine_default, {
11481
+ size: 16
11482
+ })
11483
+ }),
11484
+ (onPrevious || onNext) && /*#__PURE__*/ jsxs(Primitive.span, {
11485
+ className: classNames.pager,
11486
+ children: [
11487
+ /*#__PURE__*/ jsx(Primitive.button, {
11488
+ type: "button",
11489
+ className: classNames.navbtn,
11490
+ "aria-label": previousRecordLabel,
11491
+ disabled: !onPrevious,
11492
+ onClick: onPrevious,
11493
+ children: /*#__PURE__*/ jsx(IconChevronUpLine_default, {
11494
+ size: 16
11495
+ })
11496
+ }),
11497
+ /*#__PURE__*/ jsx(Primitive.button, {
11498
+ type: "button",
11499
+ className: classNames.navbtn,
11500
+ "aria-label": nextRecordLabel,
11501
+ disabled: !onNext,
11502
+ onClick: onNext,
11503
+ children: /*#__PURE__*/ jsx(IconChevronDownLine_default, {
11504
+ size: 16
11505
+ })
11506
+ })
11507
+ ]
11508
+ }),
11509
+ counterLabel != null && /*#__PURE__*/ jsx(Primitive.span, {
11510
+ className: classNames.counter,
11511
+ children: counterLabel
11512
+ }),
11513
+ /*#__PURE__*/ jsx(Primitive.span, {
11514
+ className: classNames.toolbarSpacer
11515
+ }),
11516
+ onOpenRecord && /*#__PURE__*/ jsx(Primitive.button, {
11517
+ type: "button",
11518
+ className: classNames.navbtn,
11519
+ "aria-label": openRecordLabel,
11520
+ onClick: onOpenRecord,
11521
+ children: /*#__PURE__*/ jsx(IconArrowUpRightLine_default, {
11522
+ size: 16
11523
+ })
11524
+ })
11525
+ ]
11526
+ }),
11527
+ /*#__PURE__*/ jsxs(Primitive.div, {
11528
+ className: classNames.header,
11529
+ children: [
11530
+ avatar ? /*#__PURE__*/ jsx(Primitive.img, {
11531
+ className: classNames.fav,
11532
+ src: avatar,
11533
+ alt: ""
11534
+ }) : /*#__PURE__*/ jsx(AvatarRoot, {
11535
+ size: "24",
11536
+ children: /*#__PURE__*/ jsx(AvatarFallback, {
11537
+ children: (record.name ?? "?").charAt(0)
11538
+ })
11539
+ }),
11540
+ /*#__PURE__*/ jsx(Primitive.span, {
11541
+ id: titleId,
11542
+ className: classNames.title,
11543
+ children: heading
11544
+ })
11545
+ ]
11546
+ }),
11547
+ /*#__PURE__*/ jsxs(Primitive.div, {
11548
+ className: classNames.body,
11549
+ children: [
11550
+ highlights && highlights.length > 0 && /*#__PURE__*/ jsxs(Primitive.div, {
11551
+ className: classNames.section,
11552
+ children: [
11553
+ /*#__PURE__*/ jsx(Primitive.div, {
11554
+ className: classNames.sectionHead,
11555
+ children: /*#__PURE__*/ jsx(Primitive.span, {
11556
+ className: classNames.sectionLabel,
11557
+ children: highlightsLabel
11558
+ })
11559
+ }),
11560
+ /*#__PURE__*/ jsx(Primitive.div, {
11561
+ className: classNames.highlights,
11562
+ children: highlights.map((h)=>/*#__PURE__*/ jsxs(Primitive.div, {
11563
+ className: classNames.highlight,
11564
+ children: [
11565
+ /*#__PURE__*/ jsxs(Primitive.span, {
11566
+ className: classNames.highlightLabel,
11567
+ children: [
11568
+ /*#__PURE__*/ jsx("span", {
11569
+ children: h.label
11570
+ }),
11571
+ h.icon ? /*#__PURE__*/ jsx(h.icon, {
11572
+ size: 16
11573
+ }) : null
11574
+ ]
11575
+ }),
11576
+ /*#__PURE__*/ jsx(Primitive.span, {
11577
+ className: classNames.highlightValue,
11578
+ children: h.value
11579
+ })
11580
+ ]
11581
+ }, h.key))
11582
+ })
11583
+ ]
11584
+ }),
11585
+ activity != null && /*#__PURE__*/ jsxs(Primitive.div, {
11586
+ className: classNames.section,
11587
+ children: [
11588
+ /*#__PURE__*/ jsxs(Primitive.div, {
11589
+ className: classNames.sectionHead,
11590
+ children: [
11591
+ /*#__PURE__*/ jsx(Primitive.span, {
11592
+ className: classNames.sectionLabel,
11593
+ children: activityLabel
11594
+ }),
11595
+ onViewAllActivity && /*#__PURE__*/ jsx(Primitive.button, {
11596
+ type: "button",
11597
+ className: classNames.sectionAction,
11598
+ onClick: onViewAllActivity,
11599
+ children: viewAllActivityLabel
11600
+ })
11601
+ ]
11602
+ }),
11603
+ /*#__PURE__*/ jsx(Primitive.div, {
11604
+ className: classNames.activity,
11605
+ children: activity
11606
+ })
11607
+ ]
11608
+ }),
11609
+ sections && sections.length > 0 && /*#__PURE__*/ jsx(Primitive.div, {
11610
+ className: classNames.sections,
11611
+ children: sections.map((s)=>{
11612
+ const isOpen = openSections.has(s.key);
11613
+ const panelId = `${titleId}-section-${s.key}`;
11614
+ return /*#__PURE__*/ jsxs("div", {
11615
+ children: [
11616
+ s.content ? /*#__PURE__*/ jsxs(Primitive.button, {
11617
+ type: "button",
11618
+ className: classNames.sectionTrigger,
11619
+ "aria-expanded": isOpen,
11620
+ "aria-controls": panelId,
11621
+ onClick: ()=>toggleSection(s.key),
11622
+ children: [
11623
+ /*#__PURE__*/ jsx(Primitive.span, {
11624
+ className: classNames.sectionRowLabel,
11625
+ children: s.label
11626
+ }),
11627
+ /*#__PURE__*/ jsx(Primitive.span, {
11628
+ className: classNames.sectionRowCount,
11629
+ children: s.count
11630
+ }),
11631
+ /*#__PURE__*/ jsx(IconChevronDownLine_default, {
11632
+ className: classNames.sectionChevron,
11633
+ size: 14,
11634
+ "data-open": isOpen ? "" : undefined,
11635
+ "aria-hidden": "true"
11636
+ })
11637
+ ]
11638
+ }) : /*#__PURE__*/ jsxs(Primitive.div, {
11639
+ className: classNames.sectionTrigger,
11640
+ "data-inert": "",
11641
+ children: [
11642
+ /*#__PURE__*/ jsx(Primitive.span, {
11643
+ className: classNames.sectionRowLabel,
11644
+ children: s.label
11645
+ }),
11646
+ /*#__PURE__*/ jsx(Primitive.span, {
11647
+ className: classNames.sectionRowCount,
11648
+ children: s.count
11649
+ })
11650
+ ]
11651
+ }),
11652
+ s.content && isOpen && /*#__PURE__*/ jsx(Primitive.div, {
11653
+ id: panelId,
11654
+ className: classNames.sectionContent,
11655
+ children: s.content
11656
+ })
11657
+ ]
11658
+ }, s.key);
11659
+ })
11660
+ })
11661
+ ]
11662
+ }),
11663
+ footer != null && /*#__PURE__*/ jsx(Primitive.div, {
11664
+ className: classNames.footer,
11665
+ children: footer
11666
+ })
11667
+ ]
11668
+ })
11669
+ });
11670
+ }
11671
+ RecordPanel.displayName = "RecordPanel";
11672
+
11673
+ export { DataTable, DataTableViewsControl, RecordPanel, ResizablePanel };