@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.cjs CHANGED
@@ -55,7 +55,7 @@ function _interopNamespace(e) {
55
55
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
56
56
 
57
57
  // src/IconArrowUpLine.tsx
58
- var Icon$f = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
58
+ var Icon$h = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
59
59
  viewBox: "0 0 24 24",
60
60
  fill: "none",
61
61
  xmlns: "http://www.w3.org/2000/svg",
@@ -73,11 +73,11 @@ var Icon$f = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg
73
73
  })
74
74
  })
75
75
  });
76
- var IconArrowUpLine = /*#__PURE__*/ React.forwardRef(Icon$f);
76
+ var IconArrowUpLine = /*#__PURE__*/ React.forwardRef(Icon$h);
77
77
  var IconArrowUpLine_default = IconArrowUpLine;
78
78
 
79
79
  // src/IconArrowDownLine.tsx
80
- var Icon$e = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
80
+ var Icon$g = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
81
81
  viewBox: "0 0 24 24",
82
82
  fill: "none",
83
83
  xmlns: "http://www.w3.org/2000/svg",
@@ -95,11 +95,33 @@ var Icon$e = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg
95
95
  })
96
96
  })
97
97
  });
98
- var IconArrowDownLine = /*#__PURE__*/ React.forwardRef(Icon$e);
98
+ var IconArrowDownLine = /*#__PURE__*/ React.forwardRef(Icon$g);
99
99
  var IconArrowDownLine_default = IconArrowDownLine;
100
100
 
101
+ // src/IconArrowUpRightLine.tsx
102
+ var Icon$f = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
103
+ viewBox: "0 0 24 24",
104
+ fill: "none",
105
+ xmlns: "http://www.w3.org/2000/svg",
106
+ "data-seed-icon": "true",
107
+ width: size,
108
+ height: size,
109
+ ref,
110
+ ...props,
111
+ children: /* @__PURE__ */ jsxRuntime.jsx("g", {
112
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", {
113
+ fillRule: "evenodd",
114
+ clipRule: "evenodd",
115
+ 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",
116
+ fill: "currentColor"
117
+ })
118
+ })
119
+ });
120
+ var IconArrowUpRightLine = /*#__PURE__*/ React.forwardRef(Icon$f);
121
+ var IconArrowUpRightLine_default = IconArrowUpRightLine;
122
+
101
123
  // src/IconArrowUpArrowDownLine.tsx
102
- var Icon$d = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
124
+ var Icon$e = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
103
125
  viewBox: "0 0 24 24",
104
126
  fill: "none",
105
127
  xmlns: "http://www.w3.org/2000/svg",
@@ -123,11 +145,11 @@ var Icon$d = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg
123
145
  })
124
146
  })
125
147
  });
126
- var IconArrowUpArrowDownLine = /*#__PURE__*/ React.forwardRef(Icon$d);
148
+ var IconArrowUpArrowDownLine = /*#__PURE__*/ React.forwardRef(Icon$e);
127
149
  var IconArrowUpArrowDownLine_default = IconArrowUpArrowDownLine;
128
150
 
129
151
  // src/IconChevronDownLine.tsx
130
- var Icon$c = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
152
+ var Icon$d = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
131
153
  viewBox: "0 0 24 24",
132
154
  fill: "none",
133
155
  xmlns: "http://www.w3.org/2000/svg",
@@ -145,11 +167,11 @@ var Icon$c = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg
145
167
  })
146
168
  })
147
169
  });
148
- var IconChevronDownLine = /*#__PURE__*/ React.forwardRef(Icon$c);
170
+ var IconChevronDownLine = /*#__PURE__*/ React.forwardRef(Icon$d);
149
171
  var IconChevronDownLine_default = IconChevronDownLine;
150
172
 
151
173
  // src/IconChevronUpLine.tsx
152
- var Icon$b = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
174
+ var Icon$c = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
153
175
  viewBox: "0 0 24 24",
154
176
  fill: "none",
155
177
  xmlns: "http://www.w3.org/2000/svg",
@@ -167,11 +189,11 @@ var Icon$b = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg
167
189
  })
168
190
  })
169
191
  });
170
- var IconChevronUpLine = /*#__PURE__*/ React.forwardRef(Icon$b);
192
+ var IconChevronUpLine = /*#__PURE__*/ React.forwardRef(Icon$c);
171
193
  var IconChevronUpLine_default = IconChevronUpLine;
172
194
 
173
195
  // src/IconDot3HorizontalLine.tsx
174
- var Icon$a = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
196
+ var Icon$b = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
175
197
  viewBox: "0 0 24 24",
176
198
  fill: "none",
177
199
  xmlns: "http://www.w3.org/2000/svg",
@@ -199,9 +221,37 @@ var Icon$a = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg
199
221
  })
200
222
  })
201
223
  });
202
- var IconDot3HorizontalLine = /*#__PURE__*/ React.forwardRef(Icon$a);
224
+ var IconDot3HorizontalLine = /*#__PURE__*/ React.forwardRef(Icon$b);
203
225
  var IconDot3HorizontalLine_default = IconDot3HorizontalLine;
204
226
 
227
+ // src/IconEyeLine.tsx
228
+ var Icon$a = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
229
+ viewBox: "0 0 24 24",
230
+ fill: "none",
231
+ xmlns: "http://www.w3.org/2000/svg",
232
+ "data-seed-icon": "true",
233
+ width: size,
234
+ height: size,
235
+ ref,
236
+ ...props,
237
+ children: /* @__PURE__ */ jsxRuntime.jsx("g", {
238
+ children: /* @__PURE__ */ jsxRuntime.jsxs("g", {
239
+ children: [
240
+ /* @__PURE__ */ jsxRuntime.jsx("path", {
241
+ 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",
242
+ fill: "currentColor"
243
+ }),
244
+ /* @__PURE__ */ jsxRuntime.jsx("path", {
245
+ 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",
246
+ fill: "currentColor"
247
+ })
248
+ ]
249
+ })
250
+ })
251
+ });
252
+ var IconEyeLine = /*#__PURE__*/ React.forwardRef(Icon$a);
253
+ var IconEyeLine_default = IconEyeLine;
254
+
205
255
  // src/IconMagnifyingglassLine.tsx
206
256
  var Icon$9 = ({ size = 24, ...props }, ref)=>/* @__PURE__ */ jsxRuntime.jsx("svg", {
207
257
  viewBox: "0 0 24 24",
@@ -878,18 +928,33 @@ function useDataTableColumnCalc(props) {
878
928
  return next;
879
929
  }
880
930
  /**
881
- * Drag-to-reorder: removes `dragKey` from `order` and reinserts it immediately before
882
- * `dropKey`'s CURRENT position (i.e. its position after the removal, so dropping a
883
- * column just after its own old slot doesn't appear to do nothing). A no-op (an
884
- * equal-valued copy) when either key is missing or they're the same key.
931
+ * Drag-to-reorder: moves `dragKey` to `dropKey`'s own ORIGINAL index (the standard
932
+ * `arrayMove` two-splice shape -- remove `dragKey`, then reinsert it at `dropKey`'s
933
+ * pre-removal index of the now-shorter array), the same semantics dnd-kit's own
934
+ * `arrayMove` uses. A no-op (an equal-valued copy) when either key is missing or
935
+ * they're the same key.
936
+ *
937
+ * An EARLIER version of this function instead reinserted `dragKey` immediately before
938
+ * `dropKey`'s post-removal position. That reads the same for a multi-column jump, but
939
+ * is a silent no-op for the single most common drag gesture there is: dragging a
940
+ * column onto its own immediate RIGHT neighbor. Concretely, for `["a","b"]`, dragging
941
+ * "a" onto "b": removing "a" leaves `["b"]`, and "immediately before b" is index 0 --
942
+ * exactly where "a" already was, so nothing moved even though a real drag-and-drop
943
+ * gesture happened (caught by `DataTable.columns.test.tsx`'s own end-to-end drag test,
944
+ * which fires a real `dragover` DOM event and asserts the header order actually
945
+ * changed -- it didn't). This version's two-splice shape lands the dragged column at
946
+ * the target's own original slot instead, which swaps immediate neighbors correctly in
947
+ * both directions and still matches the old multi-jump behavior for a LEFTWARD drag
948
+ * (only a RIGHTWARD multi-column jump now lands one slot further, after the drop
949
+ * target instead of before it -- see this file's own test for both directions).
885
950
  */ function reorderColumnKey(order, dragKey, dropKey) {
886
951
  if (dragKey === dropKey || !order.includes(dragKey) || !order.includes(dropKey)) {
887
952
  return [
888
953
  ...order
889
954
  ];
890
955
  }
956
+ const dropIndex = order.indexOf(dropKey);
891
957
  const withoutDrag = order.filter((key)=>key !== dragKey);
892
- const dropIndex = withoutDrag.indexOf(dropKey);
893
958
  return [
894
959
  ...withoutDrag.slice(0, dropIndex),
895
960
  dragKey,
@@ -901,6 +966,24 @@ function useDataTableColumnCalc(props) {
901
966
  * nor balloon past a sane cap from one fast mouse move). */ function clampColumnWidth(width, min = 80, max = 640) {
902
967
  return Math.min(max, Math.max(min, width));
903
968
  }
969
+ /**
970
+ * Reconciles a persisted/controlled PINNED set against the table's current column
971
+ * KEYS -- the same drop-what's-gone rule `reconcileColumnOrder` already applies to
972
+ * `columnOrder`, but pins never need the "append what's new" half of that: an unpinned
973
+ * column simply isn't in the set, appending it here would silently pin every brand-new
974
+ * column by accident. A key no longer in `keys` (hidden isn't "gone" -- only removed
975
+ * from `columns` entirely) is dropped; everything else keeps its order.
976
+ */ function reconcilePinnedColumns(pinned, keys) {
977
+ const keySet = new Set(keys);
978
+ return pinned.filter((key)=>keySet.has(key));
979
+ }
980
+ /** Pin/unpin: adds `key` if absent, removes it if present -- column-menu.tsx's own
981
+ * "Pin column"/"Unpin column" toggle is one call of this, the same shape
982
+ * `toggleMembership` already gives row selection. Kept as its own named function
983
+ * (rather than reusing `toggleMembership` directly) so a pin-specific doc comment and
984
+ * call sites aren't reading a generically-named helper for a column-specific concern. */ function togglePinnedColumn(pinned, key) {
985
+ return toggleMembership(pinned, key);
986
+ }
904
987
  /**
905
988
  * Infinite scroll's own gate: fire `onLoadMore` only when the sentinel is ACTUALLY
906
989
  * intersecting (not e.g. an observer's initial `false` callback, which fires once on
@@ -914,19 +997,90 @@ function useDataTableColumnCalc(props) {
914
997
  */ function shouldTriggerLoadMore(isIntersecting, hasMore, loadingMore) {
915
998
  return hasMore && !loadingMore;
916
999
  }
1000
+ function isPlainObject(value) {
1001
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1002
+ }
1003
+ /** Structural validation for ONE parsed view -- every field of `DataTableViewState` is
1004
+ * optional, so this only rejects a field that's actually PRESENT but the wrong shape
1005
+ * (a consumer's storage from a future/older version of this shape), not a field that's
1006
+ * simply missing. */ function isValidDataTableView(value) {
1007
+ if (!isPlainObject(value)) return false;
1008
+ if (typeof value["id"] !== "string" || typeof value["name"] !== "string") return false;
1009
+ if (!isPlainObject(value["state"])) return false;
1010
+ const state = value["state"];
1011
+ if (state["columnOrder"] !== undefined && !isStringArray(state["columnOrder"])) return false;
1012
+ if (state["hiddenColumnKeys"] !== undefined && !isStringArray(state["hiddenColumnKeys"])) return false;
1013
+ if (state["pinnedColumnKeys"] !== undefined && !isStringArray(state["pinnedColumnKeys"])) return false;
1014
+ if (state["columnWidths"] !== undefined && !isPlainObject(state["columnWidths"])) return false;
1015
+ if (state["toolbarSorts"] !== undefined && !Array.isArray(state["toolbarSorts"])) return false;
1016
+ if (state["toolbarFilters"] !== undefined && !Array.isArray(state["toolbarFilters"])) return false;
1017
+ return true;
1018
+ }
1019
+ function isStringArray(value) {
1020
+ return Array.isArray(value) && value.every((entry)=>typeof entry === "string");
1021
+ }
1022
+ /** JSON-serializes a saved-views list for the default localStorage store -- pure so it
1023
+ * can be unit- and mutation-tested without touching `window.localStorage` at all (the
1024
+ * hook's own effect, `useDataTableViews.ts`, is the only thing that actually touches
1025
+ * storage; this is just the byte-for-byte shape it writes/reads). */ function serializeDataTableViews(views) {
1026
+ return JSON.stringify(views);
1027
+ }
1028
+ /**
1029
+ * Parses a saved-views blob back into a `DataTableView[]`, defensively: malformed JSON,
1030
+ * a non-array root, or any single malformed entry drops just that problem (an empty
1031
+ * list, or that one entry) rather than throwing -- a consumer's localStorage can hold a
1032
+ * PRIOR version's shape after this ships a new field, and one bad/stale entry shouldn't
1033
+ * cost every other saved view.
1034
+ */ function deserializeDataTableViews(raw) {
1035
+ if (!raw) return [];
1036
+ let parsed;
1037
+ try {
1038
+ parsed = JSON.parse(raw);
1039
+ } catch {
1040
+ return [];
1041
+ }
1042
+ if (!Array.isArray(parsed)) return [];
1043
+ return parsed.filter(isValidDataTableView);
1044
+ }
1045
+ /** Inserts `view` (by `id`), or replaces the existing entry with the same `id` in
1046
+ * place -- "Save" (new view) and "update the currently loaded view" are both one call
1047
+ * of this, matching `moveColumnKey`/`reorderColumnKey`'s own "one pure op per user
1048
+ * gesture" shape. */ function upsertDataTableView(views, view) {
1049
+ const index = views.findIndex((existing)=>existing.id === view.id);
1050
+ if (index === -1) return [
1051
+ ...views,
1052
+ view
1053
+ ];
1054
+ const next = [
1055
+ ...views
1056
+ ];
1057
+ next[index] = view;
1058
+ return next;
1059
+ }
1060
+ /** Renames the view with this `id` -- a no-op (an equal-valued copy) if no view has
1061
+ * that id. */ function renameDataTableView(views, id, name) {
1062
+ return views.map((view)=>view.id === id ? {
1063
+ ...view,
1064
+ name
1065
+ } : view);
1066
+ }
1067
+ /** Removes the view with this `id`. */ function removeDataTableView(views, id) {
1068
+ return views.filter((view)=>view.id !== id);
1069
+ }
917
1070
  const EMPTY_STRINGS = [];
918
1071
  const EMPTY_RECORD = {};
919
1072
  /**
920
1073
  * Owns everything DATATABLE-ATTIO-SPEC.md's column menu + reorder + resize tranche
921
- * needs -- order, visibility, a per-column label override, and a per-column width --
922
- * the way useDataTableSelection owns the one selected-id SET rather than one hook per
923
- * row. All four are "one value per column key" maps/lists a consumer may want to
924
- * persist (a saved view), so they share this hook instead of splitting into four
925
- * separate ones; drag-to-reorder and drag-to-resize (below) are the two INTERACTIONS
926
- * built on top of the order/width state this hook already owns, not independent state
1074
+ * needs -- order, visibility, a per-column label override, a per-column width, and
1075
+ * (Attio's "Pin column") a per-column left-pinned flag -- the way useDataTableSelection
1076
+ * owns the one selected-id SET rather than one hook per row. All five are "one value
1077
+ * per column key" maps/lists/sets a consumer may want to persist (a saved view), so
1078
+ * they share this hook instead of splitting into five separate ones; drag-to-reorder
1079
+ * and drag-to-resize (below) are the two INTERACTIONS built on top of the order/width
1080
+ * state this hook already owns, not independent state
927
1081
  * of their own.
928
1082
  */ function useDataTableColumns(props) {
929
- 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;
1083
+ 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;
930
1084
  const [rawOrder, setRawOrder] = useControllableState$1({
931
1085
  prop: columnOrderProp,
932
1086
  defaultProp: defaultColumnOrder ?? columnKeys,
@@ -963,6 +1117,36 @@ const EMPTY_RECORD = {};
963
1117
  columnOrder,
964
1118
  hiddenSet
965
1119
  ]);
1120
+ const [rawPinnedColumnKeys, setRawPinnedColumnKeys] = useControllableState$1({
1121
+ prop: pinnedProp,
1122
+ defaultProp: defaultPinnedColumnKeys,
1123
+ onChange: onPinnedColumnKeysChange
1124
+ });
1125
+ // Reconciled against `columnKeys` every render, the same way `columnOrder` is above --
1126
+ // a controlled `pinnedColumnKeys` a consumer persisted (e.g. a saved view) before a
1127
+ // column was removed from `columns` must not keep pinning a ghost key.
1128
+ const pinnedColumnKeys = React.useMemo(()=>reconcilePinnedColumns(rawPinnedColumnKeys ?? EMPTY_STRINGS, columnKeys), [
1129
+ rawPinnedColumnKeys,
1130
+ columnKeys
1131
+ ]);
1132
+ const pinnedSet = React.useMemo(()=>new Set(pinnedColumnKeys), [
1133
+ pinnedColumnKeys
1134
+ ]);
1135
+ const isColumnPinned = React.useCallback((key)=>pinnedSet.has(key), [
1136
+ pinnedSet
1137
+ ]);
1138
+ const pinColumn = React.useCallback((key)=>setRawPinnedColumnKeys((current = EMPTY_STRINGS)=>current.includes(key) ? current : [
1139
+ ...current,
1140
+ key
1141
+ ]), [
1142
+ setRawPinnedColumnKeys
1143
+ ]);
1144
+ const unpinColumn = React.useCallback((key)=>setRawPinnedColumnKeys((current = EMPTY_STRINGS)=>current.filter((existing)=>existing !== key)), [
1145
+ setRawPinnedColumnKeys
1146
+ ]);
1147
+ const togglePinColumn = React.useCallback((key)=>setRawPinnedColumnKeys((current = EMPTY_STRINGS)=>togglePinnedColumn(current, key)), [
1148
+ setRawPinnedColumnKeys
1149
+ ]);
966
1150
  const isColumnHidden = React.useCallback((key)=>hiddenSet.has(key), [
967
1151
  hiddenSet
968
1152
  ]);
@@ -1007,22 +1191,30 @@ const EMPTY_RECORD = {};
1007
1191
  columnKeys
1008
1192
  ]);
1009
1193
  // -- drag-to-reorder ---------------------------------------------------------------
1010
- // Live state only (which column is currently being dragged) -- the styled layer
1011
- // drives it by calling `dragOverColumn` as the pointer crosses OTHER header cells
1012
- // (via `document.elementFromPoint`, since a captured pointer stops native
1013
- // `pointerenter` from firing on siblings), which reorders immediately rather than
1014
- // waiting for a drop. That is exactly what Attio's own header drag does (the column
1015
- // being passed visibly swaps live), and it means `endColumnDrag` never has to also
1016
- // commit a move -- there is nothing left to commit.
1194
+ // Live state only (which column is currently being dragged) -- the styled layer's
1195
+ // header cells are natively `draggable`, so `dragOverColumn` is driven straight off
1196
+ // each cell's own `onDragOver` (one real browser event per column the pointer
1197
+ // crosses), which reorders immediately rather than waiting for a drop. That is
1198
+ // exactly what Attio's own header drag does (the column being passed visibly swaps
1199
+ // live), and it means `endColumnDrag` never has to also commit a move -- there is
1200
+ // nothing left to commit.
1017
1201
  const [draggingColumnKey, setDraggingColumnKey] = React.useState(null);
1018
1202
  const beginColumnDrag = React.useCallback((key)=>setDraggingColumnKey(key), []);
1203
+ // Reads `draggingColumnKey` straight from this render's own closure rather than via
1204
+ // `setDraggingColumnKey`'s functional-updater form (an earlier version of this hook
1205
+ // nested the `reorderColumn` call inside that updater, to read a "live" value --
1206
+ // `draggingColumnKey` never actually CHANGES during a drag, so that state update was
1207
+ // pure ceremony, and nesting one hook's setState inside another's updater callback is
1208
+ // exactly what silently dropped the reorder in DataTable.columns.test.tsx's own
1209
+ // end-to-end drag test: a REAL `dragover` DOM event fired, `dragOverColumn` fired with
1210
+ // the right key, but `columnOrder` never actually moved). Each `onDragOver` is its own
1211
+ // discrete browser event (not a tight synchronous loop within one render), so a plain
1212
+ // closure read is exactly as live as the updater trick was trying to be.
1019
1213
  const dragOverColumn = React.useCallback((hoverKey)=>{
1020
- setDraggingColumnKey((current)=>{
1021
- if (!current || current === hoverKey) return current;
1022
- reorderColumn(current, hoverKey);
1023
- return current;
1024
- });
1214
+ if (!draggingColumnKey || draggingColumnKey === hoverKey) return;
1215
+ reorderColumn(draggingColumnKey, hoverKey);
1025
1216
  }, [
1217
+ draggingColumnKey,
1026
1218
  reorderColumn
1027
1219
  ]);
1028
1220
  const endColumnDrag = React.useCallback(()=>setDraggingColumnKey(null), []);
@@ -1058,10 +1250,15 @@ const EMPTY_RECORD = {};
1058
1250
  hiddenColumnKeys,
1059
1251
  columnWidths,
1060
1252
  columnLabels,
1253
+ pinnedColumnKeys,
1061
1254
  isColumnHidden,
1062
1255
  hideColumn,
1063
1256
  showColumn,
1064
1257
  toggleColumnVisibility,
1258
+ isColumnPinned,
1259
+ pinColumn,
1260
+ unpinColumn,
1261
+ togglePinColumn,
1065
1262
  getColumnLabel,
1066
1263
  renameColumn,
1067
1264
  getColumnWidth,
@@ -1710,7 +1907,7 @@ function useDataTableRowContext({ strict = true } = {}) {
1710
1907
  return context;
1711
1908
  }
1712
1909
  const DataTableRoot = /*#__PURE__*/ React.forwardRef((props, ref)=>{
1713
- 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;
1910
+ 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;
1714
1911
  const api = useDataTable({
1715
1912
  sort,
1716
1913
  defaultSort,
@@ -1742,6 +1939,9 @@ const DataTableRoot = /*#__PURE__*/ React.forwardRef((props, ref)=>{
1742
1939
  columnLabels,
1743
1940
  defaultColumnLabels,
1744
1941
  onColumnLabelsChange,
1942
+ pinnedColumnKeys,
1943
+ defaultPinnedColumnKeys,
1944
+ onPinnedColumnKeysChange,
1745
1945
  columnCalcOps,
1746
1946
  defaultColumnCalcOps,
1747
1947
  onColumnCalcOpsChange,
@@ -1829,6 +2029,132 @@ const DataTableCell$1 = /*#__PURE__*/ React.forwardRef((props, ref)=>{
1829
2029
  });
1830
2030
  DataTableCell$1.displayName = "DataTableCell";
1831
2031
 
2032
+ const EMPTY_VIEWS = [];
2033
+ function readStoredViews(storageKey) {
2034
+ if (!storageKey || typeof window === "undefined") return EMPTY_VIEWS;
2035
+ try {
2036
+ return deserializeDataTableViews(window.localStorage.getItem(storageKey));
2037
+ } catch {
2038
+ // A private-browsing tab / blocked storage throws on access, not just on quota --
2039
+ // this hook degrades to in-memory-only rather than crash the table over it.
2040
+ return EMPTY_VIEWS;
2041
+ }
2042
+ }
2043
+ /** A reasonably unique id for a newly created view -- `crypto.randomUUID` where it
2044
+ * exists (every real browser + modern Node), a plain timestamp+random fallback
2045
+ * otherwise (older jsdom/test environments) so this hook never throws just because a
2046
+ * test runner's `crypto` is a stub. */ function generateViewId() {
2047
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
2048
+ return crypto.randomUUID();
2049
+ }
2050
+ return `view-${Date.now()}-${Math.random().toString(36).slice(2)}`;
2051
+ }
2052
+ /**
2053
+ * Owns the saved-views LIST (create/rename/delete/select) and its default persistence
2054
+ * (localStorage, pluggable away by controlling `views`/`onViewsChange` instead) -- the
2055
+ * same controllable shape every other DataTable state hook already uses
2056
+ * (`useDataTableColumns`, `useDataTableToolbarSort`, ...). Read `DataTableViewsControl`
2057
+ * (`views.tsx`, the styled layer) for how a consumer wires `captureState`/`applyState`
2058
+ * around this to actually save/restore column + sort + filter state.
2059
+ */ function useDataTableViews(props) {
2060
+ const { views: viewsProp, defaultViews = EMPTY_VIEWS, onViewsChange, activeViewId: activeViewIdProp, defaultActiveViewId = null, onActiveViewIdChange, storageKey } = props;
2061
+ // Lazy, ONE-TIME read of localStorage as this render's default -- re-reading it on
2062
+ // every render (rather than a lazy ref) would clobber whatever the user just did in
2063
+ // THIS tab with whatever another tab most recently wrote. Only fires at all when this
2064
+ // hook truly owns persistence: `views` is uncontrolled AND a `storageKey` was given.
2065
+ const initialViewsRef = React.useRef(null);
2066
+ if (initialViewsRef.current === null) {
2067
+ if (viewsProp !== undefined) {
2068
+ initialViewsRef.current = defaultViews;
2069
+ } else {
2070
+ const stored = readStoredViews(storageKey);
2071
+ // Nothing in storage yet (first run, or no `storageKey` at all) -- seed from
2072
+ // `defaultViews` instead of an empty list, matching every other hook's own
2073
+ // `defaultProp` semantics.
2074
+ initialViewsRef.current = stored.length > 0 ? stored : defaultViews;
2075
+ }
2076
+ }
2077
+ const [views = EMPTY_VIEWS, setViews] = useControllableState$1({
2078
+ prop: viewsProp,
2079
+ defaultProp: initialViewsRef.current,
2080
+ onChange: onViewsChange
2081
+ });
2082
+ // Persists every change back to `storageKey` -- same "only when this hook owns
2083
+ // persistence" gate as the lazy read above. Skips the FIRST render (the effect would
2084
+ // otherwise immediately re-write back the exact bytes it just read, or stomp an
2085
+ // empty default over a controlled consumer's storage before it ever mounts).
2086
+ const skipFirstPersistRef = React.useRef(true);
2087
+ React.useEffect(()=>{
2088
+ if (viewsProp !== undefined || !storageKey || typeof window === "undefined") return;
2089
+ if (skipFirstPersistRef.current) {
2090
+ skipFirstPersistRef.current = false;
2091
+ return;
2092
+ }
2093
+ try {
2094
+ window.localStorage.setItem(storageKey, serializeDataTableViews(views));
2095
+ } catch {
2096
+ // Storage full/blocked -- the view still exists in memory for this session.
2097
+ }
2098
+ }, [
2099
+ views,
2100
+ viewsProp,
2101
+ storageKey
2102
+ ]);
2103
+ const [activeViewId = null, setActiveViewId] = useControllableState$1({
2104
+ prop: activeViewIdProp,
2105
+ defaultProp: defaultActiveViewId,
2106
+ onChange: onActiveViewIdChange
2107
+ });
2108
+ const activeView = views.find((view)=>view.id === activeViewId) ?? null;
2109
+ const createView = React.useCallback((name, state)=>{
2110
+ const id = generateViewId();
2111
+ setViews((current = EMPTY_VIEWS)=>upsertDataTableView(current, {
2112
+ id,
2113
+ name,
2114
+ state
2115
+ }));
2116
+ setActiveViewId(id);
2117
+ return id;
2118
+ }, [
2119
+ setViews,
2120
+ setActiveViewId
2121
+ ]);
2122
+ const updateView = React.useCallback((id, state)=>{
2123
+ setViews((current = EMPTY_VIEWS)=>{
2124
+ const existing = current.find((view)=>view.id === id);
2125
+ return existing ? upsertDataTableView(current, {
2126
+ ...existing,
2127
+ state
2128
+ }) : current;
2129
+ });
2130
+ }, [
2131
+ setViews
2132
+ ]);
2133
+ const renameView = React.useCallback((id, name)=>setViews((current = EMPTY_VIEWS)=>renameDataTableView(current, id, name)), [
2134
+ setViews
2135
+ ]);
2136
+ const deleteView = React.useCallback((id)=>{
2137
+ setViews((current = EMPTY_VIEWS)=>removeDataTableView(current, id));
2138
+ setActiveViewId((current)=>current === id ? null : current);
2139
+ }, [
2140
+ setViews,
2141
+ setActiveViewId
2142
+ ]);
2143
+ const selectView = React.useCallback((id)=>setActiveViewId(id), [
2144
+ setActiveViewId
2145
+ ]);
2146
+ return {
2147
+ views,
2148
+ activeViewId,
2149
+ activeView,
2150
+ createView,
2151
+ updateView,
2152
+ renameView,
2153
+ deleteView,
2154
+ selectView
2155
+ };
2156
+ }
2157
+
1832
2158
  function r(e) {
1833
2159
  var t, f, n = "";
1834
2160
  if ("string" == typeof e || "number" == typeof e) n += e;
@@ -2227,7 +2553,7 @@ function formatDateTimeCell(value, locale) {
2227
2553
  minute: "2-digit"
2228
2554
  }).format(date);
2229
2555
  }
2230
- function EntityCell({ value, className, nameClassName }) {
2556
+ function EntityCell({ value, className, nameClassName, actionsClassName, actionClassName, column, row, openPreviewLabel }) {
2231
2557
  const entity = typeof value === "object" && value !== null ? value : {
2232
2558
  name: String(value ?? "")
2233
2559
  };
@@ -2250,6 +2576,21 @@ function EntityCell({ value, className, nameClassName }) {
2250
2576
  /*#__PURE__*/ jsxRuntime.jsx("span", {
2251
2577
  className: nameClassName,
2252
2578
  children: entity.name
2579
+ }),
2580
+ column?.onOpenPreview && row !== undefined && /*#__PURE__*/ jsxRuntime.jsx("span", {
2581
+ className: actionsClassName,
2582
+ children: /*#__PURE__*/ jsxRuntime.jsx("button", {
2583
+ type: "button",
2584
+ className: actionClassName,
2585
+ "aria-label": openPreviewLabel ?? "Open preview",
2586
+ onClick: (event)=>{
2587
+ event.stopPropagation();
2588
+ column.onOpenPreview?.(row);
2589
+ },
2590
+ children: /*#__PURE__*/ jsxRuntime.jsx(IconEyeLine_default, {
2591
+ size: 16
2592
+ })
2593
+ })
2253
2594
  })
2254
2595
  ]
2255
2596
  });
@@ -2354,76 +2695,121 @@ function RatingCell({ value, maxRating = 5 }) {
2354
2695
  });
2355
2696
  }
2356
2697
 
2357
- /** The subset of `useDataTableContext()` every "resolve which columns to actually
2358
- * render, in what order, under what label/width" helper below needs -- narrowed so
2359
- * each helper's own signature documents exactly what it reads, rather than the whole
2360
- * table API. */ function useEffectiveColumns(columns) {
2361
- const { visibleColumnOrder, getColumnLabel, getColumnWidth } = useDataTableContext();
2698
+ /** Fallback width (px) used to compute a pinned column's cumulative sticky offset when
2699
+ * it has no explicit `width` and hasn't been drag-resized -- pinning needs a STATIC
2700
+ * number to put in an inline `insetInlineStart`, and `table-layout: fixed` only
2701
+ * decides how an unset column's share of the leftover width actually renders at paint
2702
+ * time (something no amount of JS math here can know ahead of it). Matches
2703
+ * `clampColumnWidth`'s own floor (react-headless's `dom.ts`) -- a real pinned column
2704
+ * narrower than this only needs its offset "wide enough not to overlap", not exact. */ const DEFAULT_PINNED_COLUMN_WIDTH = 180;
2705
+ /**
2706
+ * Every column this table actually renders, in RENDER order: any pinned columns first
2707
+ * (their own relative order preserved from `visibleColumnOrder`, not a separate pin-
2708
+ * order of their own), then everything else in normal order -- resolved label/width,
2709
+ * and this file's own sticky-left bookkeeping (`pinned`/`pinOffset`/`pinnedEdge`). Read
2710
+ * by the header, the body, the ColumnCalc footer AND the `<colgroup>` alike -- all four
2711
+ * must agree on this exact order, since a `<colgroup>`'s `<col>`s are matched
2712
+ * POSITIONALLY to every row's cells; splitting "order" (here) from "which one is
2713
+ * pinned" into two independently-ordered helpers would let a `<colgroup>` built from
2714
+ * one and a header row built from the other drift out of sync under `table-layout:
2715
+ * fixed`'s own column-to-cell matching.
2716
+ */ function useEffectiveColumns(columns, options) {
2717
+ const { visibleColumnOrder, getColumnLabel, getColumnWidth, pinnedColumnKeys } = useDataTableContext();
2718
+ const { selectable, stickyFirst } = options;
2362
2719
  return React__namespace.useMemo(()=>{
2363
2720
  const byKey = new Map(columns.map((column)=>[
2364
2721
  column.key,
2365
2722
  column
2366
2723
  ]));
2367
- return visibleColumnOrder.map((key)=>byKey.get(key)).filter((column)=>Boolean(column)).map((column)=>({
2724
+ const visibleKeySet = new Set(visibleColumnOrder);
2725
+ const explicitPins = new Set((pinnedColumnKeys ?? []).filter((key)=>byKey.has(key) && visibleKeySet.has(key)));
2726
+ // Legacy fallback (DataTable.columns.test.tsx's own `stickyFirst` tests, predating
2727
+ // per-column pin): no EXPLICIT pin at all, `stickyFirst` pins exactly the first
2728
+ // visible column -- the single-column behavior this file now generalizes to a
2729
+ // whole pinned GROUP.
2730
+ const pinnedSet = explicitPins.size > 0 ? explicitPins : stickyFirst && visibleColumnOrder.length > 0 ? new Set([
2731
+ visibleColumnOrder[0]
2732
+ ]) : explicitPins;
2733
+ // Stable partition: pinned columns first (their relative order among THEMSELVES
2734
+ // preserved from `visibleColumnOrder`), then every other column, also in its
2735
+ // existing relative order. `Array.prototype.sort` is spec-stable (ES2019+).
2736
+ const ordered = [
2737
+ ...visibleColumnOrder
2738
+ ].sort((a, b)=>{
2739
+ const aPinned = pinnedSet.has(a) ? 0 : 1;
2740
+ const bPinned = pinnedSet.has(b) ? 0 : 1;
2741
+ return aPinned - bPinned;
2742
+ });
2743
+ let cursor = selectable ? 40 : 0;
2744
+ let pinnedCount = 0;
2745
+ const entries = ordered.map((key)=>byKey.get(key)).filter((column)=>Boolean(column)).map((column)=>{
2746
+ const width = getColumnWidth(column.key) ?? column.width;
2747
+ const pinned = pinnedSet.has(column.key);
2748
+ const pinOffset = pinned ? cursor : 0;
2749
+ if (pinned) {
2750
+ cursor += width ?? DEFAULT_PINNED_COLUMN_WIDTH;
2751
+ pinnedCount += 1;
2752
+ }
2753
+ return {
2368
2754
  column,
2369
2755
  label: getColumnLabel(column.key, column.header),
2370
- width: getColumnWidth(column.key) ?? column.width
2371
- }));
2756
+ width,
2757
+ pinned,
2758
+ pinOffset,
2759
+ pinnedEdge: false
2760
+ };
2761
+ });
2762
+ if (pinnedCount > 0) entries[pinnedCount - 1].pinnedEdge = true;
2763
+ return entries;
2372
2764
  }, [
2373
2765
  columns,
2374
2766
  visibleColumnOrder,
2375
2767
  getColumnLabel,
2376
- getColumnWidth
2377
- ]);
2378
- }
2379
- /** Sticky positioning for the leading/trailing visible cell of a row (header, body, or
2380
- * footer) -- `stickyFirst` pins the SELECTION cell when the table has one, plus the
2381
- * first data column; `stickyLast` always pins the last VISIBLE data column. Only the
2382
- * OUTERMOST sticky cell on each side gets `data-sticky-edge(-end)` -- that's the one
2383
- * whose shadow should reveal on scroll, not every sticky cell.
2384
- *
2385
- * When both a selection column and a sticky first data column are present, the edge
2386
- * is the data column (e.g. Company), not the 40px selection cell: the data column is
2387
- * ALSO `position: sticky`, sitting immediately to its right, so a shadow cast from the
2388
- * selection cell's trailing edge would render directly underneath that opaque sticky
2389
- * cell and never actually be visible. Putting `data-sticky-edge` on the trailing-most
2390
- * sticky-left cell is what makes the shadow render somewhere unobstructed -- past the
2391
- * whole pinned group, not between two members of it. */ function stickyProps(options) {
2392
- const { selectable, stickyFirst, stickyLast, isSelectionCell, isFirst, isLast } = options;
2393
- if (stickyFirst && isSelectionCell) {
2394
- // Still sticky either way. The edge marker only belongs here when there is no
2395
- // sticky first DATA column to hand it to instead (i.e. no columns at all) --
2396
- // otherwise that data column is the true trailing edge of the pinned group.
2397
- return selectable ? {
2398
- "data-sticky": "",
2399
- style: {
2400
- insetInlineStart: 0
2401
- }
2402
- } : {
2403
- "data-sticky": "",
2404
- "data-sticky-edge": "",
2405
- style: {
2406
- insetInlineStart: 0
2407
- }
2408
- };
2409
- }
2410
- if (stickyFirst && isFirst && !selectable) {
2411
- return {
2412
- "data-sticky": "",
2413
- "data-sticky-edge": "",
2414
- style: {
2415
- insetInlineStart: 0
2416
- }
2417
- };
2418
- }
2419
- if (stickyFirst && isFirst && selectable) {
2420
- // The trailing edge of the pinned group -- past the 40px selection cell, so this
2421
- // is where the scroll shadow actually renders unobstructed.
2768
+ getColumnWidth,
2769
+ pinnedColumnKeys,
2770
+ selectable,
2771
+ stickyFirst
2772
+ ]);
2773
+ }
2774
+ /** The 40px selection column's own sticky-left state -- `stickyFirst` (the table-wide
2775
+ * prop) alone undercounts "should the checkbox column stick" the moment ANY per-column
2776
+ * pin is live, controlled or not, since the live pinned SET only exists once
2777
+ * `DataTablePrimitiveRoot`'s provider has mounted (an uncontrolled consumer never
2778
+ * hands its pinned columns back up as a prop for `DataTable.tsx` to read directly).
2779
+ * Mirrors `DataTable.tsx`'s own `resolvedStickyLast = stickyLast ||
2780
+ * columns.some(actions)` widening, just resolved one level down (live STATE, not
2781
+ * static column config) -- read via context from a component under the provider, not
2782
+ * computed above it. */ function useSelectionStickyFirst(stickyFirst) {
2783
+ const { pinnedColumnKeys } = useDataTableContext();
2784
+ return stickyFirst || (pinnedColumnKeys?.length ?? 0) > 0;
2785
+ }
2786
+ /** Sticky positioning for the 40px SELECTION cell only (header/body/footer) -- data
2787
+ * columns use their own `pinned`/`pinOffset`/`pinnedEdge` (`useEffectiveColumns`,
2788
+ * above) instead, via `pinnedCellProps` below. The selection cell is always the
2789
+ * leading edge of the pinned-left group when it's sticky at all, so it never itself
2790
+ * carries `data-sticky-edge` -- the trailing-most pinned DATA column does (its own
2791
+ * `pinnedEdge`), the same split the original single-column `stickyFirst` already drew
2792
+ * between the selection cell and Company/Name. */ function selectionStickyProps(stickyFirst) {
2793
+ return stickyFirst ? {
2794
+ "data-sticky": "",
2795
+ style: {
2796
+ insetInlineStart: 0
2797
+ }
2798
+ } : {};
2799
+ }
2800
+ /** Sticky positioning for one DATA cell (header, body, or ColumnCalc footer) -- pinned-
2801
+ * left (this column's own `pinOffset`, `data-sticky-edge` only on the group's
2802
+ * trailing-most member) takes priority over sticky-right (`stickyLast`, always just
2803
+ * the last VISIBLE column, e.g. an `actions` column) since a column can only stick to
2804
+ * one edge. */ function pinnedCellProps(entry, stickyLast, isLast) {
2805
+ if (entry.pinned) {
2422
2806
  return {
2423
2807
  "data-sticky": "",
2424
- "data-sticky-edge": "",
2808
+ ...entry.pinnedEdge ? {
2809
+ "data-sticky-edge": ""
2810
+ } : {},
2425
2811
  style: {
2426
- insetInlineStart: 40
2812
+ insetInlineStart: entry.pinOffset
2427
2813
  }
2428
2814
  };
2429
2815
  }
@@ -2763,7 +3149,7 @@ const TextFieldTextarea = /*#__PURE__*/ React.forwardRef(({ className, autoresiz
2763
3149
  });
2764
3150
  TextFieldTextarea.displayName = "TextFieldTextarea";
2765
3151
 
2766
- __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))}");
3152
+ __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))}");
2767
3153
 
2768
3154
  const createClassName = (className, variants, compoundVariants = [])=>{
2769
3155
  const variantKeys = Object.keys(variants);
@@ -2858,6 +3244,14 @@ const dataTableSlotNames = [
2858
3244
  "link",
2859
3245
  "seed-data-table__link"
2860
3246
  ],
3247
+ [
3248
+ "entityActions",
3249
+ "seed-data-table__entityActions"
3250
+ ],
3251
+ [
3252
+ "entityAction",
3253
+ "seed-data-table__entityAction"
3254
+ ],
2861
3255
  [
2862
3256
  "toolbar",
2863
3257
  "seed-data-table__toolbar"
@@ -2907,11 +3301,11 @@ const dataTableSlotNames = [
2907
3301
  "seed-data-table__selectionCell"
2908
3302
  ]
2909
3303
  ];
2910
- const defaultVariant$4 = {
3304
+ const defaultVariant$6 = {
2911
3305
  "surface": "card",
2912
3306
  "interactive": false
2913
3307
  };
2914
- const compoundVariants$4 = [];
3308
+ const compoundVariants$6 = [];
2915
3309
  const dataTableVariantMap = {
2916
3310
  "surface": [
2917
3311
  "card",
@@ -2926,7 +3320,7 @@ function dataTable(props) {
2926
3320
  return Object.fromEntries(dataTableSlotNames.map(([slot, className])=>{
2927
3321
  return [
2928
3322
  slot,
2929
- createClassName(className, mergeVariants(defaultVariant$4, props), compoundVariants$4)
3323
+ createClassName(className, mergeVariants(defaultVariant$6, props), compoundVariants$6)
2930
3324
  ];
2931
3325
  }));
2932
3326
  }
@@ -3471,20 +3865,16 @@ function RatingEditor({ column, value, pending, onCommit }) {
3471
3865
  return column.editor === "switch" || column.type === "rating" || column.type === "checkbox";
3472
3866
  }
3473
3867
  function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyFirst, stickyLast }) {
3474
- const effective = useEffectiveColumns(columns);
3868
+ const effective = useEffectiveColumns(columns, {
3869
+ selectable,
3870
+ stickyFirst
3871
+ });
3475
3872
  const { startEdit } = useDataTableContext();
3476
3873
  return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
3477
- children: effective.map(({ column }, index)=>{
3478
- const isFirst = index === 0;
3874
+ children: effective.map((entry, index)=>{
3875
+ const { column } = entry;
3479
3876
  const isLast = index === effective.length - 1;
3480
- const sticky = stickyProps({
3481
- selectable,
3482
- stickyFirst,
3483
- stickyLast,
3484
- isSelectionCell: false,
3485
- isFirst,
3486
- isLast
3487
- });
3877
+ const sticky = pinnedCellProps(entry, stickyLast, isLast);
3488
3878
  // A gated `editable` column (everything except the always-live widgets)
3489
3879
  // opens on double-click -- Attio's own measured gesture (crisp's #411),
3490
3880
  // matched here rather than a single click, which stays "select this cell"
@@ -3610,7 +4000,12 @@ function DisplayCellContent({ column, row, value, classNames, locale }) {
3610
4000
  return /*#__PURE__*/ jsxRuntime.jsx(EntityCell, {
3611
4001
  value: value,
3612
4002
  className: classNames.entity,
3613
- nameClassName: classNames.entityName
4003
+ nameClassName: classNames.entityName,
4004
+ actionsClassName: classNames.entityActions,
4005
+ actionClassName: classNames.entityAction,
4006
+ column: column,
4007
+ row: row,
4008
+ openPreviewLabel: column.openPreviewLabel
3614
4009
  });
3615
4010
  case "url":
3616
4011
  case "email":
@@ -3720,19 +4115,15 @@ const MenuItemLabel = withItemContext(withItemStateProps(Primitive.span), "label
3720
4115
  withItemContext(withItemStateProps(Primitive.span), "description");
3721
4116
 
3722
4117
  function ColumnCalcCells({ columns, rows, selectable, stickyFirst, stickyLast }) {
3723
- const effective = useEffectiveColumns(columns);
4118
+ const effective = useEffectiveColumns(columns, {
4119
+ selectable,
4120
+ stickyFirst
4121
+ });
3724
4122
  return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
3725
- children: effective.map(({ column }, index)=>{
3726
- const isFirst = index === 0;
4123
+ children: effective.map((entry, index)=>{
4124
+ const { column } = entry;
3727
4125
  const isLast = index === effective.length - 1;
3728
- const sticky = stickyProps({
3729
- selectable,
3730
- stickyFirst,
3731
- stickyLast,
3732
- isSelectionCell: false,
3733
- isFirst,
3734
- isLast
3735
- });
4126
+ const sticky = pinnedCellProps(entry, stickyLast, isLast);
3736
4127
  return /*#__PURE__*/ jsxRuntime.jsx(DataTableFooterCell, {
3737
4128
  "data-sticky": sticky["data-sticky"],
3738
4129
  "data-sticky-edge": sticky["data-sticky-edge"],
@@ -3916,20 +4307,16 @@ const DEFAULT_SORT_ICON = {
3916
4307
  * `visibleColumnOrder`/labels/widths change, without also re-deriving `sortedData`'s
3917
4308
  * render above it. */ function ColumnHeaderCells({ columns, columnMenu, reorderable, resizable, sortIcon, selectable, stickyFirst, stickyLast }) {
3918
4309
  const { draggingColumnKey, beginColumnDrag, dragOverColumn, endColumnDrag } = useDataTableContext();
3919
- const effective = useEffectiveColumns(columns);
4310
+ const effective = useEffectiveColumns(columns, {
4311
+ selectable,
4312
+ stickyFirst
4313
+ });
3920
4314
  const [renamingKey, setRenamingKey] = React__namespace.useState(null);
3921
4315
  return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
3922
- children: effective.map(({ column, label, width }, index)=>{
3923
- const isFirst = index === 0;
4316
+ children: effective.map((entry, index)=>{
4317
+ const { column, label, width } = entry;
3924
4318
  const isLast = index === effective.length - 1;
3925
- const sticky = stickyProps({
3926
- selectable,
3927
- stickyFirst,
3928
- stickyLast,
3929
- isSelectionCell: false,
3930
- isFirst,
3931
- isLast
3932
- });
4319
+ const sticky = pinnedCellProps(entry, stickyLast, isLast);
3933
4320
  return /*#__PURE__*/ jsxRuntime.jsxs(DataTableHeaderCell, {
3934
4321
  columnKey: column.key,
3935
4322
  sortable: column.sortable,
@@ -4059,8 +4446,9 @@ function ColumnRenameInput({ column, initialLabel, onDone }) {
4059
4446
  * permanently, so this one carries its own marker attribute distinct from that
4060
4447
  * slot's OTHER occupants (the sort chevron, the filter trigger), which stay visible
4061
4448
  * under their own separate rules regardless of hover. */ function ColumnMenu({ column, onRename }) {
4062
- const { moveColumn, hideColumn } = useDataTableContext();
4449
+ const { moveColumn, hideColumn, isColumnPinned, togglePinColumn } = useDataTableContext();
4063
4450
  const columnLabel = typeof column.header === "string" ? column.header : column.key;
4451
+ const pinned = isColumnPinned(column.key);
4064
4452
  const stopPropagation = (event)=>event.stopPropagation();
4065
4453
  return /*#__PURE__*/ jsxRuntime.jsxs(MenuRoot, {
4066
4454
  children: [
@@ -4102,6 +4490,12 @@ function ColumnRenameInput({ column, initialLabel, onDone }) {
4102
4490
  children: "Move right"
4103
4491
  })
4104
4492
  }),
4493
+ /*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
4494
+ onClick: ()=>togglePinColumn(column.key),
4495
+ children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
4496
+ children: pinned ? "Unpin column" : "Pin column"
4497
+ })
4498
+ }),
4105
4499
  /*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
4106
4500
  onClick: ()=>hideColumn(column.key),
4107
4501
  children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
@@ -4224,12 +4618,12 @@ function ColumnRenameInput({ column, initialLabel, onDone }) {
4224
4618
 
4225
4619
  __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)}}");
4226
4620
 
4227
- const defaultVariant$3 = {
4621
+ const defaultVariant$5 = {
4228
4622
  "variant": "brandSolid",
4229
4623
  "size": "medium",
4230
4624
  "layout": "withText"
4231
4625
  };
4232
- const compoundVariants$3 = [
4626
+ const compoundVariants$5 = [
4233
4627
  {
4234
4628
  "size": "xsmall",
4235
4629
  "layout": "withText"
@@ -4285,7 +4679,7 @@ const actionButtonVariantMap = {
4285
4679
  ]
4286
4680
  };
4287
4681
  function actionButton(props) {
4288
- return createClassName("seed-action-button", mergeVariants(defaultVariant$3, props), compoundVariants$3);
4682
+ return createClassName("seed-action-button", mergeVariants(defaultVariant$5, props), compoundVariants$5);
4289
4683
  }
4290
4684
  Object.assign(actionButton, {
4291
4685
  splitVariantProps: (props)=>splitVariantProps(props, actionButtonVariantMap)
@@ -5367,10 +5761,10 @@ const datePickerSlotNames = [
5367
5761
  "seed-date-picker__liveRegion"
5368
5762
  ]
5369
5763
  ];
5370
- const defaultVariant$2 = {
5764
+ const defaultVariant$4 = {
5371
5765
  "visibleRange": "month"
5372
5766
  };
5373
- const compoundVariants$2 = [];
5767
+ const compoundVariants$4 = [];
5374
5768
  const datePickerVariantMap = {
5375
5769
  "visibleRange": [
5376
5770
  "month",
@@ -5383,7 +5777,7 @@ function datePicker(props) {
5383
5777
  return Object.fromEntries(datePickerSlotNames.map(([slot, className])=>{
5384
5778
  return [
5385
5779
  slot,
5386
- createClassName(className, mergeVariants(defaultVariant$2, props), compoundVariants$2)
5780
+ createClassName(className, mergeVariants(defaultVariant$4, props), compoundVariants$4)
5387
5781
  ];
5388
5782
  }));
5389
5783
  }
@@ -7717,14 +8111,14 @@ const wheelPickerSlotNames = [
7717
8111
  "seed-wheel-picker__selectionIndicator"
7718
8112
  ]
7719
8113
  ];
7720
- const defaultVariant$1 = {};
7721
- const compoundVariants$1 = [];
8114
+ const defaultVariant$3 = {};
8115
+ const compoundVariants$3 = [];
7722
8116
  const wheelPickerVariantMap = {};
7723
8117
  function wheelPicker(props) {
7724
8118
  return Object.fromEntries(wheelPickerSlotNames.map(([slot, className])=>{
7725
8119
  return [
7726
8120
  slot,
7727
- createClassName(className, mergeVariants(defaultVariant$1, props), compoundVariants$1)
8121
+ createClassName(className, mergeVariants(defaultVariant$3, props), compoundVariants$3)
7728
8122
  ];
7729
8123
  }));
7730
8124
  }
@@ -8506,17 +8900,17 @@ var WheelPicker_namespace = {
8506
8900
 
8507
8901
  __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}");
8508
8902
 
8509
- const defaultVariant = {
8903
+ const defaultVariant$2 = {
8510
8904
  "hideScrollBar": false
8511
8905
  };
8512
- const compoundVariants = [];
8906
+ const compoundVariants$2 = [];
8513
8907
  const scrollFogVariantMap = {
8514
8908
  "hideScrollBar": [
8515
8909
  true
8516
8910
  ]
8517
8911
  };
8518
8912
  function scrollFog(props) {
8519
- return createClassName("seed-scroll-fog", mergeVariants(defaultVariant, props), compoundVariants);
8913
+ return createClassName("seed-scroll-fog", mergeVariants(defaultVariant$2, props), compoundVariants$2);
8520
8914
  }
8521
8915
  Object.assign(scrollFog, {
8522
8916
  splitVariantProps: (props)=>splitVariantProps(props, scrollFogVariantMap)
@@ -9322,7 +9716,7 @@ const fromDatePickerDate = (d)=>new Date(d.year, d.month - 1, d.day);
9322
9716
  "aria-label": "Move sort up",
9323
9717
  disabled: index === 0,
9324
9718
  onClick: ()=>moveToolbarSort(index, index - 1),
9325
- style: iconButtonStyle,
9719
+ style: iconButtonStyle$1,
9326
9720
  children: /*#__PURE__*/ jsxRuntime.jsx(IconArrowUpLine_default, {
9327
9721
  size: 13,
9328
9722
  strokeWidth: 1.75
@@ -9333,7 +9727,7 @@ const fromDatePickerDate = (d)=>new Date(d.year, d.month - 1, d.day);
9333
9727
  "aria-label": "Move sort down",
9334
9728
  disabled: index === toolbarSorts.length - 1,
9335
9729
  onClick: ()=>moveToolbarSort(index, index + 1),
9336
- style: iconButtonStyle,
9730
+ style: iconButtonStyle$1,
9337
9731
  children: /*#__PURE__*/ jsxRuntime.jsx(IconArrowDownLine_default, {
9338
9732
  size: 13,
9339
9733
  strokeWidth: 1.75
@@ -9343,7 +9737,7 @@ const fromDatePickerDate = (d)=>new Date(d.year, d.month - 1, d.day);
9343
9737
  type: "button",
9344
9738
  "aria-label": "Remove sort",
9345
9739
  onClick: ()=>removeToolbarSort(index),
9346
- style: iconButtonStyle,
9740
+ style: iconButtonStyle$1,
9347
9741
  children: /*#__PURE__*/ jsxRuntime.jsx(IconXmarkLine_default, {
9348
9742
  size: 13,
9349
9743
  strokeWidth: 1.75
@@ -9358,7 +9752,7 @@ const fromDatePickerDate = (d)=>new Date(d.year, d.month - 1, d.day);
9358
9752
  disabled: availableColumns.length === 0,
9359
9753
  onClick: ()=>availableColumns[0] && addToolbarSort(availableColumns[0].key),
9360
9754
  style: {
9361
- ...iconButtonStyle,
9755
+ ...iconButtonStyle$1,
9362
9756
  width: "auto",
9363
9757
  gap: 6,
9364
9758
  padding: "6px 8px",
@@ -9380,7 +9774,7 @@ const fromDatePickerDate = (d)=>new Date(d.year, d.month - 1, d.day);
9380
9774
  ]
9381
9775
  });
9382
9776
  }
9383
- const iconButtonStyle = {
9777
+ const iconButtonStyle$1 = {
9384
9778
  display: "inline-flex",
9385
9779
  alignItems: "center",
9386
9780
  justifyContent: "center",
@@ -9478,7 +9872,7 @@ const formatFilterDate = (iso)=>{
9478
9872
  type: "button",
9479
9873
  "aria-label": `Remove ${column ? columnLabel(column) : filter.key} filter`,
9480
9874
  onClick: ()=>removeToolbarFilter(filter.id),
9481
- style: iconButtonStyle,
9875
+ style: iconButtonStyle$1,
9482
9876
  children: /*#__PURE__*/ jsxRuntime.jsx(IconXmarkLine_default, {
9483
9877
  size: 12,
9484
9878
  strokeWidth: 1.75
@@ -9735,7 +10129,7 @@ const formatFilterDate = (iso)=>{
9735
10129
  type: "button",
9736
10130
  onClick: ()=>setPickingField(true),
9737
10131
  style: {
9738
- ...iconButtonStyle,
10132
+ ...iconButtonStyle$1,
9739
10133
  width: "auto",
9740
10134
  gap: 6,
9741
10135
  padding: "6px 8px",
@@ -9820,7 +10214,7 @@ function RowCount({ shown, total, countLabel }) {
9820
10214
  }
9821
10215
 
9822
10216
  function DataTableInner(props, ref) {
9823
- 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;
10217
+ 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;
9824
10218
  const classNames = dataTable({
9825
10219
  surface,
9826
10220
  interactive
@@ -9956,6 +10350,9 @@ function DataTableInner(props, ref) {
9956
10350
  columnLabels: columnLabels,
9957
10351
  defaultColumnLabels: defaultColumnLabels,
9958
10352
  onColumnLabelsChange: onColumnLabelsChange,
10353
+ pinnedColumnKeys: pinnedColumnKeys,
10354
+ defaultPinnedColumnKeys: defaultPinnedColumnKeys,
10355
+ onPinnedColumnKeysChange: onPinnedColumnKeysChange,
9959
10356
  columnCalcOps: columnCalcOps,
9960
10357
  defaultColumnCalcOps: defaultColumnCalcOps,
9961
10358
  onColumnCalcOpsChange: onColumnCalcOpsChange,
@@ -9999,19 +10396,13 @@ function DataTableInner(props, ref) {
9999
10396
  children: [
10000
10397
  /*#__PURE__*/ jsxRuntime.jsx(DataTableColGroup, {
10001
10398
  columns: columns,
10002
- selectable: !!selectable
10399
+ selectable: !!selectable,
10400
+ stickyFirst: stickyFirst
10003
10401
  }),
10004
10402
  /*#__PURE__*/ jsxRuntime.jsxs(DataTableHeader, {
10005
10403
  children: [
10006
- selectable && /*#__PURE__*/ jsxRuntime.jsx(DataTableSelectionHeaderCell, {
10007
- ...stickyProps({
10008
- selectable,
10009
- stickyFirst,
10010
- stickyLast: resolvedStickyLast,
10011
- isSelectionCell: true,
10012
- isFirst: false,
10013
- isLast: false
10014
- }),
10404
+ selectable && /*#__PURE__*/ jsxRuntime.jsx(SelectionHeaderCell, {
10405
+ stickyFirst: stickyFirst,
10015
10406
  children: /*#__PURE__*/ jsxRuntime.jsx(SelectAllCheckbox, {
10016
10407
  label: selectAllLabel,
10017
10408
  checkedIcon: selectionCheckedIcon ?? DEFAULT_CHECKED_ICON,
@@ -10062,7 +10453,7 @@ function DataTableInner(props, ref) {
10062
10453
  "data-clickable": onRowClick ? "" : undefined,
10063
10454
  onClick: onRowClick ? ()=>onRowClick(row) : undefined,
10064
10455
  children: [
10065
- selectable && /*#__PURE__*/ jsxRuntime.jsx(DataTableSelectionCell, {
10456
+ selectable && /*#__PURE__*/ jsxRuntime.jsx(SelectionCell, {
10066
10457
  // The row itself carries `onClick={onRowClick}` above, and a
10067
10458
  // native click on this cell's checkbox bubbles up through it
10068
10459
  // (React attaches DataTableRow's handler on the <tr>, which
@@ -10070,14 +10461,7 @@ function DataTableInner(props, ref) {
10070
10461
  // it from at -- so this has to live here, not in the consumer).
10071
10462
  // Without this, checking a row's box also fires `onRowClick`.
10072
10463
  onClick: (event)=>event.stopPropagation(),
10073
- ...stickyProps({
10074
- selectable,
10075
- stickyFirst,
10076
- stickyLast: resolvedStickyLast,
10077
- isSelectionCell: true,
10078
- isFirst: false,
10079
- isLast: false
10080
- }),
10464
+ stickyFirst: stickyFirst,
10081
10465
  children: /*#__PURE__*/ jsxRuntime.jsx(RowCheckbox, {
10082
10466
  label: getRowSelectionLabel(row),
10083
10467
  checkedIcon: selectionCheckedIcon ?? DEFAULT_CHECKED_ICON
@@ -10109,15 +10493,8 @@ function DataTableInner(props, ref) {
10109
10493
  // is what makes every row's selection column line up now, not a matching
10110
10494
  // per-slot width formula, so there is no more reason for this cell to
10111
10495
  // borrow a different slot than its footer siblings.
10112
- /*#__PURE__*/ jsxRuntime.jsx(DataTableFooterCell, {
10113
- ...stickyProps({
10114
- selectable,
10115
- stickyFirst,
10116
- stickyLast: resolvedStickyLast,
10117
- isSelectionCell: true,
10118
- isFirst: false,
10119
- isLast: false
10120
- })
10496
+ /*#__PURE__*/ jsxRuntime.jsx(SelectionFooterCell, {
10497
+ stickyFirst: stickyFirst
10121
10498
  }),
10122
10499
  /*#__PURE__*/ jsxRuntime.jsx(ColumnCalcCells, {
10123
10500
  columns: columns,
@@ -10153,7 +10530,16 @@ DataTableInner.displayName = "DataTable";
10153
10530
  * `DataTableInner`) purely so it can call `useDataTableContext()` -- that context is
10154
10531
  * provided by the `DataTablePrimitiveRoot` this renders as a SIBLING of, one level
10155
10532
  * up from where `DataTableInner` itself sits. */ function ColumnsChangeEffect({ columns, onColumnsChange }) {
10156
- const effective = useEffectiveColumns(columns);
10533
+ // `selectable`/`stickyFirst` are both `false` here on purpose: this convenience blob
10534
+ // never renders a row of its own, so it needs neither the +40px selection offset nor
10535
+ // `stickyFirst`'s legacy "no explicit pin -> pin the first visible column" fallback.
10536
+ // An EXPLICIT per-column pin (`pinnedColumnKeys`) still reorders this list the same
10537
+ // way it reorders every rendered row -- this callback reports "what's showing now",
10538
+ // and a pinned column showing first IS what's showing now.
10539
+ const effective = useEffectiveColumns(columns, {
10540
+ selectable: false,
10541
+ stickyFirst: false
10542
+ });
10157
10543
  // A NEW array every time `effective` itself is a new array (its own `useMemo`
10158
10544
  // recomputes only when order/hidden/label/width actually change) -- `header`
10159
10545
  // resolves to the menu's rename override (falling back to the column's own static
@@ -10188,8 +10574,16 @@ const DataTableTable = withContext$1(DataTableTable$1, "table");
10188
10574
  * out of sync between the three. A column with no explicit width gets a bare `<col>`
10189
10575
  * (no `style`): `table-layout: fixed`'s own algorithm gives every such column an equal
10190
10576
  * share of whatever space is left, matching the old flex grid's `flex: 1 1 0%`
10191
- * default with no extra code needed here. */ function DataTableColGroup({ columns, selectable }) {
10192
- const effective = useEffectiveColumns(columns);
10577
+ * default with no extra code needed here. */ function DataTableColGroup({ columns, selectable, stickyFirst }) {
10578
+ // MUST use the same pinned-first ordering every OTHER row (header/body/footer)
10579
+ // renders in (`useEffectiveColumns`'s own doc comment) -- a `<colgroup>`'s `<col>`s
10580
+ // are matched positionally to each row's cells, so if a pinned column visually moves
10581
+ // to the front of the header/body but not here, every column's width applies to the
10582
+ // WRONG cell.
10583
+ const effective = useEffectiveColumns(columns, {
10584
+ selectable,
10585
+ stickyFirst
10586
+ });
10193
10587
  return /*#__PURE__*/ jsxRuntime.jsxs("colgroup", {
10194
10588
  children: [
10195
10589
  selectable && /*#__PURE__*/ jsxRuntime.jsx("col", {
@@ -10275,6 +10669,32 @@ function DataTableFooter({ children, ...props }) {
10275
10669
  });
10276
10670
  }
10277
10671
  const DataTableFooterCell = withContext$1(Primitive.td, "footerCell");
10672
+ // The selection column's OWN sticky wrappers -- one each for header/body/footer,
10673
+ // reading the live pinned set via `useSelectionStickyFirst` (column-layout.ts) instead
10674
+ // of the `stickyFirst` PROP alone, so the checkbox column sticks the moment ANY column
10675
+ // is pinned, uncontrolled or not (see that hook's own doc comment for why this can't
10676
+ // just be computed once, above, in `DataTableInner`).
10677
+ function SelectionHeaderCell({ stickyFirst, children }) {
10678
+ const resolvedStickyFirst = useSelectionStickyFirst(stickyFirst);
10679
+ return /*#__PURE__*/ jsxRuntime.jsx(DataTableSelectionHeaderCell, {
10680
+ ...selectionStickyProps(resolvedStickyFirst),
10681
+ children: children
10682
+ });
10683
+ }
10684
+ function SelectionCell({ stickyFirst, onClick, children }) {
10685
+ const resolvedStickyFirst = useSelectionStickyFirst(stickyFirst);
10686
+ return /*#__PURE__*/ jsxRuntime.jsx(DataTableSelectionCell, {
10687
+ onClick: onClick,
10688
+ ...selectionStickyProps(resolvedStickyFirst),
10689
+ children: children
10690
+ });
10691
+ }
10692
+ function SelectionFooterCell({ stickyFirst }) {
10693
+ const resolvedStickyFirst = useSelectionStickyFirst(stickyFirst);
10694
+ return /*#__PURE__*/ jsxRuntime.jsx(DataTableFooterCell, {
10695
+ ...selectionStickyProps(resolvedStickyFirst)
10696
+ });
10697
+ }
10278
10698
  ////////////////////////////////////////////////////////////////////////////////////
10279
10699
  // Fix (bug report): karrot icons default to a 24px intrinsic SVG attribute size
10280
10700
  // -- see column-menu.tsx's own `SORT_ICON_SIZE` comment for the full mechanism.
@@ -10330,4 +10750,946 @@ function SelectAllCheckbox({ label, checkedIcon, indeterminateIcon }) {
10330
10750
  });
10331
10751
  }
10332
10752
 
10753
+ const rowStyle = {
10754
+ display: "flex",
10755
+ alignItems: "center",
10756
+ gap: 4
10757
+ };
10758
+ const rowButtonStyle = {
10759
+ flex: 1,
10760
+ minWidth: 0,
10761
+ textAlign: "left",
10762
+ display: "flex",
10763
+ alignItems: "center",
10764
+ gap: 6,
10765
+ padding: "6px 8px",
10766
+ border: "none",
10767
+ borderRadius: 6,
10768
+ background: "transparent",
10769
+ color: "var(--seed-color-fg-neutral)",
10770
+ fontSize: 13,
10771
+ cursor: "pointer",
10772
+ overflow: "hidden",
10773
+ textOverflow: "ellipsis",
10774
+ whiteSpace: "nowrap"
10775
+ };
10776
+ const smallButtonStyle = {
10777
+ flexShrink: 0,
10778
+ border: "none",
10779
+ borderRadius: 6,
10780
+ background: "transparent",
10781
+ color: "var(--seed-color-fg-neutral-subtle)",
10782
+ fontSize: 12,
10783
+ padding: "4px 6px",
10784
+ cursor: "pointer"
10785
+ };
10786
+ const iconButtonStyle = {
10787
+ display: "inline-flex",
10788
+ alignItems: "center",
10789
+ justifyContent: "center",
10790
+ width: 22,
10791
+ height: 22,
10792
+ flexShrink: 0,
10793
+ border: "none",
10794
+ borderRadius: 6,
10795
+ background: "transparent",
10796
+ color: "var(--seed-color-fg-neutral-subtle)",
10797
+ cursor: "pointer"
10798
+ };
10799
+ /**
10800
+ * A compact saved-views switcher -- current view name (or `label`) as the trigger,
10801
+ * a popover listing every saved view (click to switch, inline Rename/Delete), a
10802
+ * trailing "Save as new view", and (once a view is active) "Update view" to overwrite
10803
+ * the loaded view with the table's current state.
10804
+ */ 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 }) {
10805
+ const viewsApi = useDataTableViews(viewsProps);
10806
+ const { activeViewId, activeView } = viewsApi;
10807
+ const triggerLabel = activeView ? activeView.name : label;
10808
+ return /*#__PURE__*/ jsxRuntime.jsxs(MenuRoot, {
10809
+ children: [
10810
+ /*#__PURE__*/ jsxRuntime.jsx(MenuTrigger, {
10811
+ asChild: true,
10812
+ children: /*#__PURE__*/ jsxRuntime.jsxs(ActionButton, {
10813
+ variant: "neutralOutline",
10814
+ size: "xsmall",
10815
+ "data-active": activeViewId ? "" : undefined,
10816
+ children: [
10817
+ /*#__PURE__*/ jsxRuntime.jsx(IconArrowUpArrowDownLine_default, {
10818
+ size: 14,
10819
+ strokeWidth: 1.75
10820
+ }),
10821
+ triggerLabel,
10822
+ /*#__PURE__*/ jsxRuntime.jsx(IconChevronDownSmallLine_default, {
10823
+ size: 14,
10824
+ strokeWidth: 1.75
10825
+ })
10826
+ ]
10827
+ })
10828
+ }),
10829
+ /*#__PURE__*/ jsxRuntime.jsx(MenuPositioner, {
10830
+ children: /*#__PURE__*/ jsxRuntime.jsx(MenuContent, {
10831
+ style: {
10832
+ minWidth: 240
10833
+ },
10834
+ children: /*#__PURE__*/ jsxRuntime.jsx(MenuScrollArea, {
10835
+ children: /*#__PURE__*/ jsxRuntime.jsx(ViewsMenuBody, {
10836
+ viewsApi: viewsApi,
10837
+ captureState: captureState,
10838
+ applyState: applyState,
10839
+ label: label,
10840
+ showClearRow: showClearRow,
10841
+ clearLabel: clearLabel,
10842
+ newViewLabel: newViewLabel,
10843
+ updateViewLabel: updateViewLabel,
10844
+ renameLabel: renameLabel,
10845
+ deleteLabel: deleteLabel,
10846
+ renameInputLabel: renameInputLabel
10847
+ })
10848
+ })
10849
+ })
10850
+ })
10851
+ ]
10852
+ });
10853
+ }
10854
+ DataTableViewsControl.displayName = "DataTableViewsControl";
10855
+ /**
10856
+ * The popover's own body -- split out from `DataTableViewsControl` purely so it can
10857
+ * call `useMenuContext()` (`@seed-design/react-menu`), which only resolves for a
10858
+ * descendant of `MenuRoot`, not the component that RENDERS `MenuRoot` itself (the same
10859
+ * reason `column-layout.ts`'s `useSelectionStickyFirst` is its own component-level
10860
+ * hook rather than something computed in `DataTable.tsx` above its provider). Plain
10861
+ * `<button>` rows here (not seed `MenuItem`s -- `toolbar-conditions.tsx`'s own Sort/
10862
+ * Filter popovers make the same call) don't auto-close the menu on click the way a real
10863
+ * `MenuItem` does, so switching/creating/updating a view calls `setOpen(false)` here
10864
+ * explicitly; renaming and deleting deliberately do NOT close it, so a consumer can
10865
+ * clean up more than one view without reopening the popover each time.
10866
+ */ function ViewsMenuBody({ viewsApi, captureState, applyState, label, showClearRow, clearLabel, newViewLabel, updateViewLabel, renameLabel, deleteLabel, renameInputLabel }) {
10867
+ const { views, activeViewId, createView, updateView, renameView, deleteView, selectView } = viewsApi;
10868
+ const { setOpen } = reactMenu.useMenuContext();
10869
+ const [renamingId, setRenamingId] = React__namespace.useState(null);
10870
+ const [renameValue, setRenameValue] = React__namespace.useState("");
10871
+ // Same race `column-menu.tsx`'s own inline rename input already guards against:
10872
+ // starting a rename swaps the clicked "Rename" button for an input in the SAME
10873
+ // MenuContent this popover's own floating-ui focus management watches, and its
10874
+ // focus-guard spans can steal focus right back (to the content, or the trigger)
10875
+ // one frame after mount -- BEFORE this ref flips true -- so `onBlur` ignores that
10876
+ // one spurious blur and only commits a REAL blur (an actual click/tab away) after.
10877
+ const renameReadyRef = React__namespace.useRef(false);
10878
+ const renameInputRef = React__namespace.useRef(null);
10879
+ const handleSelect = (id)=>{
10880
+ selectView(id);
10881
+ if (id !== null) {
10882
+ const view = views.find((v)=>v.id === id);
10883
+ if (view) applyState(view.state);
10884
+ }
10885
+ setOpen(false);
10886
+ };
10887
+ const handleCreate = ()=>{
10888
+ createView(`View ${views.length + 1}`, captureState());
10889
+ setOpen(false);
10890
+ };
10891
+ const handleUpdate = ()=>{
10892
+ if (activeViewId) updateView(activeViewId, captureState());
10893
+ setOpen(false);
10894
+ };
10895
+ const startRename = (view)=>{
10896
+ renameReadyRef.current = false;
10897
+ setRenamingId(view.id);
10898
+ setRenameValue(view.name);
10899
+ };
10900
+ const commitRename = ()=>{
10901
+ if (renamingId && renameValue.trim()) renameView(renamingId, renameValue.trim());
10902
+ setRenamingId(null);
10903
+ };
10904
+ React__namespace.useEffect(()=>{
10905
+ if (!renamingId) return;
10906
+ // Re-grab focus (and select the text) one frame after mount, AFTER whatever
10907
+ // floating-ui's own focus-guard restore was going to do -- see this component's
10908
+ // own `renameReadyRef` doc comment above.
10909
+ const frame = requestAnimationFrame(()=>{
10910
+ renameReadyRef.current = true;
10911
+ renameInputRef.current?.focus();
10912
+ renameInputRef.current?.select();
10913
+ });
10914
+ return ()=>cancelAnimationFrame(frame);
10915
+ }, [
10916
+ renamingId
10917
+ ]);
10918
+ return /*#__PURE__*/ jsxRuntime.jsxs("div", {
10919
+ style: {
10920
+ display: "flex",
10921
+ flexDirection: "column",
10922
+ gap: 2,
10923
+ padding: "4px 8px"
10924
+ },
10925
+ children: [
10926
+ showClearRow && /*#__PURE__*/ jsxRuntime.jsx("button", {
10927
+ type: "button",
10928
+ onClick: ()=>handleSelect(null),
10929
+ "data-active": !activeViewId ? "" : undefined,
10930
+ style: rowButtonStyle,
10931
+ children: clearLabel ?? label
10932
+ }),
10933
+ views.length === 0 && /*#__PURE__*/ jsxRuntime.jsx("div", {
10934
+ style: {
10935
+ fontSize: 13,
10936
+ color: "var(--seed-color-fg-neutral-subtle)",
10937
+ padding: "4px 8px"
10938
+ },
10939
+ children: "No saved views yet."
10940
+ }),
10941
+ views.map((view)=>renamingId === view.id ? /*#__PURE__*/ jsxRuntime.jsx("div", {
10942
+ style: rowStyle,
10943
+ children: /*#__PURE__*/ jsxRuntime.jsx("input", {
10944
+ ref: renameInputRef,
10945
+ // 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).
10946
+ autoFocus: true,
10947
+ "aria-label": renameInputLabel(view.name),
10948
+ value: renameValue,
10949
+ onChange: (event)=>setRenameValue(event.target.value),
10950
+ onBlur: ()=>{
10951
+ if (renameReadyRef.current) commitRename();
10952
+ },
10953
+ onKeyDown: (event)=>{
10954
+ event.stopPropagation();
10955
+ if (event.key === "Enter") commitRename();
10956
+ if (event.key === "Escape") setRenamingId(null);
10957
+ },
10958
+ style: {
10959
+ flex: 1,
10960
+ minWidth: 0,
10961
+ font: "inherit",
10962
+ fontSize: 13,
10963
+ padding: "6px 8px",
10964
+ border: "1px solid var(--seed-color-border-neutral)",
10965
+ borderRadius: 6,
10966
+ background: "var(--seed-color-bg-surface)",
10967
+ color: "var(--seed-color-fg-neutral)"
10968
+ }
10969
+ })
10970
+ }, view.id) : /*#__PURE__*/ jsxRuntime.jsxs("div", {
10971
+ style: rowStyle,
10972
+ children: [
10973
+ /*#__PURE__*/ jsxRuntime.jsx("button", {
10974
+ type: "button",
10975
+ onClick: ()=>handleSelect(view.id),
10976
+ "data-active": view.id === activeViewId ? "" : undefined,
10977
+ style: rowButtonStyle,
10978
+ children: view.name
10979
+ }),
10980
+ /*#__PURE__*/ jsxRuntime.jsx("button", {
10981
+ type: "button",
10982
+ onClick: ()=>startRename(view),
10983
+ style: smallButtonStyle,
10984
+ children: renameLabel
10985
+ }),
10986
+ /*#__PURE__*/ jsxRuntime.jsx("button", {
10987
+ type: "button",
10988
+ "aria-label": `${deleteLabel} ${view.name}`,
10989
+ onClick: ()=>deleteView(view.id),
10990
+ style: iconButtonStyle,
10991
+ children: /*#__PURE__*/ jsxRuntime.jsx(IconXmarkLine_default, {
10992
+ size: 13,
10993
+ strokeWidth: 1.75
10994
+ })
10995
+ })
10996
+ ]
10997
+ }, view.id)),
10998
+ activeViewId && /*#__PURE__*/ jsxRuntime.jsx("button", {
10999
+ type: "button",
11000
+ onClick: handleUpdate,
11001
+ style: {
11002
+ ...rowButtonStyle,
11003
+ color: "var(--seed-color-fg-neutral-subtle)"
11004
+ },
11005
+ children: updateViewLabel
11006
+ }),
11007
+ /*#__PURE__*/ jsxRuntime.jsxs("button", {
11008
+ type: "button",
11009
+ onClick: handleCreate,
11010
+ style: rowButtonStyle,
11011
+ children: [
11012
+ /*#__PURE__*/ jsxRuntime.jsx(IconPlusLine_default, {
11013
+ size: 13,
11014
+ strokeWidth: 1.75
11015
+ }),
11016
+ newViewLabel
11017
+ ]
11018
+ })
11019
+ ]
11020
+ });
11021
+ }
11022
+
11023
+ __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}");
11024
+
11025
+ const resizablePanelSlotNames = [
11026
+ [
11027
+ "root",
11028
+ "seed-resizable-panel__root"
11029
+ ],
11030
+ [
11031
+ "spacer",
11032
+ "seed-resizable-panel__spacer"
11033
+ ],
11034
+ [
11035
+ "panel",
11036
+ "seed-resizable-panel__panel"
11037
+ ],
11038
+ [
11039
+ "inner",
11040
+ "seed-resizable-panel__inner"
11041
+ ],
11042
+ [
11043
+ "handle",
11044
+ "seed-resizable-panel__handle"
11045
+ ],
11046
+ [
11047
+ "handleInner",
11048
+ "seed-resizable-panel__handleInner"
11049
+ ]
11050
+ ];
11051
+ const defaultVariant$1 = {};
11052
+ const compoundVariants$1 = [];
11053
+ const resizablePanelVariantMap = {};
11054
+ function resizablePanel(props) {
11055
+ return Object.fromEntries(resizablePanelSlotNames.map(([slot, className])=>{
11056
+ return [
11057
+ slot,
11058
+ createClassName(className, mergeVariants(defaultVariant$1, props), compoundVariants$1)
11059
+ ];
11060
+ }));
11061
+ }
11062
+ Object.assign(resizablePanel, {
11063
+ splitVariantProps: (props)=>splitVariantProps(props, resizablePanelVariantMap)
11064
+ }); // @recipe(seed): resizable-panel
11065
+
11066
+ // Pure geometry + persistence helpers for ResizablePanel -- isolated from React so
11067
+ // they're unit-testable without a DOM, the same split `useDataTable`'s own dom.ts
11068
+ // draws for its column-layout math. Ported from your-moon/crisp's
11069
+ // `components/resizablepanel/resizablepanel.tsx` (computeDragWidth/widthToPercent/
11070
+ // percentToWidth/readStoredPercent/writeStoredPercent), unchanged in behavior.
11071
+ /**
11072
+ * Drag delta -> next width, in px, signed by which edge of the panel the handle
11073
+ * drags from. A left-side panel's handle sits at its *right* edge, so dragging
11074
+ * right (positive dx) grows it; a right-side panel's handle sits at its *left*
11075
+ * edge, so dragging right shrinks it.
11076
+ */ function computeDragWidth(startWidth, startX, clientX, side) {
11077
+ const dx = clientX - startX;
11078
+ return side === "left" ? startWidth + dx : startWidth - dx;
11079
+ }
11080
+ /** width (px) -> percentage of the container's width. Pure, unrounded. */ function widthToPercent(width, containerWidth) {
11081
+ if (!(containerWidth > 0)) return 0;
11082
+ return width / containerWidth * 100;
11083
+ }
11084
+ /** percentage of the container's width -> width (px). Pure, unrounded. */ function percentToWidth(percent, containerWidth) {
11085
+ return percent / 100 * containerWidth;
11086
+ }
11087
+ /**
11088
+ * Reads a persisted width percentage, wrapped in try/catch: `localStorage` can
11089
+ * throw (private browsing, storage disabled), and a resizable panel failing to
11090
+ * *render* over a persistence error would be worse than the panel simply
11091
+ * forgetting its width. `storage` defaults to `window.localStorage` and exists
11092
+ * as a seam for tests -- dropping the try/catch here is the exact failure this
11093
+ * must catch.
11094
+ */ function readStoredPercent(key, storage = window.localStorage) {
11095
+ try {
11096
+ const raw = storage.getItem(key);
11097
+ if (raw == null) return null;
11098
+ const n = Number(raw);
11099
+ return Number.isFinite(n) ? n : null;
11100
+ } catch {
11101
+ // private mode / storage disabled -- behave as if nothing is stored
11102
+ return null;
11103
+ }
11104
+ }
11105
+ /** Writes a persisted width percentage, wrapped in try/catch -- see {@link readStoredPercent}. */ function writeStoredPercent(key, percent, storage = window.localStorage) {
11106
+ try {
11107
+ storage.setItem(key, String(percent));
11108
+ } catch {
11109
+ // private mode / quota exceeded -- persistence is best-effort
11110
+ }
11111
+ }
11112
+ /**
11113
+ * Owns ResizablePanel's width state and pointer-drag handling -- the same
11114
+ * split `useDataTableSort` draws between the state it owns and the DOM
11115
+ * ref/style/recipe-class assembly a styled component does on top. Ported
11116
+ * from your-moon/crisp's `resizablepanel.tsx`; ONLY the state/behavior moved
11117
+ * here, not the DOM -- `ResizablePanel.tsx` (react package) still renders
11118
+ * the spacer/panel/handle and reads back the panel's actual rendered rect,
11119
+ * because crisp's own comment matters just as much in this split: constraints
11120
+ * are CSS `min-width`/`max-width`, never re-clamped in JS. This hook only
11121
+ * ever writes an UNclamped drag width; the caller's own panel ref is what
11122
+ * gets read back after layout on pointerup.
11123
+ */ function useResizablePanel(props) {
11124
+ const { side = "left", size, defaultSize = 280, onSizeChange, storageKey } = props;
11125
+ const controlled = size != null;
11126
+ const [width, setWidth] = useControllableState$1({
11127
+ prop: size,
11128
+ defaultProp: defaultSize,
11129
+ onChange: onSizeChange
11130
+ });
11131
+ const containerRef = React__namespace.useRef(null);
11132
+ const panelRef = React__namespace.useRef(null);
11133
+ const dragRef = React__namespace.useRef(null);
11134
+ const [dragging, setDragging] = React__namespace.useState(false);
11135
+ // Restore a persisted percentage on mount (uncontrolled + storageKey only).
11136
+ // biome-ignore lint/correctness/useExhaustiveDependencies: restore the persisted width once, on mount only
11137
+ React__namespace.useEffect(()=>{
11138
+ if (controlled || !storageKey) return;
11139
+ const percent = readStoredPercent(storageKey);
11140
+ if (percent == null) return;
11141
+ const containerWidth = containerRef.current?.getBoundingClientRect().width;
11142
+ if (!containerWidth) return;
11143
+ setWidth(percentToWidth(percent, containerWidth));
11144
+ }, []);
11145
+ const commitSize = React__namespace.useCallback((next)=>{
11146
+ setWidth(next);
11147
+ if (!controlled && storageKey) {
11148
+ const containerWidth = containerRef.current?.getBoundingClientRect().width;
11149
+ if (containerWidth) {
11150
+ writeStoredPercent(storageKey, widthToPercent(next, containerWidth));
11151
+ }
11152
+ }
11153
+ }, [
11154
+ controlled,
11155
+ setWidth,
11156
+ storageKey
11157
+ ]);
11158
+ const onHandlePointerDown = React__namespace.useCallback((event)=>{
11159
+ event.preventDefault();
11160
+ event.target.setPointerCapture?.(event.pointerId);
11161
+ dragRef.current = {
11162
+ startX: event.clientX,
11163
+ startWidth: width,
11164
+ moved: false
11165
+ };
11166
+ }, [
11167
+ width
11168
+ ]);
11169
+ const onHandlePointerMove = React__namespace.useCallback((event)=>{
11170
+ const drag = dragRef.current;
11171
+ if (!drag) return;
11172
+ if (!drag.moved) {
11173
+ drag.moved = true;
11174
+ setDragging(true);
11175
+ }
11176
+ const next = computeDragWidth(drag.startWidth, drag.startX, event.clientX, side);
11177
+ setWidth(next);
11178
+ }, [
11179
+ side,
11180
+ setWidth
11181
+ ]);
11182
+ const onHandlePointerUp = React__namespace.useCallback((event)=>{
11183
+ const drag = dragRef.current;
11184
+ dragRef.current = null;
11185
+ setDragging(false);
11186
+ event.target.releasePointerCapture?.(event.pointerId);
11187
+ if (!drag) return;
11188
+ // Never re-clamp here: read back the panel's actual, CSS-clamped
11189
+ // rendered width after layout, and commit *that* value.
11190
+ const rect = panelRef.current?.getBoundingClientRect();
11191
+ const finalWidth = rect ? Math.round(rect.width) : width;
11192
+ commitSize(finalWidth);
11193
+ }, [
11194
+ width,
11195
+ commitSize
11196
+ ]);
11197
+ // your-moon/crisp#795: double-click resets to `defaultSize`, confirmed
11198
+ // live on Attio's own record-page divider. Reuses `commitSize`, the same
11199
+ // commit path a drag already uses, so persistence (`storageKey`) picks up
11200
+ // the reset the same way it picks up a drag.
11201
+ const onHandleDoubleClick = React__namespace.useCallback(()=>{
11202
+ commitSize(defaultSize);
11203
+ }, [
11204
+ commitSize,
11205
+ defaultSize
11206
+ ]);
11207
+ return {
11208
+ width,
11209
+ dragging,
11210
+ containerRef,
11211
+ panelRef,
11212
+ handleHandlers: {
11213
+ onPointerDown: onHandlePointerDown,
11214
+ onPointerMove: onHandlePointerMove,
11215
+ onPointerUp: onHandlePointerUp,
11216
+ onDoubleClick: onHandleDoubleClick
11217
+ }
11218
+ };
11219
+ }
11220
+
11221
+ // The "column" handle variant's own wider hit-target class -- a literal
11222
+ // class name (not a recipe slot) the same way the recipe itself keys off it
11223
+ // (`resizable-panel.ts`'s own `.crisp-seed-resizable-panel-handle--column`
11224
+ // selector), so this component and that recipe stay in lockstep without a
11225
+ // second source of truth for the string.
11226
+ const COLUMN_HANDLE_CLASS = "crisp-seed-resizable-panel-handle--column";
11227
+ /**
11228
+ * An adjustable-panel primitive: a spacer that reserves layout width plus a
11229
+ * panel that overlays it, so the panel can move between docked (in-flow) and
11230
+ * floating (`position: fixed`, an overlay) without a reflow glitch. Drag the
11231
+ * edge handle to resize; constraints are CSS `min-width`/`max-width`, never
11232
+ * re-clamped in JS. Ported from your-moon/crisp's `ResizablePanel`
11233
+ * (`components/resizablepanel/`); state/drag behavior lives in
11234
+ * `useResizablePanel` (`@seed-design/react-resizable-panel`), this component
11235
+ * owns the DOM + recipe classes on top of it.
11236
+ */ const ResizablePanel = /*#__PURE__*/ React.forwardRef(({ side = "left", width: sizeProp, defaultSize = 280, onWidthChange, min = 200, max, floating = false, handleVariant = "panel", resizable = true, storageKey, className, children, ...rest }, forwardedRef)=>{
11237
+ const { width, dragging, containerRef, panelRef, handleHandlers } = useResizablePanel({
11238
+ side,
11239
+ size: sizeProp,
11240
+ defaultSize,
11241
+ onSizeChange: onWidthChange,
11242
+ storageKey
11243
+ });
11244
+ const classNames = resizablePanel();
11245
+ const maxStyle = max == null ? undefined : typeof max === "number" ? `${max}px` : max;
11246
+ const panelSizeStyle = {
11247
+ width,
11248
+ minWidth: min,
11249
+ maxWidth: maxStyle
11250
+ };
11251
+ return /*#__PURE__*/ jsxRuntime.jsxs(Primitive.div, {
11252
+ ref: (node)=>{
11253
+ containerRef.current = node;
11254
+ if (typeof forwardedRef === "function") forwardedRef(node);
11255
+ else if (forwardedRef) forwardedRef.current = node;
11256
+ },
11257
+ className: clsx(classNames.root, className),
11258
+ ...rest,
11259
+ children: [
11260
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.div, {
11261
+ className: classNames.spacer,
11262
+ style: floating ? {
11263
+ width: 0
11264
+ } : {
11265
+ width,
11266
+ minWidth: min,
11267
+ maxWidth: maxStyle
11268
+ }
11269
+ }),
11270
+ /*#__PURE__*/ jsxRuntime.jsxs(Primitive.div, {
11271
+ ref: panelRef,
11272
+ className: classNames.panel,
11273
+ "data-side": side,
11274
+ "data-floating": floating ? "true" : "false",
11275
+ style: panelSizeStyle,
11276
+ children: [
11277
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.div, {
11278
+ className: classNames.inner,
11279
+ children: children
11280
+ }),
11281
+ resizable && /*#__PURE__*/ jsxRuntime.jsx(Primitive.div, {
11282
+ className: clsx(classNames.handle, handleVariant === "column" && COLUMN_HANDLE_CLASS),
11283
+ "data-side": side,
11284
+ "data-dragging": dragging ? "true" : undefined,
11285
+ "data-handle": "",
11286
+ ...handleHandlers,
11287
+ children: handleVariant === "column" && /*#__PURE__*/ jsxRuntime.jsx(Primitive.span, {
11288
+ className: classNames.handleInner,
11289
+ "aria-hidden": "true"
11290
+ })
11291
+ })
11292
+ ]
11293
+ })
11294
+ ]
11295
+ });
11296
+ });
11297
+ ResizablePanel.displayName = "ResizablePanel";
11298
+
11299
+ __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)}");
11300
+
11301
+ const recordPanelSlotNames = [
11302
+ [
11303
+ "root",
11304
+ "seed-record-panel__root"
11305
+ ],
11306
+ [
11307
+ "toolbar",
11308
+ "seed-record-panel__toolbar"
11309
+ ],
11310
+ [
11311
+ "toolbarSpacer",
11312
+ "seed-record-panel__toolbarSpacer"
11313
+ ],
11314
+ [
11315
+ "pager",
11316
+ "seed-record-panel__pager"
11317
+ ],
11318
+ [
11319
+ "counter",
11320
+ "seed-record-panel__counter"
11321
+ ],
11322
+ [
11323
+ "iconbtn",
11324
+ "seed-record-panel__iconbtn"
11325
+ ],
11326
+ [
11327
+ "navbtn",
11328
+ "seed-record-panel__navbtn"
11329
+ ],
11330
+ [
11331
+ "header",
11332
+ "seed-record-panel__header"
11333
+ ],
11334
+ [
11335
+ "fav",
11336
+ "seed-record-panel__fav"
11337
+ ],
11338
+ [
11339
+ "title",
11340
+ "seed-record-panel__title"
11341
+ ],
11342
+ [
11343
+ "body",
11344
+ "seed-record-panel__body"
11345
+ ],
11346
+ [
11347
+ "section",
11348
+ "seed-record-panel__section"
11349
+ ],
11350
+ [
11351
+ "sectionHead",
11352
+ "seed-record-panel__sectionHead"
11353
+ ],
11354
+ [
11355
+ "sectionLabel",
11356
+ "seed-record-panel__sectionLabel"
11357
+ ],
11358
+ [
11359
+ "sectionAction",
11360
+ "seed-record-panel__sectionAction"
11361
+ ],
11362
+ [
11363
+ "highlights",
11364
+ "seed-record-panel__highlights"
11365
+ ],
11366
+ [
11367
+ "highlight",
11368
+ "seed-record-panel__highlight"
11369
+ ],
11370
+ [
11371
+ "highlightLabel",
11372
+ "seed-record-panel__highlightLabel"
11373
+ ],
11374
+ [
11375
+ "highlightValue",
11376
+ "seed-record-panel__highlightValue"
11377
+ ],
11378
+ [
11379
+ "activity",
11380
+ "seed-record-panel__activity"
11381
+ ],
11382
+ [
11383
+ "sections",
11384
+ "seed-record-panel__sections"
11385
+ ],
11386
+ [
11387
+ "sectionTrigger",
11388
+ "seed-record-panel__sectionTrigger"
11389
+ ],
11390
+ [
11391
+ "sectionRowLabel",
11392
+ "seed-record-panel__sectionRowLabel"
11393
+ ],
11394
+ [
11395
+ "sectionRowCount",
11396
+ "seed-record-panel__sectionRowCount"
11397
+ ],
11398
+ [
11399
+ "sectionChevron",
11400
+ "seed-record-panel__sectionChevron"
11401
+ ],
11402
+ [
11403
+ "sectionContent",
11404
+ "seed-record-panel__sectionContent"
11405
+ ],
11406
+ [
11407
+ "footer",
11408
+ "seed-record-panel__footer"
11409
+ ]
11410
+ ];
11411
+ const defaultVariant = {};
11412
+ const compoundVariants = [];
11413
+ const recordPanelVariantMap = {};
11414
+ function recordPanel(props) {
11415
+ return Object.fromEntries(recordPanelSlotNames.map(([slot, className])=>{
11416
+ return [
11417
+ slot,
11418
+ createClassName(className, mergeVariants(defaultVariant, props), compoundVariants)
11419
+ ];
11420
+ }));
11421
+ }
11422
+ Object.assign(recordPanel, {
11423
+ splitVariantProps: (props)=>splitVariantProps(props, recordPanelVariantMap)
11424
+ }); // @recipe(seed): record-panel
11425
+
11426
+ const RESIZE_MIN_WIDTH = 360;
11427
+ const RESIZE_MAX_WIDTH = 720;
11428
+ /**
11429
+ * Right-side record peek panel -- Attio's own peek shows a Highlights card
11430
+ * area and an Activity feed (measured live). Ported from your-moon/crisp's
11431
+ * `RecordPanel` (`product/recordpanel/`), built ON `ResizablePanel`
11432
+ * (`side="right" floating`) rather than crisp's own duplicate absolute-
11433
+ * positioning/slide-in/resize-handle implementation -- the outer shell (the
11434
+ * `@starting-style` slide-in, the floating elevation, the drag handle
11435
+ * itself) all come from that primitive; this component only renders the
11436
+ * CONTENT inside it.
11437
+ */ 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 }) {
11438
+ const titleId = React.useId();
11439
+ const classNames = recordPanel();
11440
+ // Which sections (your-moon/crisp#413) are expanded -- uncontrolled and
11441
+ // independent (Attio's own Emails/Notes/Tasks open without closing one
11442
+ // another): a plain `Set`, reset whenever the record itself changes so a
11443
+ // stale open section doesn't carry over between two different records.
11444
+ const [openSections, setOpenSections] = React.useState(()=>new Set());
11445
+ // 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.
11446
+ React.useEffect(()=>{
11447
+ setOpenSections(new Set());
11448
+ }, [
11449
+ record
11450
+ ]);
11451
+ const toggleSection = (key)=>setOpenSections((prev)=>{
11452
+ const next = new Set(prev);
11453
+ if (next.has(key)) next.delete(key);
11454
+ else next.add(key);
11455
+ return next;
11456
+ });
11457
+ // Close on Escape while open. Simpler than crisp's own version (crisp
11458
+ // additionally checks `hasOpenFloatingLayer()` so an Escape meant for a
11459
+ // nested Menu/Select/Popover doesn't also close this panel) -- crispy-seed
11460
+ // has no equivalent floating-stack registry to read, so a consumer nesting
11461
+ // its own floating layers inside `footer`/`sections` content should stop
11462
+ // propagation on its own Escape handler.
11463
+ React.useEffect(()=>{
11464
+ if (!open) return;
11465
+ const onKey = (event)=>{
11466
+ if (event.key === "Escape") onClose();
11467
+ };
11468
+ document.addEventListener("keydown", onKey);
11469
+ return ()=>document.removeEventListener("keydown", onKey);
11470
+ }, [
11471
+ open,
11472
+ onClose
11473
+ ]);
11474
+ if (!open || !record) return null;
11475
+ const heading = title ?? record.name ?? "Record";
11476
+ return /*#__PURE__*/ jsxRuntime.jsx(ResizablePanel, {
11477
+ side: "right",
11478
+ floating: true,
11479
+ resizable: resizable,
11480
+ width: width,
11481
+ defaultSize: defaultWidth,
11482
+ onWidthChange: onWidthChange,
11483
+ min: minWidth,
11484
+ max: maxWidth,
11485
+ children: /*#__PURE__*/ jsxRuntime.jsxs(Primitive.div, {
11486
+ className: clsx(classNames.root, className),
11487
+ ...rest,
11488
+ role: "dialog",
11489
+ "aria-labelledby": titleId,
11490
+ children: [
11491
+ /*#__PURE__*/ jsxRuntime.jsxs(Primitive.div, {
11492
+ className: classNames.toolbar,
11493
+ children: [
11494
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.button, {
11495
+ type: "button",
11496
+ className: classNames.iconbtn,
11497
+ "aria-label": closeLabel,
11498
+ onClick: onClose,
11499
+ children: /*#__PURE__*/ jsxRuntime.jsx(IconXmarkLine_default, {
11500
+ size: 16
11501
+ })
11502
+ }),
11503
+ (onPrevious || onNext) && /*#__PURE__*/ jsxRuntime.jsxs(Primitive.span, {
11504
+ className: classNames.pager,
11505
+ children: [
11506
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.button, {
11507
+ type: "button",
11508
+ className: classNames.navbtn,
11509
+ "aria-label": previousRecordLabel,
11510
+ disabled: !onPrevious,
11511
+ onClick: onPrevious,
11512
+ children: /*#__PURE__*/ jsxRuntime.jsx(IconChevronUpLine_default, {
11513
+ size: 16
11514
+ })
11515
+ }),
11516
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.button, {
11517
+ type: "button",
11518
+ className: classNames.navbtn,
11519
+ "aria-label": nextRecordLabel,
11520
+ disabled: !onNext,
11521
+ onClick: onNext,
11522
+ children: /*#__PURE__*/ jsxRuntime.jsx(IconChevronDownLine_default, {
11523
+ size: 16
11524
+ })
11525
+ })
11526
+ ]
11527
+ }),
11528
+ counterLabel != null && /*#__PURE__*/ jsxRuntime.jsx(Primitive.span, {
11529
+ className: classNames.counter,
11530
+ children: counterLabel
11531
+ }),
11532
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.span, {
11533
+ className: classNames.toolbarSpacer
11534
+ }),
11535
+ onOpenRecord && /*#__PURE__*/ jsxRuntime.jsx(Primitive.button, {
11536
+ type: "button",
11537
+ className: classNames.navbtn,
11538
+ "aria-label": openRecordLabel,
11539
+ onClick: onOpenRecord,
11540
+ children: /*#__PURE__*/ jsxRuntime.jsx(IconArrowUpRightLine_default, {
11541
+ size: 16
11542
+ })
11543
+ })
11544
+ ]
11545
+ }),
11546
+ /*#__PURE__*/ jsxRuntime.jsxs(Primitive.div, {
11547
+ className: classNames.header,
11548
+ children: [
11549
+ avatar ? /*#__PURE__*/ jsxRuntime.jsx(Primitive.img, {
11550
+ className: classNames.fav,
11551
+ src: avatar,
11552
+ alt: ""
11553
+ }) : /*#__PURE__*/ jsxRuntime.jsx(AvatarRoot, {
11554
+ size: "24",
11555
+ children: /*#__PURE__*/ jsxRuntime.jsx(AvatarFallback, {
11556
+ children: (record.name ?? "?").charAt(0)
11557
+ })
11558
+ }),
11559
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.span, {
11560
+ id: titleId,
11561
+ className: classNames.title,
11562
+ children: heading
11563
+ })
11564
+ ]
11565
+ }),
11566
+ /*#__PURE__*/ jsxRuntime.jsxs(Primitive.div, {
11567
+ className: classNames.body,
11568
+ children: [
11569
+ highlights && highlights.length > 0 && /*#__PURE__*/ jsxRuntime.jsxs(Primitive.div, {
11570
+ className: classNames.section,
11571
+ children: [
11572
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.div, {
11573
+ className: classNames.sectionHead,
11574
+ children: /*#__PURE__*/ jsxRuntime.jsx(Primitive.span, {
11575
+ className: classNames.sectionLabel,
11576
+ children: highlightsLabel
11577
+ })
11578
+ }),
11579
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.div, {
11580
+ className: classNames.highlights,
11581
+ children: highlights.map((h)=>/*#__PURE__*/ jsxRuntime.jsxs(Primitive.div, {
11582
+ className: classNames.highlight,
11583
+ children: [
11584
+ /*#__PURE__*/ jsxRuntime.jsxs(Primitive.span, {
11585
+ className: classNames.highlightLabel,
11586
+ children: [
11587
+ /*#__PURE__*/ jsxRuntime.jsx("span", {
11588
+ children: h.label
11589
+ }),
11590
+ h.icon ? /*#__PURE__*/ jsxRuntime.jsx(h.icon, {
11591
+ size: 16
11592
+ }) : null
11593
+ ]
11594
+ }),
11595
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.span, {
11596
+ className: classNames.highlightValue,
11597
+ children: h.value
11598
+ })
11599
+ ]
11600
+ }, h.key))
11601
+ })
11602
+ ]
11603
+ }),
11604
+ activity != null && /*#__PURE__*/ jsxRuntime.jsxs(Primitive.div, {
11605
+ className: classNames.section,
11606
+ children: [
11607
+ /*#__PURE__*/ jsxRuntime.jsxs(Primitive.div, {
11608
+ className: classNames.sectionHead,
11609
+ children: [
11610
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.span, {
11611
+ className: classNames.sectionLabel,
11612
+ children: activityLabel
11613
+ }),
11614
+ onViewAllActivity && /*#__PURE__*/ jsxRuntime.jsx(Primitive.button, {
11615
+ type: "button",
11616
+ className: classNames.sectionAction,
11617
+ onClick: onViewAllActivity,
11618
+ children: viewAllActivityLabel
11619
+ })
11620
+ ]
11621
+ }),
11622
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.div, {
11623
+ className: classNames.activity,
11624
+ children: activity
11625
+ })
11626
+ ]
11627
+ }),
11628
+ sections && sections.length > 0 && /*#__PURE__*/ jsxRuntime.jsx(Primitive.div, {
11629
+ className: classNames.sections,
11630
+ children: sections.map((s)=>{
11631
+ const isOpen = openSections.has(s.key);
11632
+ const panelId = `${titleId}-section-${s.key}`;
11633
+ return /*#__PURE__*/ jsxRuntime.jsxs("div", {
11634
+ children: [
11635
+ s.content ? /*#__PURE__*/ jsxRuntime.jsxs(Primitive.button, {
11636
+ type: "button",
11637
+ className: classNames.sectionTrigger,
11638
+ "aria-expanded": isOpen,
11639
+ "aria-controls": panelId,
11640
+ onClick: ()=>toggleSection(s.key),
11641
+ children: [
11642
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.span, {
11643
+ className: classNames.sectionRowLabel,
11644
+ children: s.label
11645
+ }),
11646
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.span, {
11647
+ className: classNames.sectionRowCount,
11648
+ children: s.count
11649
+ }),
11650
+ /*#__PURE__*/ jsxRuntime.jsx(IconChevronDownLine_default, {
11651
+ className: classNames.sectionChevron,
11652
+ size: 14,
11653
+ "data-open": isOpen ? "" : undefined,
11654
+ "aria-hidden": "true"
11655
+ })
11656
+ ]
11657
+ }) : /*#__PURE__*/ jsxRuntime.jsxs(Primitive.div, {
11658
+ className: classNames.sectionTrigger,
11659
+ "data-inert": "",
11660
+ children: [
11661
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.span, {
11662
+ className: classNames.sectionRowLabel,
11663
+ children: s.label
11664
+ }),
11665
+ /*#__PURE__*/ jsxRuntime.jsx(Primitive.span, {
11666
+ className: classNames.sectionRowCount,
11667
+ children: s.count
11668
+ })
11669
+ ]
11670
+ }),
11671
+ s.content && isOpen && /*#__PURE__*/ jsxRuntime.jsx(Primitive.div, {
11672
+ id: panelId,
11673
+ className: classNames.sectionContent,
11674
+ children: s.content
11675
+ })
11676
+ ]
11677
+ }, s.key);
11678
+ })
11679
+ })
11680
+ ]
11681
+ }),
11682
+ footer != null && /*#__PURE__*/ jsxRuntime.jsx(Primitive.div, {
11683
+ className: classNames.footer,
11684
+ children: footer
11685
+ })
11686
+ ]
11687
+ })
11688
+ });
11689
+ }
11690
+ RecordPanel.displayName = "RecordPanel";
11691
+
10333
11692
  exports.DataTable = DataTable;
11693
+ exports.DataTableViewsControl = DataTableViewsControl;
11694
+ exports.RecordPanel = RecordPanel;
11695
+ exports.ResizablePanel = ResizablePanel;