@crispy-seed/data-table 0.10.5 → 0.11.1
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/data-table-recipe.css +58 -0
- package/dist/data-table-recipe.layered.css +63 -0
- package/dist/index.cjs +725 -359
- package/dist/index.d.ts +82 -15
- package/dist/index.js +725 -360
- package/dist/styles.css +63 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -17,6 +17,9 @@ var reactCheckbox = require('@seed-design/react-checkbox');
|
|
|
17
17
|
var reactScaleFeedback = require('@seed-design/react-scale-feedback');
|
|
18
18
|
var checkboxGroup = require('@seed-design/css/recipes/checkbox-group');
|
|
19
19
|
var reactDom = require('react-dom');
|
|
20
|
+
var reactMenu = require('@seed-design/react-menu');
|
|
21
|
+
var menu = require('@seed-design/css/recipes/menu');
|
|
22
|
+
var menuItem = require('@seed-design/css/recipes/menu-item');
|
|
20
23
|
var reactImage = require('@seed-design/react-image');
|
|
21
24
|
var avatar = require('@seed-design/css/recipes/avatar');
|
|
22
25
|
require('@seed-design/css/recipes/avatar-stack');
|
|
@@ -31,9 +34,6 @@ var _switch = require('@seed-design/css/recipes/switch');
|
|
|
31
34
|
var switchmark = require('@seed-design/css/recipes/switchmark');
|
|
32
35
|
var reactTextField = require('@seed-design/react-text-field');
|
|
33
36
|
var textInput = require('@seed-design/css/recipes/text-input');
|
|
34
|
-
var reactMenu = require('@seed-design/react-menu');
|
|
35
|
-
var menu = require('@seed-design/css/recipes/menu');
|
|
36
|
-
var menuItem = require('@seed-design/css/recipes/menu-item');
|
|
37
37
|
var tabs = require('@seed-design/css/recipes/tabs');
|
|
38
38
|
|
|
39
39
|
function _interopNamespace(e) {
|
|
@@ -780,7 +780,10 @@ function isFunction$1(value) {
|
|
|
780
780
|
const DATA_TABLE_UNIVERSAL_CALC_OPS = [
|
|
781
781
|
"count",
|
|
782
782
|
"empty",
|
|
783
|
-
"notEmpty"
|
|
783
|
+
"notEmpty",
|
|
784
|
+
"percentEmpty",
|
|
785
|
+
"percentFilled",
|
|
786
|
+
"none"
|
|
784
787
|
];
|
|
785
788
|
const DATA_TABLE_NUMERIC_CALC_OPS = [
|
|
786
789
|
"sum",
|
|
@@ -795,8 +798,11 @@ const DATA_TABLE_NUMERIC_CALC_OPS = [
|
|
|
795
798
|
];
|
|
796
799
|
const DATA_TABLE_CALC_LABEL = {
|
|
797
800
|
count: "Count",
|
|
798
|
-
empty: "
|
|
799
|
-
notEmpty: "
|
|
801
|
+
empty: "Count empty",
|
|
802
|
+
notEmpty: "Count filled",
|
|
803
|
+
percentEmpty: "Percent empty",
|
|
804
|
+
percentFilled: "Percent filled",
|
|
805
|
+
none: "None",
|
|
800
806
|
sum: "Sum",
|
|
801
807
|
average: "Average",
|
|
802
808
|
median: "Median",
|
|
@@ -826,7 +832,12 @@ const DATA_TABLE_CALC_LABEL = {
|
|
|
826
832
|
* (`JSON.stringify`-normalized, so two arrays/objects with the same shape count
|
|
827
833
|
* once) -- empties are already their own op (`empty`), so folding them into "one
|
|
828
834
|
* more unique value" here would double-count the same information two different
|
|
829
|
-
* ways in the same menu.
|
|
835
|
+
* ways in the same menu. `percentEmpty`/`percentFilled` are `empty`/`notEmpty` as a
|
|
836
|
+
* share of the row count (0-100, unrounded -- formatting rounds it for display) --
|
|
837
|
+
* `null` on zero rows, since 0/0 has no meaningful percentage (not 0%, not 100%).
|
|
838
|
+
* `none` always renders nothing: it is Attio's own "no calculation" menu entry, not a
|
|
839
|
+
* separate always-appended "Clear" item, and picking it is a real, storable op so it
|
|
840
|
+
* overrides a `summaryDefaultOp` instead of falling back to it.
|
|
830
841
|
*/ function computeColumnCalc(values, op) {
|
|
831
842
|
switch(op){
|
|
832
843
|
case "count":
|
|
@@ -835,6 +846,14 @@ const DATA_TABLE_CALC_LABEL = {
|
|
|
835
846
|
return values.filter(isEmptyValueForCalc).length;
|
|
836
847
|
case "notEmpty":
|
|
837
848
|
return values.filter((value)=>!isEmptyValueForCalc(value)).length;
|
|
849
|
+
case "percentEmpty":
|
|
850
|
+
if (values.length === 0) return null;
|
|
851
|
+
return values.filter(isEmptyValueForCalc).length / values.length * 100;
|
|
852
|
+
case "percentFilled":
|
|
853
|
+
if (values.length === 0) return null;
|
|
854
|
+
return values.filter((value)=>!isEmptyValueForCalc(value)).length / values.length * 100;
|
|
855
|
+
case "none":
|
|
856
|
+
return null;
|
|
838
857
|
case "countUnique":
|
|
839
858
|
{
|
|
840
859
|
const seen = new Set(values.filter((value)=>!isEmptyValueForCalc(value)).map((value)=>JSON.stringify(value)));
|
|
@@ -968,15 +987,33 @@ function sameCell$1(a, id, key) {
|
|
|
968
987
|
* first captured) nor keeps a ghost entry for one that was removed. Known keys keep
|
|
969
988
|
* their position from `order`; any key in `keys` missing from `order` is appended, in
|
|
970
989
|
* `keys`' own order; any entry in `order` no longer in `keys` is dropped.
|
|
971
|
-
|
|
990
|
+
*
|
|
991
|
+
* `actionsKey` (the styled layer's `actions`-flagged column, e.g. the row-menu `⋯`
|
|
992
|
+
* column) is kept LAST no matter what -- without this, a brand-new column added to
|
|
993
|
+
* `columns` after the table first mounted got appended past it (the "any key in `keys`
|
|
994
|
+
* missing from `order` is appended" rule above has no notion of "past the end" vs. "at
|
|
995
|
+
* the very end"), stranding it in the middle of the table since `stickyLast`/`actions`
|
|
996
|
+
* only sticks the actual trailing column. A real consumer hit this: their newly-added
|
|
997
|
+
* column landed to the right of the already-pinned-sticky `actions` column, covered by
|
|
998
|
+
* it under horizontal scroll. Column-layout's own `pinnedCellProps` independently
|
|
999
|
+
* targets the `actions` column by FLAG rather than by position (belt and suspenders --
|
|
1000
|
+
* see that file's own doc comment), but this still keeps the VISUAL order sane so nothing
|
|
1001
|
+
* renders hidden behind the sticky cell in the first place.
|
|
1002
|
+
*/ function reconcileColumnOrder(order, keys, actionsKey) {
|
|
972
1003
|
const keySet = new Set(keys);
|
|
973
1004
|
const known = order.filter((key)=>keySet.has(key));
|
|
974
1005
|
const knownSet = new Set(known);
|
|
975
1006
|
const added = keys.filter((key)=>!knownSet.has(key));
|
|
976
|
-
|
|
1007
|
+
const merged = [
|
|
977
1008
|
...known,
|
|
978
1009
|
...added
|
|
979
1010
|
];
|
|
1011
|
+
if (actionsKey === undefined || !keySet.has(actionsKey)) return merged;
|
|
1012
|
+
const withoutActions = merged.filter((key)=>key !== actionsKey);
|
|
1013
|
+
return [
|
|
1014
|
+
...withoutActions,
|
|
1015
|
+
actionsKey
|
|
1016
|
+
];
|
|
980
1017
|
}
|
|
981
1018
|
/**
|
|
982
1019
|
* Moves `key` one step toward `direction` in `order` -- a no-op (same array, well,
|
|
@@ -1155,7 +1192,7 @@ const EMPTY_RECORD = {};
|
|
|
1155
1192
|
* state this hook already owns, not independent state
|
|
1156
1193
|
* of their own.
|
|
1157
1194
|
*/ function useDataTableColumns(props) {
|
|
1158
|
-
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;
|
|
1195
|
+
const { columnKeys = EMPTY_STRINGS, actionsColumnKey, 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;
|
|
1159
1196
|
const [rawOrder, setRawOrder] = useControllableState$1({
|
|
1160
1197
|
prop: columnOrderProp,
|
|
1161
1198
|
defaultProp: defaultColumnOrder ?? columnKeys,
|
|
@@ -1166,9 +1203,10 @@ const EMPTY_RECORD = {};
|
|
|
1166
1203
|
// consumer persisted before a new column existed must still show that new column
|
|
1167
1204
|
// (appended), and one holding a column that got removed from `columns` must not
|
|
1168
1205
|
// render a ghost header for it.
|
|
1169
|
-
const columnOrder = React.useMemo(()=>reconcileColumnOrder(rawOrder ?? columnKeys, columnKeys), [
|
|
1206
|
+
const columnOrder = React.useMemo(()=>reconcileColumnOrder(rawOrder ?? columnKeys, columnKeys, actionsColumnKey), [
|
|
1170
1207
|
rawOrder,
|
|
1171
|
-
columnKeys
|
|
1208
|
+
columnKeys,
|
|
1209
|
+
actionsColumnKey
|
|
1172
1210
|
]);
|
|
1173
1211
|
const [hiddenColumnKeys = EMPTY_STRINGS, setHiddenColumnKeys] = useControllableState$1({
|
|
1174
1212
|
prop: hiddenProp,
|
|
@@ -1653,6 +1691,17 @@ function useDataTableSelection(props) {
|
|
|
1653
1691
|
rowIds,
|
|
1654
1692
|
setSelectedIds
|
|
1655
1693
|
]);
|
|
1694
|
+
// Bulk-action bar's own "×" (gap #4, DATATABLE-ATTIO-SPEC's Attio review) --
|
|
1695
|
+
// deliberately its own function rather than reusing `toggleAll`: `toggleAll` only
|
|
1696
|
+
// clears from an "all" selection, and otherwise SELECTS every row (`selectionState
|
|
1697
|
+
// === "some"` -> `rowIds`, above) -- exactly the wrong direction for a "clear
|
|
1698
|
+
// selection" affordance shown while `selectionState` is "some". This always empties
|
|
1699
|
+
// the set, regardless of `selectionState`.
|
|
1700
|
+
const clearSelection = React.useCallback(()=>{
|
|
1701
|
+
setSelectedIds([]);
|
|
1702
|
+
}, [
|
|
1703
|
+
setSelectedIds
|
|
1704
|
+
]);
|
|
1656
1705
|
const getRowProps = React.useCallback((rowId)=>{
|
|
1657
1706
|
const isRowSelected = isSelected(rowId);
|
|
1658
1707
|
return domUtils.elementProps({
|
|
@@ -1671,6 +1720,7 @@ function useDataTableSelection(props) {
|
|
|
1671
1720
|
isSelected,
|
|
1672
1721
|
toggleRow,
|
|
1673
1722
|
toggleAll,
|
|
1723
|
+
clearSelection,
|
|
1674
1724
|
getRowProps
|
|
1675
1725
|
};
|
|
1676
1726
|
}
|
|
@@ -2138,7 +2188,7 @@ function useDataTableRowContext({ strict = true } = {}) {
|
|
|
2138
2188
|
return context;
|
|
2139
2189
|
}
|
|
2140
2190
|
const DataTableRoot = /*#__PURE__*/ React.forwardRef((props, ref)=>{
|
|
2141
|
-
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;
|
|
2191
|
+
const { sort, defaultSort, onSortChange, rowIds, selectable, selectedIds, defaultSelectedIds, onSelectionChange, query, defaultQuery, onQueryChange, toolbarSorts, defaultToolbarSorts, onToolbarSortsChange, toolbarFilters, defaultToolbarFilters, onToolbarFiltersChange, columnKeys, actionsColumnKey, columnOrder, defaultColumnOrder, onColumnOrderChange, hiddenColumnKeys, defaultHiddenColumnKeys, onHiddenColumnKeysChange, columnWidths, defaultColumnWidths, onColumnWidthsChange, columnLabels, defaultColumnLabels, onColumnLabelsChange, pinnedColumnKeys, defaultPinnedColumnKeys, onPinnedColumnKeysChange, columnCalcOps, defaultColumnCalcOps, onColumnCalcOpsChange, onEdit, onLoadMore, hasMore, loadingMore, ...otherProps } = props;
|
|
2142
2192
|
const api = useDataTable({
|
|
2143
2193
|
sort,
|
|
2144
2194
|
defaultSort,
|
|
@@ -2158,6 +2208,7 @@ const DataTableRoot = /*#__PURE__*/ React.forwardRef((props, ref)=>{
|
|
|
2158
2208
|
defaultToolbarFilters,
|
|
2159
2209
|
onToolbarFiltersChange,
|
|
2160
2210
|
columnKeys,
|
|
2211
|
+
actionsColumnKey,
|
|
2161
2212
|
columnOrder,
|
|
2162
2213
|
defaultColumnOrder,
|
|
2163
2214
|
onColumnOrderChange,
|
|
@@ -2679,11 +2730,70 @@ CheckboxIndicator.displayName = "CheckboxIndicator";
|
|
|
2679
2730
|
const CheckboxLabel = withContext$6(withStateProps$4(Primitive.span), "label");
|
|
2680
2731
|
const CheckboxHiddenInput = reactCheckbox.Checkbox.HiddenInput;
|
|
2681
2732
|
|
|
2682
|
-
const {
|
|
2733
|
+
const { ClassNamesProvider: ClassNamesProvider$2, withContext: withContext$5, useClassNames: useClassNames$2 } = createSlotRecipeContext(menu.menu);
|
|
2734
|
+
const { PropsProvider: ItemPropsProvider$1, useProps: useItemProps$1, withContext: withItemContext$1, ClassNamesProvider: ItemClassNamesProvider$1 } = createSlotRecipeContext(menuItem.menuItem);
|
|
2735
|
+
const withStateProps$3 = createWithStateProps([
|
|
2736
|
+
reactMenu.useMenuContext
|
|
2737
|
+
]);
|
|
2738
|
+
const withItemStateProps$1 = createWithStateProps([
|
|
2739
|
+
reactMenu.useMenuItemContext
|
|
2740
|
+
]);
|
|
2741
|
+
const MenuRoot = (props)=>{
|
|
2742
|
+
const [variantProps, otherProps] = menu.menu.splitVariantProps(props);
|
|
2743
|
+
const classNames = menu.menu(variantProps);
|
|
2744
|
+
return /*#__PURE__*/ jsxRuntime.jsx(ClassNamesProvider$2, {
|
|
2745
|
+
value: classNames,
|
|
2746
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(ItemPropsProvider$1, {
|
|
2747
|
+
value: {
|
|
2748
|
+
size: variantProps.size
|
|
2749
|
+
},
|
|
2750
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(reactMenu.Menu.Root, {
|
|
2751
|
+
...otherProps
|
|
2752
|
+
})
|
|
2753
|
+
})
|
|
2754
|
+
});
|
|
2755
|
+
};
|
|
2756
|
+
const MenuAnchor = reactMenu.Menu.Anchor;
|
|
2757
|
+
const MenuTrigger = reactMenu.Menu.Trigger;
|
|
2758
|
+
const MenuPositioner = /*#__PURE__*/ React__namespace.forwardRef(({ className, ...props }, ref)=>{
|
|
2759
|
+
const classNames = useClassNames$2();
|
|
2760
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactMenu.Menu.Positioner, {
|
|
2761
|
+
ref: ref,
|
|
2762
|
+
className: clsx(classNames.positioner, className),
|
|
2763
|
+
...props
|
|
2764
|
+
});
|
|
2765
|
+
});
|
|
2766
|
+
MenuPositioner.displayName = "MenuPositioner";
|
|
2767
|
+
const MenuContent = withContext$5(reactMenu.Menu.Content, "content");
|
|
2768
|
+
const MenuScrollArea = withContext$5(withStateProps$3(Primitive.div), "scrollArea");
|
|
2769
|
+
withContext$5(reactMenu.Menu.Group, "group");
|
|
2770
|
+
withContext$5(reactMenu.Menu.GroupLabel, "groupLabel");
|
|
2771
|
+
const MenuItem = /*#__PURE__*/ React__namespace.forwardRef(({ className: propClassName, ...props }, ref)=>{
|
|
2772
|
+
const [variantProps, otherProps] = menuItem.menuItem.splitVariantProps(props);
|
|
2773
|
+
const parentProps = useItemProps$1();
|
|
2774
|
+
const classNames = menuItem.menuItem({
|
|
2775
|
+
...parentProps,
|
|
2776
|
+
...variantProps
|
|
2777
|
+
});
|
|
2778
|
+
return /*#__PURE__*/ jsxRuntime.jsx(ItemClassNamesProvider$1, {
|
|
2779
|
+
value: classNames,
|
|
2780
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(reactMenu.Menu.Item, {
|
|
2781
|
+
ref: ref,
|
|
2782
|
+
className: clsx(classNames.root, propClassName),
|
|
2783
|
+
...otherProps
|
|
2784
|
+
})
|
|
2785
|
+
});
|
|
2786
|
+
});
|
|
2787
|
+
MenuItem.displayName = "MenuItem";
|
|
2788
|
+
withItemContext$1(withItemStateProps$1(Primitive.div), "body");
|
|
2789
|
+
const MenuItemLabel = withItemContext$1(withItemStateProps$1(Primitive.span), "label");
|
|
2790
|
+
withItemContext$1(withItemStateProps$1(Primitive.span), "description");
|
|
2791
|
+
|
|
2792
|
+
const { withProvider: withProvider$2, withContext: withContext$4 } = createSlotRecipeContext(avatar.avatar);
|
|
2683
2793
|
const AvatarRoot = withProvider$2(reactImage.Image.Root, "root");
|
|
2684
|
-
const AvatarImage = withContext$
|
|
2685
|
-
const AvatarFallback = withContext$
|
|
2686
|
-
withContext$
|
|
2794
|
+
const AvatarImage = withContext$4(reactImage.Image.Content, "image");
|
|
2795
|
+
const AvatarFallback = withContext$4(reactImage.Image.Fallback, "fallback");
|
|
2796
|
+
withContext$4(Primitive.div, "badge");
|
|
2687
2797
|
|
|
2688
2798
|
const Badge = /*#__PURE__*/ React.forwardRef(({ className, children, ...props }, ref)=>{
|
|
2689
2799
|
const [variantProps, restProps] = badge.badge.splitVariantProps(props);
|
|
@@ -3227,6 +3337,141 @@ function RatingCell({ value, maxRating = 5 }) {
|
|
|
3227
3337
|
});
|
|
3228
3338
|
}
|
|
3229
3339
|
|
|
3340
|
+
/** Clear is withheld for `chip-list`: that column already owns its own per-tag remove
|
|
3341
|
+
* affordance (`ChipListEditor`) and commits a JSON-STRINGIFIED array through `onEdit`
|
|
3342
|
+
* (`DataTable.chips.test.tsx`'s own `TagsHarness` -- and this package's own Storybook
|
|
3343
|
+
* demo, `CellFeaturesDemo`, does exactly `JSON.parse(value)` on commit) -- committing
|
|
3344
|
+
* a bare `""` through that same path throws in the consumer's `onEdit`, it doesn't
|
|
3345
|
+
* clear anything. Every OTHER editable shape's commit value is a plain string
|
|
3346
|
+
* (`"true"`/`"false"`, a stringified rating, an option's own `value`, free text) that
|
|
3347
|
+
* a consumer's `onEdit` already has to accept a possibly-empty version of. */ function isClearableEditableCell(column) {
|
|
3348
|
+
return !!column.editable && column.type !== "chip-list";
|
|
3349
|
+
}
|
|
3350
|
+
/** Paste is narrower still -- restricted to a PLAIN `editable` column (no `editor`,
|
|
3351
|
+
* and not one of the always-live widget types) whose committed value IS the raw
|
|
3352
|
+
* text/number a user typed. `select`/`reference`/`actor` expect one of THEIR OWN
|
|
3353
|
+
* option values (not arbitrary clipboard text), `switch`/`rating`/`checkbox` are
|
|
3354
|
+
* always-live widgets with their own encoding, and `chip-list` is excluded for the
|
|
3355
|
+
* same JSON reason `isClearableEditableCell` documents above. This is the task's own
|
|
3356
|
+
* "only for simple editable text/number cells" guard -- committing pasted text
|
|
3357
|
+
* through any of the excluded shapes would corrupt the row rather than edit it
|
|
3358
|
+
* (crispy-seed's own #1094 lesson: never assume an editor's commit shape).
|
|
3359
|
+
*/ function isSimpleEditableCell(column) {
|
|
3360
|
+
if (!column.editable) return false;
|
|
3361
|
+
if (column.editor) return false;
|
|
3362
|
+
if (column.type === "chip-list" || column.type === "checkbox" || column.type === "rating") {
|
|
3363
|
+
return false;
|
|
3364
|
+
}
|
|
3365
|
+
return true;
|
|
3366
|
+
}
|
|
3367
|
+
/** Copy's own text representation -- deliberately mirrors `DisplayCellContent`'s
|
|
3368
|
+
* (body-cells.tsx) switch closely enough to read the same as what's on screen, but
|
|
3369
|
+
* returns a plain string (`navigator.clipboard.writeText`) rather than JSX. Not
|
|
3370
|
+
* exported -- it exists only to feed Copy, not as a general-purpose formatter. */ function cellValueAsText(column, value, locale) {
|
|
3371
|
+
if (value == null) return "";
|
|
3372
|
+
switch(column.type){
|
|
3373
|
+
case "entity":
|
|
3374
|
+
if (typeof value === "object") return String(value.name ?? "");
|
|
3375
|
+
return String(value);
|
|
3376
|
+
case "tags":
|
|
3377
|
+
case "chip-list":
|
|
3378
|
+
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
3379
|
+
case "number":
|
|
3380
|
+
return typeof value === "number" ? String(formatNumberCell(value, locale) ?? "") : String(value);
|
|
3381
|
+
case "currency":
|
|
3382
|
+
return typeof value === "number" ? String(formatCurrencyCell(value, column.symbol ?? "$", locale) ?? "") : String(value);
|
|
3383
|
+
case "date":
|
|
3384
|
+
return String(formatDateCell(value, locale) ?? "");
|
|
3385
|
+
case "datetime":
|
|
3386
|
+
return String(formatDateTimeCell(value, locale) ?? "");
|
|
3387
|
+
case "checkbox":
|
|
3388
|
+
return value === true || value === "true" ? "true" : "false";
|
|
3389
|
+
default:
|
|
3390
|
+
return String(value);
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
/**
|
|
3394
|
+
* One cell's right-click menu -- mounted by `body-cells.tsx`'s `DataTableBodyCell`
|
|
3395
|
+
* only while actually open (the same "don't keep an unused floating-ui instance alive
|
|
3396
|
+
* per cell" reasoning as that file's own portaled chip-list popover), so this never
|
|
3397
|
+
* costs anything for the row×column cells a user never right-clicks.
|
|
3398
|
+
*/ function CellContextMenu({ column, row, value, locale, point, open, onOpenChange, onCommit, onViewEditHistory, cellContextMenuItems }) {
|
|
3399
|
+
const clearable = isClearableEditableCell(column);
|
|
3400
|
+
const pasteable = isSimpleEditableCell(column);
|
|
3401
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(MenuRoot, {
|
|
3402
|
+
open: open,
|
|
3403
|
+
onOpenChange: onOpenChange,
|
|
3404
|
+
placement: "bottom-start",
|
|
3405
|
+
strategy: "fixed",
|
|
3406
|
+
gutter: 2,
|
|
3407
|
+
children: [
|
|
3408
|
+
/*#__PURE__*/ jsxRuntime.jsx(MenuAnchor, {
|
|
3409
|
+
"aria-hidden": true,
|
|
3410
|
+
style: {
|
|
3411
|
+
position: "fixed",
|
|
3412
|
+
top: point.y,
|
|
3413
|
+
left: point.x,
|
|
3414
|
+
width: 0,
|
|
3415
|
+
height: 0,
|
|
3416
|
+
pointerEvents: "none"
|
|
3417
|
+
}
|
|
3418
|
+
}),
|
|
3419
|
+
/*#__PURE__*/ jsxRuntime.jsx(MenuPositioner, {
|
|
3420
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(MenuContent, {
|
|
3421
|
+
style: {
|
|
3422
|
+
minWidth: 180
|
|
3423
|
+
},
|
|
3424
|
+
children: /*#__PURE__*/ jsxRuntime.jsxs(MenuScrollArea, {
|
|
3425
|
+
children: [
|
|
3426
|
+
/*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
|
|
3427
|
+
onClick: ()=>{
|
|
3428
|
+
const text = cellValueAsText(column, value, locale);
|
|
3429
|
+
// Best-effort: an insecure context or a denied permission rejects
|
|
3430
|
+
// this silently (no `MenuItem` state depends on the outcome) --
|
|
3431
|
+
// there's nothing else for a plain "Copy" item to do about a
|
|
3432
|
+
// browser that refused the write.
|
|
3433
|
+
void navigator.clipboard?.writeText?.(text);
|
|
3434
|
+
},
|
|
3435
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
|
|
3436
|
+
children: "Copy"
|
|
3437
|
+
})
|
|
3438
|
+
}),
|
|
3439
|
+
pasteable && /*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
|
|
3440
|
+
onClick: ()=>{
|
|
3441
|
+
void navigator.clipboard?.readText?.().then((text)=>onCommit(text)).catch(()=>{
|
|
3442
|
+
// Clipboard read denied/unavailable -- best-effort, same
|
|
3443
|
+
// reasoning as Copy above.
|
|
3444
|
+
});
|
|
3445
|
+
},
|
|
3446
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
|
|
3447
|
+
children: "Paste"
|
|
3448
|
+
})
|
|
3449
|
+
}),
|
|
3450
|
+
clearable && /*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
|
|
3451
|
+
onClick: ()=>onCommit(""),
|
|
3452
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
|
|
3453
|
+
children: "Clear value"
|
|
3454
|
+
})
|
|
3455
|
+
}),
|
|
3456
|
+
onViewEditHistory && /*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
|
|
3457
|
+
onClick: ()=>onViewEditHistory(row, column.key),
|
|
3458
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
|
|
3459
|
+
children: "View edit history"
|
|
3460
|
+
})
|
|
3461
|
+
}),
|
|
3462
|
+
cellContextMenuItems?.({
|
|
3463
|
+
row,
|
|
3464
|
+
column,
|
|
3465
|
+
value
|
|
3466
|
+
})
|
|
3467
|
+
]
|
|
3468
|
+
})
|
|
3469
|
+
})
|
|
3470
|
+
})
|
|
3471
|
+
]
|
|
3472
|
+
});
|
|
3473
|
+
}
|
|
3474
|
+
|
|
3230
3475
|
/** Fallback width (px) used to compute a pinned column's cumulative sticky offset when
|
|
3231
3476
|
* it has no explicit `width` and hasn't been drag-resized -- pinning needs a STATIC
|
|
3232
3477
|
* number to put in an inline `insetInlineStart`, and `table-layout: fixed` only
|
|
@@ -3308,10 +3553,25 @@ function RatingCell({ value, maxRating = 5 }) {
|
|
|
3308
3553
|
width,
|
|
3309
3554
|
pinned,
|
|
3310
3555
|
pinOffset,
|
|
3311
|
-
pinnedEdge: false
|
|
3556
|
+
pinnedEdge: false,
|
|
3557
|
+
stickyLastTarget: false
|
|
3312
3558
|
};
|
|
3313
3559
|
});
|
|
3314
3560
|
if (pinnedCount > 0) entries[pinnedCount - 1].pinnedEdge = true;
|
|
3561
|
+
// `stickyLast` sticks the `actions`-flagged column specifically -- not whichever
|
|
3562
|
+
// column merely landed last in render order. Without this, `reconcileColumnOrder`
|
|
3563
|
+
// appending a brand-new column past `actions` (this file's own `<colgroup>` doc
|
|
3564
|
+
// comment on why order must stay in lockstep) silently moved the sticky-right
|
|
3565
|
+
// treatment onto that new column instead, stranding `actions` in the middle of the
|
|
3566
|
+
// table -- a real consumer hit this. Falls back to the genuine last entry when no
|
|
3567
|
+
// column is flagged `actions` at all, matching `stickyLast`'s original single-
|
|
3568
|
+
// column behavior.
|
|
3569
|
+
if (entries.length > 0) {
|
|
3570
|
+
const actionsColumn = columns.find((column)=>column.actions);
|
|
3571
|
+
const actionsIndex = actionsColumn ? entries.findIndex((entry)=>entry.column.key === actionsColumn.key) : -1;
|
|
3572
|
+
const stickyLastIndex = actionsIndex !== -1 ? actionsIndex : entries.length - 1;
|
|
3573
|
+
entries[stickyLastIndex].stickyLastTarget = true;
|
|
3574
|
+
}
|
|
3315
3575
|
return entries;
|
|
3316
3576
|
}, [
|
|
3317
3577
|
columns,
|
|
@@ -3351,9 +3611,12 @@ function RatingCell({ value, maxRating = 5 }) {
|
|
|
3351
3611
|
}
|
|
3352
3612
|
/** Sticky positioning for one DATA cell (header, body, or ColumnCalc footer) -- pinned-
|
|
3353
3613
|
* left (this column's own `pinOffset`, `data-sticky-edge` only on the group's
|
|
3354
|
-
* trailing-most member) takes priority over sticky-right (`stickyLast`,
|
|
3355
|
-
*
|
|
3356
|
-
* one edge.
|
|
3614
|
+
* trailing-most member) takes priority over sticky-right (`stickyLast`, the
|
|
3615
|
+
* `actions`-flagged column when one exists, else the genuine last VISIBLE column)
|
|
3616
|
+
* since a column can only stick to one edge. Reads `entry.stickyLastTarget`
|
|
3617
|
+
* (`useEffectiveColumns`) rather than an `isLast` index the caller computes itself --
|
|
3618
|
+
* that index is just "last in render order", which is exactly what stranded a
|
|
3619
|
+
* reordered-past `actions` column in the first place. */ function pinnedCellProps(entry, stickyLast) {
|
|
3357
3620
|
if (entry.pinned) {
|
|
3358
3621
|
return {
|
|
3359
3622
|
"data-sticky": "",
|
|
@@ -3365,7 +3628,7 @@ function RatingCell({ value, maxRating = 5 }) {
|
|
|
3365
3628
|
}
|
|
3366
3629
|
};
|
|
3367
3630
|
}
|
|
3368
|
-
if (stickyLast &&
|
|
3631
|
+
if (stickyLast && entry.stickyLastTarget) {
|
|
3369
3632
|
return {
|
|
3370
3633
|
"data-sticky": "",
|
|
3371
3634
|
"data-sticky-edge-end": "",
|
|
@@ -3385,11 +3648,11 @@ function RatingCell({ value, maxRating = 5 }) {
|
|
|
3385
3648
|
// recipe, so a per-instance variant can override the root's default.
|
|
3386
3649
|
const { ClassNamesProvider: TriggerClassNamesProvider, PropsProvider: TriggerPropsProvider, useProps: useTriggerProps, withContext: withTriggerContext, useClassNames: useTriggerClassNames } = createSlotRecipeContext(selectTrigger.selectTrigger);
|
|
3387
3650
|
const { ClassNamesProvider: ContentClassNamesProvider, withContext: withContentContext, useClassNames: useContentClassNames } = createSlotRecipeContext(select.select);
|
|
3388
|
-
const { ClassNamesProvider: ItemClassNamesProvider
|
|
3389
|
-
const withStateProps$
|
|
3651
|
+
const { ClassNamesProvider: ItemClassNamesProvider, PropsProvider: ItemPropsProvider, useProps: useItemProps, withContext: withItemContext, useClassNames: useItemClassNames } = createSlotRecipeContext(selectItem.selectItem);
|
|
3652
|
+
const withStateProps$2 = createWithStateProps([
|
|
3390
3653
|
reactSelect.useSelectContext
|
|
3391
3654
|
]);
|
|
3392
|
-
const withItemStateProps
|
|
3655
|
+
const withItemStateProps = createWithStateProps([
|
|
3393
3656
|
reactSelect.useSelectItemContext
|
|
3394
3657
|
]);
|
|
3395
3658
|
// NOTE: `gutter` and `overflowPadding` are specified in Rootage (`select.yaml`,
|
|
@@ -3410,7 +3673,7 @@ const SelectRoot = (props)=>{
|
|
|
3410
3673
|
value: contentClassNames,
|
|
3411
3674
|
children: /*#__PURE__*/ jsxRuntime.jsx(TriggerPropsProvider, {
|
|
3412
3675
|
value: triggerVariantProps,
|
|
3413
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(ItemPropsProvider
|
|
3676
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(ItemPropsProvider, {
|
|
3414
3677
|
value: itemVariantProps,
|
|
3415
3678
|
children: /*#__PURE__*/ jsxRuntime.jsx(reactSelect.Select.Root, {
|
|
3416
3679
|
...otherProps
|
|
@@ -3450,8 +3713,8 @@ const SelectTrigger = /*#__PURE__*/ React__namespace.forwardRef(({ className, ..
|
|
|
3450
3713
|
});
|
|
3451
3714
|
});
|
|
3452
3715
|
SelectTrigger.displayName = "SelectTrigger";
|
|
3453
|
-
const SelectValue = withTriggerContext(withStateProps$
|
|
3454
|
-
const SelectPlaceholder = withTriggerContext(withStateProps$
|
|
3716
|
+
const SelectValue = withTriggerContext(withStateProps$2(reactSelect.Select.Value), "value");
|
|
3717
|
+
const SelectPlaceholder = withTriggerContext(withStateProps$2(reactSelect.Select.Placeholder), "placeholder");
|
|
3455
3718
|
const SelectPrefixIcon = /*#__PURE__*/ React__namespace.forwardRef(({ fallback, className, ...otherProps }, ref)=>{
|
|
3456
3719
|
const { selectedItem, stateProps } = reactSelect.useSelectContext();
|
|
3457
3720
|
const classNames = useTriggerClassNames();
|
|
@@ -3466,7 +3729,7 @@ const SelectPrefixIcon = /*#__PURE__*/ React__namespace.forwardRef(({ fallback,
|
|
|
3466
3729
|
});
|
|
3467
3730
|
});
|
|
3468
3731
|
SelectPrefixIcon.displayName = "SelectPrefixIcon";
|
|
3469
|
-
const SelectSuffixIcon = withTriggerContext(withStateProps$
|
|
3732
|
+
const SelectSuffixIcon = withTriggerContext(withStateProps$2(InternalIcon), "suffixIcon");
|
|
3470
3733
|
const SelectPositioner = /*#__PURE__*/ React__namespace.forwardRef(({ className, ...props }, ref)=>{
|
|
3471
3734
|
const classNames = useContentClassNames();
|
|
3472
3735
|
return /*#__PURE__*/ jsxRuntime.jsx(reactSelect.Select.Positioner, {
|
|
@@ -3497,12 +3760,12 @@ withContentContext(reactSelect.Select.Group, "group");
|
|
|
3497
3760
|
withContentContext(reactSelect.Select.GroupLabel, "groupLabel");
|
|
3498
3761
|
const SelectItem = /*#__PURE__*/ React__namespace.forwardRef(({ prefixIcon, className, ...props }, ref)=>{
|
|
3499
3762
|
const [variantProps, otherProps] = selectItem.selectItem.splitVariantProps(props);
|
|
3500
|
-
const rootProps = useItemProps
|
|
3763
|
+
const rootProps = useItemProps();
|
|
3501
3764
|
const classNames = selectItem.selectItem({
|
|
3502
3765
|
...rootProps,
|
|
3503
3766
|
...variantProps
|
|
3504
3767
|
});
|
|
3505
|
-
return /*#__PURE__*/ jsxRuntime.jsx(ItemClassNamesProvider
|
|
3768
|
+
return /*#__PURE__*/ jsxRuntime.jsx(ItemClassNamesProvider, {
|
|
3506
3769
|
value: classNames,
|
|
3507
3770
|
children: /*#__PURE__*/ jsxRuntime.jsx(reactSelect.Select.Item, {
|
|
3508
3771
|
ref: ref,
|
|
@@ -3527,7 +3790,7 @@ const SelectItemPrefixIcon = /*#__PURE__*/ React__namespace.forwardRef(({ svg: s
|
|
|
3527
3790
|
});
|
|
3528
3791
|
});
|
|
3529
3792
|
SelectItemPrefixIcon.displayName = "SelectItemPrefixIcon";
|
|
3530
|
-
const SelectItemBody = withItemContext
|
|
3793
|
+
const SelectItemBody = withItemContext(withItemStateProps(Primitive.div), "body");
|
|
3531
3794
|
const SelectItemLabel = /*#__PURE__*/ React__namespace.forwardRef(({ children, className, ...otherProps }, ref)=>{
|
|
3532
3795
|
const { label, stateProps } = reactSelect.useSelectItemContext();
|
|
3533
3796
|
const classNames = useItemClassNames();
|
|
@@ -3542,7 +3805,7 @@ const SelectItemLabel = /*#__PURE__*/ React__namespace.forwardRef(({ children, c
|
|
|
3542
3805
|
});
|
|
3543
3806
|
});
|
|
3544
3807
|
SelectItemLabel.displayName = "SelectItemLabel";
|
|
3545
|
-
withItemContext
|
|
3808
|
+
withItemContext(withItemStateProps(Primitive.span), "description");
|
|
3546
3809
|
const SelectItemIndicator = /*#__PURE__*/ React__namespace.forwardRef(({ selected: selectedSvg, unselected: unselectedSvg, className, ...otherProps }, ref)=>{
|
|
3547
3810
|
const { isSelected, stateProps } = reactSelect.useSelectItemContext();
|
|
3548
3811
|
const classNames = useItemClassNames();
|
|
@@ -3574,9 +3837,9 @@ const SelectHiddenSelect = /*#__PURE__*/ React__namespace.forwardRef((props, ref
|
|
|
3574
3837
|
});
|
|
3575
3838
|
SelectHiddenSelect.displayName = "SelectHiddenSelect";
|
|
3576
3839
|
|
|
3577
|
-
const { withContext: withContext$
|
|
3840
|
+
const { withContext: withContext$3, ClassNamesProvider: ClassNamesProvider$1 } = createSlotRecipeContext(_switch.switchStyle);
|
|
3578
3841
|
const { withContext: withControlContext, PropsProvider: ControlPropsProvider, withProvider: withControlProvider } = createSlotRecipeContext(switchmark.switchmark);
|
|
3579
|
-
const withStateProps$
|
|
3842
|
+
const withStateProps$1 = createWithStateProps([
|
|
3580
3843
|
reactSwitch.useSwitchContext
|
|
3581
3844
|
]);
|
|
3582
3845
|
const SwitchRoot = /*#__PURE__*/ React__namespace.default.forwardRef(({ className, ...props }, ref)=>{
|
|
@@ -3587,7 +3850,7 @@ const SwitchRoot = /*#__PURE__*/ React__namespace.default.forwardRef(({ classNam
|
|
|
3587
3850
|
const classNames = _switch.switchStyle(switchVariantProps);
|
|
3588
3851
|
return /*#__PURE__*/ jsxRuntime.jsx(ControlPropsProvider, {
|
|
3589
3852
|
value: switchmarkVariantProps,
|
|
3590
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(ClassNamesProvider$
|
|
3853
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(ClassNamesProvider$1, {
|
|
3591
3854
|
value: classNames,
|
|
3592
3855
|
children: /*#__PURE__*/ jsxRuntime.jsx(reactSwitch.Switch.Root, {
|
|
3593
3856
|
ref: ref,
|
|
@@ -3600,20 +3863,20 @@ const SwitchRoot = /*#__PURE__*/ React__namespace.default.forwardRef(({ classNam
|
|
|
3600
3863
|
SwitchRoot.displayName = "SwitchRoot";
|
|
3601
3864
|
const SwitchControl = withScaleFeedback(withControlProvider(reactSwitch.Switch.Control, "root"));
|
|
3602
3865
|
const SwitchThumb = withControlContext(reactSwitch.Switch.Thumb, "thumb");
|
|
3603
|
-
withContext$
|
|
3866
|
+
withContext$3(withStateProps$1(Primitive.span), "label");
|
|
3604
3867
|
const SwitchHiddenInput = reactSwitch.Switch.HiddenInput;
|
|
3605
3868
|
|
|
3606
3869
|
// src/use-layout-effect.tsx
|
|
3607
3870
|
var useLayoutEffect2 = globalThis?.document ? React__namespace.useLayoutEffect : ()=>{};
|
|
3608
3871
|
|
|
3609
|
-
const { withProvider: withProvider$1, withContext: withContext$
|
|
3872
|
+
const { withProvider: withProvider$1, withContext: withContext$2, useClassNames: useClassNames$1 } = createSlotRecipeContext(textInput.textInput);
|
|
3610
3873
|
const withFieldStateProps = createWithStateProps([
|
|
3611
3874
|
{
|
|
3612
3875
|
useContext: reactField.useFieldContext,
|
|
3613
3876
|
strict: false
|
|
3614
3877
|
}
|
|
3615
3878
|
]);
|
|
3616
|
-
const withStateProps
|
|
3879
|
+
const withStateProps = createWithStateProps([
|
|
3617
3880
|
reactTextField.useTextFieldContext,
|
|
3618
3881
|
{
|
|
3619
3882
|
useContext: reactField.useFieldContext,
|
|
@@ -3621,12 +3884,12 @@ const withStateProps$1 = createWithStateProps([
|
|
|
3621
3884
|
}
|
|
3622
3885
|
]);
|
|
3623
3886
|
const TextFieldRoot = withProvider$1(withFieldStateProps(reactTextField.TextField.Root), "root");
|
|
3624
|
-
withContext$
|
|
3625
|
-
withContext$
|
|
3626
|
-
withContext$
|
|
3627
|
-
withContext$
|
|
3887
|
+
withContext$2(withStateProps(InternalIcon), "prefixIcon");
|
|
3888
|
+
withContext$2(withStateProps(Primitive.span), "prefixText");
|
|
3889
|
+
withContext$2(withStateProps(InternalIcon), "suffixIcon");
|
|
3890
|
+
withContext$2(withStateProps(Primitive.span), "suffixText");
|
|
3628
3891
|
const TextFieldInput = /*#__PURE__*/ React.forwardRef(({ className, ...otherProps }, ref)=>{
|
|
3629
|
-
const classNames = useClassNames$
|
|
3892
|
+
const classNames = useClassNames$1();
|
|
3630
3893
|
const textFieldContext = reactTextField.useTextFieldContext();
|
|
3631
3894
|
const fieldContext = reactField.useFieldContext({
|
|
3632
3895
|
strict: false
|
|
@@ -3644,7 +3907,7 @@ const TextFieldInput = /*#__PURE__*/ React.forwardRef(({ className, ...otherProp
|
|
|
3644
3907
|
});
|
|
3645
3908
|
TextFieldInput.displayName = "TextFieldInput";
|
|
3646
3909
|
const TextFieldTextarea = /*#__PURE__*/ React.forwardRef(({ className, autoresize = true, ...otherProps }, ref)=>{
|
|
3647
|
-
const classNames = useClassNames$
|
|
3910
|
+
const classNames = useClassNames$1();
|
|
3648
3911
|
const textFieldContext = reactTextField.useTextFieldContext();
|
|
3649
3912
|
const fieldContext = reactField.useFieldContext({
|
|
3650
3913
|
strict: false
|
|
@@ -3701,7 +3964,7 @@ const TextFieldTextarea = /*#__PURE__*/ React.forwardRef(({ className, autoresiz
|
|
|
3701
3964
|
});
|
|
3702
3965
|
TextFieldTextarea.displayName = "TextFieldTextarea";
|
|
3703
3966
|
|
|
3704
|
-
__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:not([data-editable]){user-select:none}.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-overlay-open]{overflow:visible;z-index:20}.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;transition:opacity .15s}tr:hover .seed-data-table__entityActions{opacity:1}.seed-data-table__entityActions:focus-within{opacity:1}.seed-data-table__entityAction{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin:0;padding:2px;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;transition:background-color .2s,color .2s,box-shadow .2s}.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__chip{box-sizing:border-box;display:inline-flex;align-items:center;flex-shrink:0;max-width:100%;height:22px;padding:0 4px;border-radius:7px;font-size:10px;font-weight:var(--seed-font-weight-regular);line-height:15px;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__chipList{position:relative;display:flex;align-items:center;flex-wrap:nowrap;gap:3px;overflow:hidden;min-width:0;width:100%}.seed-data-table__chipOverflow{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;height:20px;padding:0 4px;border-radius:6px;background-color:#f6f7f7;color:#000;font-size:10px;font-weight:var(--seed-font-weight-regular);line-height:15px;white-space:nowrap}.seed-data-table__chipListEditor{display:flex;align-items:center;flex-wrap:wrap;gap:3px;min-width:0;width:100%}.seed-data-table__chipRemove{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:12px;height:12px;margin:0;margin-inline-start:2px;padding:0;border:none;border-radius:999px;background:0 0;color:inherit;opacity:.6;cursor:pointer;transition:opacity .12s,background-color .12s}.seed-data-table__chipRemove:hover{opacity:1;background-color:rgba(0,0,0,.08)}.seed-data-table__chipInput{flex:1 1 auto;min-width:40px;height:22px;margin:0;padding:0;border:none;outline:0;background:0 0;font-family:inherit;font-size:var(--seed-font-size-t4);color:var(--seed-color-fg-neutral);letter-spacing:-.14px}.seed-data-table__expandOverlay{box-sizing:border-box;position:absolute;top:-1px;inset-inline-start:-1px;inset-inline-end:-1px;z-index:10;min-height:calc(100% + 2px);display:flex;align-items:flex-start;padding-inline:var(--seed-dimension-x3);padding-block:var(--seed-dimension-x3);background-color:var(--seed-color-bg-layer-floating);border-radius:4px;box-shadow:none;border:1px solid #266df0;color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);letter-spacing:-.14px;cursor:default}.seed-data-table__expandOverlayText{width:100%;min-width:0;white-space:normal;word-break:break-word}.seed-data-table__cellSuffixRow{display:flex;align-items:center;gap:4px;min-width:0;width:100%}.seed-data-table__cellSuffixText{flex:1 1 0%;min-width:0;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__cellSuffixIcon{flex-shrink:0;display:inline-flex;align-items:center;color:color-mix(in srgb,var(--seed-color-fg-neutral) 55%,transparent)}.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))}");
|
|
3967
|
+
__insertCSS(".seed-data-table__root{box-sizing:border-box;position:relative;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:not([data-editable]){user-select:none}.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-overlay-open]{overflow:visible;z-index:20}.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;transition:opacity .15s}tr:hover .seed-data-table__entityActions{opacity:1}.seed-data-table__entityActions:focus-within{opacity:1}.seed-data-table__entityAction{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin:0;padding:2px;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;transition:background-color .2s,color .2s,box-shadow .2s}.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__chip{box-sizing:border-box;display:inline-flex;align-items:center;flex-shrink:0;max-width:100%;height:22px;padding:0 4px;border-radius:7px;font-size:10px;font-weight:var(--seed-font-weight-regular);line-height:15px;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__chipList{position:relative;display:flex;align-items:center;flex-wrap:nowrap;gap:3px;overflow:hidden;min-width:0;width:100%}.seed-data-table__chipOverflow{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;height:20px;padding:0 4px;border-radius:6px;background-color:#f6f7f7;color:#000;font-size:10px;font-weight:var(--seed-font-weight-regular);line-height:15px;white-space:nowrap}.seed-data-table__chipListEditor{display:flex;align-items:center;flex-wrap:wrap;gap:3px;min-width:0;width:100%}.seed-data-table__chipRemove{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:12px;height:12px;margin:0;margin-inline-start:2px;padding:0;border:none;border-radius:999px;background:0 0;color:inherit;opacity:.6;cursor:pointer;transition:opacity .12s,background-color .12s}.seed-data-table__chipRemove:hover{opacity:1;background-color:rgba(0,0,0,.08)}.seed-data-table__chipInput{flex:1 1 auto;min-width:40px;height:22px;margin:0;padding:0;border:none;outline:0;background:0 0;font-family:inherit;font-size:var(--seed-font-size-t4);color:var(--seed-color-fg-neutral);letter-spacing:-.14px}.seed-data-table__expandOverlay{box-sizing:border-box;position:absolute;top:-1px;inset-inline-start:-1px;inset-inline-end:-1px;z-index:10;min-height:calc(100% + 2px);display:flex;align-items:flex-start;padding-inline:var(--seed-dimension-x3);padding-block:var(--seed-dimension-x3);background-color:var(--seed-color-bg-layer-floating);border-radius:4px;box-shadow:none;border:1px solid #266df0;color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);letter-spacing:-.14px;cursor:default}.seed-data-table__expandOverlayText{width:100%;min-width:0;white-space:normal;word-break:break-word}.seed-data-table__cellSuffixRow{display:flex;align-items:center;gap:4px;min-width:0;width:100%}.seed-data-table__cellSuffixText{flex:1 1 0%;min-width:0;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__cellSuffixIcon{flex-shrink:0;display:inline-flex;align-items:center;color:color-mix(in srgb,var(--seed-color-fg-neutral) 55%,transparent)}.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__bulkBar{box-sizing:border-box;position:absolute;inset-inline-start:50%;transform:translateX(-50%);bottom:var(--seed-dimension-x4);z-index:30;display:flex;align-items:center;gap:var(--seed-dimension-x3);min-height:36px;padding-inline:var(--seed-dimension-x3_5);padding-block:var(--seed-dimension-x2);border-radius:var(--seed-radius-full);box-shadow:var(--seed-shadow-s3);background-color:var(--seed-color-bg-layer-floating);color:var(--seed-color-fg-neutral);font-family:inherit;font-size:var(--seed-font-size-t4);font-weight:var(--seed-font-weight-medium);white-space:nowrap}.seed-data-table__bulkBarCount{flex-shrink:0;color:var(--seed-color-fg-neutral);font-variant-numeric:tabular-nums}.seed-data-table__bulkBarClear{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:20px;height:20px;margin:0;padding:2px;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;transition:background-color .2s,color .2s}.seed-data-table__bulkBarClear:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 8%,transparent);color:var(--seed-color-fg-neutral)}.seed-data-table__bulkBarActions{display:flex;align-items:center;flex-shrink:0;gap:var(--seed-dimension-x3);padding-inline-start:var(--seed-dimension-x3);border-inline-start:1px solid color-mix(in srgb,var(--seed-color-fg-neutral) 16%,transparent)}.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))}");
|
|
3705
3968
|
|
|
3706
3969
|
const createClassName = (className, variants, compoundVariants = [])=>{
|
|
3707
3970
|
const variantKeys = Object.keys(variants);
|
|
@@ -3895,6 +4158,22 @@ const dataTableSlotNames = [
|
|
|
3895
4158
|
[
|
|
3896
4159
|
"selectionCell",
|
|
3897
4160
|
"seed-data-table__selectionCell"
|
|
4161
|
+
],
|
|
4162
|
+
[
|
|
4163
|
+
"bulkBar",
|
|
4164
|
+
"seed-data-table__bulkBar"
|
|
4165
|
+
],
|
|
4166
|
+
[
|
|
4167
|
+
"bulkBarCount",
|
|
4168
|
+
"seed-data-table__bulkBarCount"
|
|
4169
|
+
],
|
|
4170
|
+
[
|
|
4171
|
+
"bulkBarClear",
|
|
4172
|
+
"seed-data-table__bulkBarClear"
|
|
4173
|
+
],
|
|
4174
|
+
[
|
|
4175
|
+
"bulkBarActions",
|
|
4176
|
+
"seed-data-table__bulkBarActions"
|
|
3898
4177
|
]
|
|
3899
4178
|
];
|
|
3900
4179
|
const defaultVariant$6 = {
|
|
@@ -3932,7 +4211,7 @@ Object.assign(dataTable, {
|
|
|
3932
4211
|
// other file (`DataTable.tsx`, `column-menu.tsx`, `resize.tsx`, `column-calc.tsx`,
|
|
3933
4212
|
// `toolbar.tsx`, `body-cells.tsx`, `editors.tsx`) imports its exports from here rather
|
|
3934
4213
|
// than re-deriving its own.
|
|
3935
|
-
const { ClassNamesProvider
|
|
4214
|
+
const { ClassNamesProvider, withContext: withContext$1, useClassNames } = createSlotRecipeContext(dataTable);
|
|
3936
4215
|
|
|
3937
4216
|
/**
|
|
3938
4217
|
* The pure filter itself, split out of `useSelectSearch` below so it can be
|
|
@@ -4508,26 +4787,87 @@ function ChipListEditor({ column, value, pending, onCommit, classNames }) {
|
|
|
4508
4787
|
}));
|
|
4509
4788
|
}
|
|
4510
4789
|
////////////////////////////////////////////////////////////////////////////////////
|
|
4511
|
-
// -- Feature C (#12): cell-expand "show full content" overlay --
|
|
4512
|
-
//
|
|
4513
|
-
//
|
|
4514
|
-
//
|
|
4515
|
-
//
|
|
4516
|
-
//
|
|
4517
|
-
//
|
|
4518
|
-
//
|
|
4519
|
-
|
|
4520
|
-
|
|
4790
|
+
// -- Feature C (#12): cell-expand "show full content" overlay -- a box that wraps
|
|
4791
|
+
// whatever a truncated cell would otherwise show inline: an editable column's OWN
|
|
4792
|
+
// editor node (unchanged, just relocated into this box instead of rendered flush in
|
|
4793
|
+
// the 36px row) for the editable case, or the plain full value for a read-only one.
|
|
4794
|
+
// `body-cells.tsx` decides WHEN to render this (a click on a cell whose content is
|
|
4795
|
+
// actually truncated, `truncate.ts`'s `isCellTruncated`); this component only
|
|
4796
|
+
// supplies the box.
|
|
4797
|
+
//
|
|
4798
|
+
// Portals to `document.body` (crispy-seed#1094's own pinned-column follow-up,
|
|
4799
|
+
// ported from the chip-list editor's popover, `body-cells.tsx`'s
|
|
4800
|
+
// `isChipListEditable` -- that one shipped this exact fix in 0.10.3) rather than
|
|
4801
|
+
// positioning `absolute` against its own cell: a `position: sticky` `<td>` clips ANY
|
|
4802
|
+
// descendant that grows past its own box, in every browser tested, regardless of
|
|
4803
|
+
// `overflow`/`z-index` on anything in between, so a pinned column's own truncated
|
|
4804
|
+
// cell used to clip this overlay's grown content instead of showing it in full. A
|
|
4805
|
+
// portal sidesteps that by not being a descendant of the sticky `<td>` at all once
|
|
4806
|
+
// mounted -- position is instead measured live off `anchorRef`'s own
|
|
4807
|
+
// `getBoundingClientRect()`, the same technique the chip-list popover already uses.
|
|
4808
|
+
function CellExpandOverlay({ className, anchorRef, contentRef, children }) {
|
|
4809
|
+
const [style, setStyle] = React__namespace.useState(null);
|
|
4810
|
+
// Grows 1px past the cell's own edges in every direction, matching this box's
|
|
4811
|
+
// pre-portal `top: -1px; insetInlineStart: -1px; insetInlineEnd: -1px` (the recipe's
|
|
4812
|
+
// `expandOverlay` class, `data-table.ts`) -- hides the 1px border seam against the
|
|
4813
|
+
// cell it's expanding out of. `minHeight`/`insetInlineEnd` from that same class no
|
|
4814
|
+
// longer apply once portaled (they resolved against the `<td>` as this box's own
|
|
4815
|
+
// containing block, meaningless once it's a `position: fixed` child of `<body>`
|
|
4816
|
+
// instead -- the same override the chip-list popover's own `measurePopoverPosition`,
|
|
4817
|
+
// `body-cells.tsx`, already makes), so this overrides both explicitly.
|
|
4818
|
+
const measure = React__namespace.useCallback(()=>{
|
|
4819
|
+
const cell = anchorRef.current;
|
|
4820
|
+
if (!cell) return;
|
|
4821
|
+
const rect = cell.getBoundingClientRect();
|
|
4822
|
+
setStyle({
|
|
4823
|
+
position: "fixed",
|
|
4824
|
+
top: rect.top - 1,
|
|
4825
|
+
insetInlineStart: rect.left - 1,
|
|
4826
|
+
insetInlineEnd: "auto",
|
|
4827
|
+
width: rect.width + 2,
|
|
4828
|
+
minHeight: "auto",
|
|
4829
|
+
zIndex: 1000
|
|
4830
|
+
});
|
|
4831
|
+
}, [
|
|
4832
|
+
anchorRef
|
|
4833
|
+
]);
|
|
4834
|
+
// Measured before paint, on mount -- see this component's own prop doc comment for
|
|
4835
|
+
// why it can't just trust a caller to have measured first.
|
|
4836
|
+
React__namespace.useLayoutEffect(()=>{
|
|
4837
|
+
measure();
|
|
4838
|
+
}, [
|
|
4839
|
+
measure
|
|
4840
|
+
]);
|
|
4841
|
+
// Same capture-phase listeners as the chip-list popover's own reposition effect
|
|
4842
|
+
// (`body-cells.tsx`) -- `scroll` doesn't bubble, so the table's own horizontal/
|
|
4843
|
+
// vertical scroll container (an arbitrary ancestor, not necessarily `window` itself)
|
|
4844
|
+
// is only observable this way.
|
|
4845
|
+
React__namespace.useEffect(()=>{
|
|
4846
|
+
window.addEventListener("scroll", measure, true);
|
|
4847
|
+
window.addEventListener("resize", measure);
|
|
4848
|
+
return ()=>{
|
|
4849
|
+
window.removeEventListener("scroll", measure, true);
|
|
4850
|
+
window.removeEventListener("resize", measure);
|
|
4851
|
+
};
|
|
4852
|
+
}, [
|
|
4853
|
+
measure
|
|
4854
|
+
]);
|
|
4855
|
+
// Nothing to portal until the first measurement lands (avoids a one-frame flash at
|
|
4856
|
+
// the origin corner before `useLayoutEffect` runs).
|
|
4857
|
+
if (!style) return null;
|
|
4858
|
+
return /*#__PURE__*/ reactDom.createPortal(// `stopPropagation` -- an overlay sits on top of (and past) its own cell/row;
|
|
4521
4859
|
// a click anywhere inside it must never ALSO fire the row's own `onRowClick`,
|
|
4522
4860
|
// the same guard every other interactive cell affordance in this directory
|
|
4523
4861
|
// already applies (`LinkCell`, `EntityCell`'s preview button, editors.tsx's
|
|
4524
4862
|
// `TextEditor` root).
|
|
4525
4863
|
// biome-ignore lint/a11y/noStaticElementInteractions: not a widget -- this div never responds to interaction on ITSELF, only stops propagation of events that already occurred on a real interactive descendant (the editor/text it wraps). No role fits it because it isn't a control.
|
|
4526
4864
|
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
4865
|
+
ref: contentRef,
|
|
4527
4866
|
className: className,
|
|
4867
|
+
style: style,
|
|
4528
4868
|
onClick: (event)=>event.stopPropagation(),
|
|
4529
4869
|
children: children
|
|
4530
|
-
}));
|
|
4870
|
+
}), document.body);
|
|
4531
4871
|
}
|
|
4532
4872
|
|
|
4533
4873
|
// Row-narrowing for the toolbar's search box -- split out of DataTable.tsx the way
|
|
@@ -4623,39 +4963,37 @@ function isCellTruncated(cell) {
|
|
|
4623
4963
|
* close itself after the first tag commits, see `ChipListEditor`'s own doc
|
|
4624
4964
|
* comment).
|
|
4625
4965
|
*
|
|
4626
|
-
*
|
|
4627
|
-
*
|
|
4628
|
-
*
|
|
4629
|
-
*
|
|
4630
|
-
*
|
|
4631
|
-
* `<td>` clips ANY descendant content that grows past its own
|
|
4632
|
-
* scrollport, in EVERY browser tested, regardless of
|
|
4633
|
-
* element in between and regardless of how high its
|
|
4634
|
-
* of which is a stacking-context or overflow bug
|
|
4635
|
-
* INSIDE. A portal sidesteps it entirely by not being a
|
|
4636
|
-
* `<td>` at all once mounted.
|
|
4637
|
-
* OTHER gated editors' `CellExpandOverlay` too when their own column is pinned,
|
|
4638
|
-
* but porting all of Feature C to this same portal model is its own change,
|
|
4639
|
-
* out of scope here -- this fix is scoped to the one editor crispy-seed#1094
|
|
4640
|
-
* actually reported against a pinned column. */ function isChipListEditable(column) {
|
|
4966
|
+
* This one renders through its OWN REAL React portal to `document.body`
|
|
4967
|
+
* (`DataTableBodyCell`'s own `popoverStyle`) rather than `editors.tsx`'s shared
|
|
4968
|
+
* `CellExpandOverlay`, since its shape is different (Attio's own click-anywhere-
|
|
4969
|
+
* opens gesture, no truncation gate). `CellExpandOverlay` itself ALSO portals to
|
|
4970
|
+
* `document.body` now (ported from this exact fix) -- both exist because a
|
|
4971
|
+
* `position: sticky` `<td>` clips ANY descendant content that grows past its own
|
|
4972
|
+
* box to the table's scrollport, in EVERY browser tested, regardless of
|
|
4973
|
+
* `overflow: visible` on every element in between and regardless of how high its
|
|
4974
|
+
* `z-index` is raised -- neither of which is a stacking-context or overflow bug
|
|
4975
|
+
* fixable from the INSIDE. A portal sidesteps it entirely by not being a
|
|
4976
|
+
* descendant of the sticky `<td>` at all once mounted. */ function isChipListEditable(column) {
|
|
4641
4977
|
return !!column.editable && column.type === "chip-list";
|
|
4642
4978
|
}
|
|
4643
|
-
function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyFirst, stickyLast }) {
|
|
4979
|
+
function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyFirst, stickyLast, cellContextMenu, onViewEditHistory, cellContextMenuItems }) {
|
|
4644
4980
|
const effective = useEffectiveColumns(columns, {
|
|
4645
4981
|
selectable,
|
|
4646
4982
|
stickyFirst
|
|
4647
4983
|
});
|
|
4648
4984
|
return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
4649
|
-
children: effective.map((entry
|
|
4985
|
+
children: effective.map((entry)=>{
|
|
4650
4986
|
const { column } = entry;
|
|
4651
|
-
const
|
|
4652
|
-
const sticky = pinnedCellProps(entry, stickyLast, isLast);
|
|
4987
|
+
const sticky = pinnedCellProps(entry, stickyLast);
|
|
4653
4988
|
return /*#__PURE__*/ jsxRuntime.jsx(DataTableBodyCell, {
|
|
4654
4989
|
column: column,
|
|
4655
4990
|
row: row,
|
|
4656
4991
|
classNames: classNames,
|
|
4657
4992
|
locale: locale,
|
|
4658
|
-
sticky: sticky
|
|
4993
|
+
sticky: sticky,
|
|
4994
|
+
cellContextMenu: cellContextMenu,
|
|
4995
|
+
onViewEditHistory: onViewEditHistory,
|
|
4996
|
+
cellContextMenuItems: cellContextMenuItems
|
|
4659
4997
|
}, column.key);
|
|
4660
4998
|
})
|
|
4661
4999
|
});
|
|
@@ -4667,7 +5005,7 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4667
5005
|
* on every row's render. React keeps this instance stable across re-renders because
|
|
4668
5006
|
* `ColumnBodyCells` keys it by `column.key` the same way it always keyed the bare
|
|
4669
5007
|
* `<DataTableCell>` before this split.
|
|
4670
|
-
*/ function DataTableBodyCell({ column, row, classNames, locale, sticky }) {
|
|
5008
|
+
*/ function DataTableBodyCell({ column, row, classNames, locale, sticky, cellContextMenu, onViewEditHistory, cellContextMenuItems }) {
|
|
4671
5009
|
const { startEdit, cancelEdit, isEditing, isPending, commitEdit, isPeeking, openPeek, closePeek } = useDataTableContext();
|
|
4672
5010
|
const cellRef = React__namespace.useRef(null);
|
|
4673
5011
|
// Feature B rework (#8) -- the chip-list popover's own live position, in VIEWPORT
|
|
@@ -4683,6 +5021,16 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4683
5021
|
// editable cell's existing double-click-to-edit (tranche 5, unchanged) must keep
|
|
4684
5022
|
// rendering exactly as it always has, not suddenly gain overlay chrome.
|
|
4685
5023
|
const [overlayOpen, setOverlayOpen] = React__namespace.useState(false);
|
|
5024
|
+
// Attio parity (attio-column-features-full.md gap #1) -- the right-click menu's own
|
|
5025
|
+
// point + open state. `contextMenuPoint` is frozen at the moment of the right-click
|
|
5026
|
+
// (never re-read live), same reasoning as `overlayOpen` above: the menu shouldn't
|
|
5027
|
+
// chase the cursor after it opens. `<CellContextMenu>` itself is only rendered below
|
|
5028
|
+
// while `contextMenuOpen` is true (not permanently mounted per cell) -- unlike
|
|
5029
|
+
// `ColumnMenu` (one per COLUMN, header row only), this component runs once per
|
|
5030
|
+
// row×column cell, and a floating-ui instance genuinely idle in every one of
|
|
5031
|
+
// thousands of cells would be real, avoidable overhead.
|
|
5032
|
+
const [contextMenuPoint, setContextMenuPoint] = React__namespace.useState(null);
|
|
5033
|
+
const [contextMenuOpen, setContextMenuOpen] = React__namespace.useState(false);
|
|
4686
5034
|
const alwaysLive = isAlwaysLiveEditable(column);
|
|
4687
5035
|
const chipListEditable = isChipListEditable(column);
|
|
4688
5036
|
// A gated `editable` column (everything except the always-live widgets AND the
|
|
@@ -4734,6 +5082,19 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4734
5082
|
setOverlayOpen(isCellTruncated(event.currentTarget));
|
|
4735
5083
|
startEdit(row.id, column.key);
|
|
4736
5084
|
}
|
|
5085
|
+
function handleContextMenu(event) {
|
|
5086
|
+
if (!cellContextMenu) return;
|
|
5087
|
+
// Replaces the browser's own native context menu (Attio's own gesture) -- and
|
|
5088
|
+
// must not also reach the row's own `onRowClick`, same reasoning as every other
|
|
5089
|
+
// cell-local click handler in this file.
|
|
5090
|
+
event.preventDefault();
|
|
5091
|
+
event.stopPropagation();
|
|
5092
|
+
setContextMenuPoint({
|
|
5093
|
+
x: event.clientX,
|
|
5094
|
+
y: event.clientY
|
|
5095
|
+
});
|
|
5096
|
+
setContextMenuOpen(true);
|
|
5097
|
+
}
|
|
4737
5098
|
function handleClick(event) {
|
|
4738
5099
|
if (chipListEditable) {
|
|
4739
5100
|
// Attio's own chip-list gesture: click opens the editor regardless of
|
|
@@ -4771,6 +5132,16 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4771
5132
|
// mounted, in `document.body` -- see `isChipListEditable`'s doc comment) and by
|
|
4772
5133
|
// the reposition effect further down.
|
|
4773
5134
|
const popoverRef = React__namespace.useRef(null);
|
|
5135
|
+
// Feature C's own portaled overlay (`CellExpandOverlay`, editors.tsx) -- its own DOM
|
|
5136
|
+
// node, once mounted, same reasoning as `popoverRef` above: it lives outside
|
|
5137
|
+
// `cellRef`'s subtree (a sibling of the table in `document.body`, not a descendant of
|
|
5138
|
+
// the `<td>`), so the outside-click detector below needs a ref to it too. Without
|
|
5139
|
+
// this, `isInside` saw every click/keystroke INSIDE the portaled editor as "outside"
|
|
5140
|
+
// once the overlay actually escaped the `<td>` (this fix's whole point) -- e.g.
|
|
5141
|
+
// typing into the overlay's own `TextEditor` fires a pointerdown on an input that is
|
|
5142
|
+
// no longer `cellRef.current`'s descendant, so every keystroke closed the overlay and
|
|
5143
|
+
// cancelled the edit before the user finished typing.
|
|
5144
|
+
const expandOverlayRef = React__namespace.useRef(null);
|
|
4774
5145
|
// Closes the overlay on Escape or an outside click/pointerdown -- a gated
|
|
4775
5146
|
// editor's OWN Escape/blur handling already ends `isEditing` on its own (see
|
|
4776
5147
|
// `TextEditor`/`SelectEditor`'s existing onCancel/onOpenChange wiring), which
|
|
@@ -4783,7 +5154,7 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4783
5154
|
React__namespace.useEffect(()=>{
|
|
4784
5155
|
if (!overlayOpen) return;
|
|
4785
5156
|
function isInside(target) {
|
|
4786
|
-
return (cellRef.current?.contains(target) ?? false) || (popoverRef.current?.contains(target) ?? false);
|
|
5157
|
+
return (cellRef.current?.contains(target) ?? false) || (popoverRef.current?.contains(target) ?? false) || (expandOverlayRef.current?.contains(target) ?? false);
|
|
4787
5158
|
}
|
|
4788
5159
|
function handlePointerDown(event) {
|
|
4789
5160
|
if (!isInside(event.target)) {
|
|
@@ -4837,7 +5208,7 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4837
5208
|
const pending = isPending(row.id, column.key);
|
|
4838
5209
|
return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
4839
5210
|
children: [
|
|
4840
|
-
/*#__PURE__*/ jsxRuntime.
|
|
5211
|
+
/*#__PURE__*/ jsxRuntime.jsxs(DataTableCell, {
|
|
4841
5212
|
ref: cellRef,
|
|
4842
5213
|
"data-numeric": domUtils.dataAttr(column.type === "number" || column.type === "currency"),
|
|
4843
5214
|
"data-editable": domUtils.dataAttr(!!column.editable),
|
|
@@ -4848,14 +5219,36 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4848
5219
|
style: sticky.style,
|
|
4849
5220
|
onClick: handleClick,
|
|
4850
5221
|
onDoubleClick: handleDoubleClick,
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
5222
|
+
onContextMenu: handleContextMenu,
|
|
5223
|
+
children: [
|
|
5224
|
+
/*#__PURE__*/ jsxRuntime.jsx(CellContent, {
|
|
5225
|
+
column: column,
|
|
5226
|
+
row: row,
|
|
5227
|
+
rowId: row.id,
|
|
5228
|
+
classNames: classNames,
|
|
5229
|
+
locale: locale,
|
|
5230
|
+
overlayActive: overlayActive,
|
|
5231
|
+
cellRef: cellRef,
|
|
5232
|
+
expandOverlayRef: expandOverlayRef
|
|
5233
|
+
}),
|
|
5234
|
+
cellContextMenu && contextMenuOpen && contextMenuPoint && // A `<td>` (unlike its own parent `<tr>`) can validly hold any flow
|
|
5235
|
+
// content, so `CellContextMenu`'s own 0x0 `MenuAnchor` -- itself never
|
|
5236
|
+
// portaled, only `MenuPositioner`'s actual dropdown content is (via
|
|
5237
|
+
// floating-ui's own `FloatingPortal`, straight to `document.body`) --
|
|
5238
|
+
// renders here, INSIDE this cell, rather than as a sibling of it.
|
|
5239
|
+
/*#__PURE__*/ jsxRuntime.jsx(CellContextMenu, {
|
|
5240
|
+
column: column,
|
|
5241
|
+
row: row,
|
|
5242
|
+
value: rawValue,
|
|
5243
|
+
locale: locale,
|
|
5244
|
+
point: contextMenuPoint,
|
|
5245
|
+
open: contextMenuOpen,
|
|
5246
|
+
onOpenChange: setContextMenuOpen,
|
|
5247
|
+
onCommit: (value)=>commitEdit(row.id, column.key, value),
|
|
5248
|
+
onViewEditHistory: onViewEditHistory,
|
|
5249
|
+
cellContextMenuItems: cellContextMenuItems
|
|
5250
|
+
})
|
|
5251
|
+
]
|
|
4859
5252
|
}),
|
|
4860
5253
|
chipListEditorOpen && popoverStyle && /*#__PURE__*/ reactDom.createPortal(// biome-ignore lint/a11y/noStaticElementInteractions: not a widget -- same shape as `CellExpandOverlay` (editors.tsx), which this box is a portaled variant of: it never responds to interaction on ITSELF, only stops propagation of clicks that already occurred on a real interactive descendant (the editor's input/remove buttons). No role fits it because it isn't a control.
|
|
4861
5254
|
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
@@ -4881,7 +5274,7 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4881
5274
|
* display (a custom `render` wins there, same as before `editable` existed; it never
|
|
4882
5275
|
* overrides an actual editing/always-live state, matching crisp's own split between
|
|
4883
5276
|
* `renderTyped`'s rest-state branch and the editing branches above it).
|
|
4884
|
-
*/ function CellContent({ column, row, rowId, classNames, locale, overlayActive }) {
|
|
5277
|
+
*/ function CellContent({ column, row, rowId, classNames, locale, overlayActive, cellRef, expandOverlayRef }) {
|
|
4885
5278
|
const { isEditing, isPending, getEditError, commitEdit, cancelEdit } = useDataTableContext();
|
|
4886
5279
|
const rawValue = getColumnValue(column, row);
|
|
4887
5280
|
const pending = isPending(rowId, column.key);
|
|
@@ -4975,6 +5368,8 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4975
5368
|
children: [
|
|
4976
5369
|
overlayActive ? /*#__PURE__*/ jsxRuntime.jsx(CellExpandOverlay, {
|
|
4977
5370
|
className: classNames.expandOverlay,
|
|
5371
|
+
anchorRef: cellRef,
|
|
5372
|
+
contentRef: expandOverlayRef,
|
|
4978
5373
|
children: column.editable ? node : /*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
4979
5374
|
className: classNames.expandOverlayText,
|
|
4980
5375
|
children: node
|
|
@@ -5085,64 +5480,52 @@ function DisplayCellContent({ column, row, value, classNames, locale }) {
|
|
|
5085
5480
|
}
|
|
5086
5481
|
}
|
|
5087
5482
|
|
|
5088
|
-
const
|
|
5089
|
-
const
|
|
5090
|
-
const
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5483
|
+
const DataTableBulkBarRoot = withContext$1(Primitive.div, "bulkBar");
|
|
5484
|
+
const DataTableBulkBarCount = withContext$1(Primitive.span, "bulkBarCount");
|
|
5485
|
+
const DataTableBulkBarClear = withContext$1(Primitive.button, "bulkBarClear");
|
|
5486
|
+
/** Wraps whatever the CONSUMER passes as this bar's own action buttons -- the bar
|
|
5487
|
+
* itself only ever supplies chrome (count + clear); every actual action (Add to
|
|
5488
|
+
* list, Send email, …) is the consumer's own `<ActionButton>`/`<Menu>`, the same
|
|
5489
|
+
* "chrome vs. consumer content" split `toolbarActions`/`toolbarEnd` already draw for
|
|
5490
|
+
* the toolbar's own custom actions. */ const DataTableBulkBarActions = withContext$1(Primitive.div, "bulkBarActions");
|
|
5491
|
+
/**
|
|
5492
|
+
* The floating bulk-action pill (gap #4) -- renders nothing while no row is selected
|
|
5493
|
+
* (reads `selectedIds` off the table-wide context itself, so a consumer doesn't have
|
|
5494
|
+
* to gate this on `selectable`/`selectedIds` on their own). Composed as the LAST
|
|
5495
|
+
* child of the table's own root (`DataTable.tsx`), which is `position: relative` for
|
|
5496
|
+
* exactly this reason -- see `data-table.ts`'s own `bulkBar` slot comment for why its
|
|
5497
|
+
* geometry borrows `contextual-floating-button`'s already-measured vars rather than a
|
|
5498
|
+
* guessed literal.
|
|
5499
|
+
*/ function DataTableBulkBar({ clearLabel = "Clear selection", children }) {
|
|
5500
|
+
const { selectedIds, clearSelection } = useDataTableContext();
|
|
5501
|
+
if (selectedIds.length === 0) return null;
|
|
5502
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(DataTableBulkBarRoot, {
|
|
5503
|
+
role: "toolbar",
|
|
5504
|
+
"aria-label": "Bulk actions",
|
|
5505
|
+
"aria-orientation": "horizontal",
|
|
5506
|
+
children: [
|
|
5507
|
+
/*#__PURE__*/ jsxRuntime.jsxs(DataTableBulkBarCount, {
|
|
5508
|
+
"aria-live": "polite",
|
|
5509
|
+
children: [
|
|
5510
|
+
selectedIds.length,
|
|
5511
|
+
" selected"
|
|
5512
|
+
]
|
|
5513
|
+
}),
|
|
5514
|
+
/*#__PURE__*/ jsxRuntime.jsx(DataTableBulkBarClear, {
|
|
5515
|
+
type: "button",
|
|
5516
|
+
"aria-label": clearLabel,
|
|
5517
|
+
onClick: clearSelection,
|
|
5518
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(IconXmarkLine_default, {
|
|
5519
|
+
size: 12,
|
|
5520
|
+
"aria-hidden": "true"
|
|
5521
|
+
})
|
|
5522
|
+
}),
|
|
5523
|
+
children && /*#__PURE__*/ jsxRuntime.jsx(DataTableBulkBarActions, {
|
|
5524
|
+
children: children(selectedIds)
|
|
5107
5525
|
})
|
|
5108
|
-
|
|
5109
|
-
});
|
|
5110
|
-
};
|
|
5111
|
-
reactMenu.Menu.Anchor;
|
|
5112
|
-
const MenuTrigger = reactMenu.Menu.Trigger;
|
|
5113
|
-
const MenuPositioner = /*#__PURE__*/ React__namespace.forwardRef(({ className, ...props }, ref)=>{
|
|
5114
|
-
const classNames = useClassNames();
|
|
5115
|
-
return /*#__PURE__*/ jsxRuntime.jsx(reactMenu.Menu.Positioner, {
|
|
5116
|
-
ref: ref,
|
|
5117
|
-
className: clsx(classNames.positioner, className),
|
|
5118
|
-
...props
|
|
5119
|
-
});
|
|
5120
|
-
});
|
|
5121
|
-
MenuPositioner.displayName = "MenuPositioner";
|
|
5122
|
-
const MenuContent = withContext$1(reactMenu.Menu.Content, "content");
|
|
5123
|
-
const MenuScrollArea = withContext$1(withStateProps(Primitive.div), "scrollArea");
|
|
5124
|
-
withContext$1(reactMenu.Menu.Group, "group");
|
|
5125
|
-
withContext$1(reactMenu.Menu.GroupLabel, "groupLabel");
|
|
5126
|
-
const MenuItem = /*#__PURE__*/ React__namespace.forwardRef(({ className: propClassName, ...props }, ref)=>{
|
|
5127
|
-
const [variantProps, otherProps] = menuItem.menuItem.splitVariantProps(props);
|
|
5128
|
-
const parentProps = useItemProps();
|
|
5129
|
-
const classNames = menuItem.menuItem({
|
|
5130
|
-
...parentProps,
|
|
5131
|
-
...variantProps
|
|
5132
|
-
});
|
|
5133
|
-
return /*#__PURE__*/ jsxRuntime.jsx(ItemClassNamesProvider, {
|
|
5134
|
-
value: classNames,
|
|
5135
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(reactMenu.Menu.Item, {
|
|
5136
|
-
ref: ref,
|
|
5137
|
-
className: clsx(classNames.root, propClassName),
|
|
5138
|
-
...otherProps
|
|
5139
|
-
})
|
|
5526
|
+
]
|
|
5140
5527
|
});
|
|
5141
|
-
}
|
|
5142
|
-
MenuItem.displayName = "MenuItem";
|
|
5143
|
-
withItemContext(withItemStateProps(Primitive.div), "body");
|
|
5144
|
-
const MenuItemLabel = withItemContext(withItemStateProps(Primitive.span), "label");
|
|
5145
|
-
withItemContext(withItemStateProps(Primitive.span), "description");
|
|
5528
|
+
}
|
|
5146
5529
|
|
|
5147
5530
|
function ColumnCalcCells({ columns, rows, selectable, stickyFirst, stickyLast }) {
|
|
5148
5531
|
const effective = useEffectiveColumns(columns, {
|
|
@@ -5150,10 +5533,9 @@ function ColumnCalcCells({ columns, rows, selectable, stickyFirst, stickyLast })
|
|
|
5150
5533
|
stickyFirst
|
|
5151
5534
|
});
|
|
5152
5535
|
return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
5153
|
-
children: effective.map((entry
|
|
5536
|
+
children: effective.map((entry)=>{
|
|
5154
5537
|
const { column } = entry;
|
|
5155
|
-
const
|
|
5156
|
-
const sticky = pinnedCellProps(entry, stickyLast, isLast);
|
|
5538
|
+
const sticky = pinnedCellProps(entry, stickyLast);
|
|
5157
5539
|
return /*#__PURE__*/ jsxRuntime.jsx(DataTableFooterCell, {
|
|
5158
5540
|
"data-sticky": sticky["data-sticky"],
|
|
5159
5541
|
"data-sticky-edge": sticky["data-sticky-edge"],
|
|
@@ -5169,10 +5551,11 @@ function ColumnCalcCells({ columns, rows, selectable, stickyFirst, stickyLast })
|
|
|
5169
5551
|
})
|
|
5170
5552
|
});
|
|
5171
5553
|
}
|
|
5172
|
-
function formatCalcValue(value) {
|
|
5173
|
-
|
|
5554
|
+
function formatCalcValue(value, op) {
|
|
5555
|
+
const formatted = value.toLocaleString(undefined, {
|
|
5174
5556
|
maximumFractionDigits: 2
|
|
5175
5557
|
});
|
|
5558
|
+
return op === "percentEmpty" || op === "percentFilled" ? `${formatted}%` : formatted;
|
|
5176
5559
|
}
|
|
5177
5560
|
/**
|
|
5178
5561
|
* One ColumnCalc footer cell -- a click-anywhere-in-the-cell trigger (crisp's own
|
|
@@ -5207,7 +5590,7 @@ function formatCalcValue(value) {
|
|
|
5207
5590
|
children: [
|
|
5208
5591
|
/*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
5209
5592
|
className: "seed-data-table-column-calc-value",
|
|
5210
|
-
children: formatCalcValue(result)
|
|
5593
|
+
children: formatCalcValue(result, op)
|
|
5211
5594
|
}),
|
|
5212
5595
|
/*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
5213
5596
|
className: "seed-data-table-column-calc-op",
|
|
@@ -5228,21 +5611,13 @@ function formatCalcValue(value) {
|
|
|
5228
5611
|
style: {
|
|
5229
5612
|
minWidth: 160
|
|
5230
5613
|
},
|
|
5231
|
-
children: /*#__PURE__*/ jsxRuntime.
|
|
5232
|
-
children:
|
|
5233
|
-
|
|
5234
|
-
onClick: ()=>setColumnCalcOp(column.key, candidate),
|
|
5235
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
|
|
5236
|
-
children: DATA_TABLE_CALC_LABEL[candidate]
|
|
5237
|
-
})
|
|
5238
|
-
}, candidate)),
|
|
5239
|
-
op && /*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
|
|
5240
|
-
onClick: ()=>setColumnCalcOp(column.key, undefined),
|
|
5614
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(MenuScrollArea, {
|
|
5615
|
+
children: ops.map((candidate)=>/*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
|
|
5616
|
+
onClick: ()=>setColumnCalcOp(column.key, candidate),
|
|
5241
5617
|
children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
|
|
5242
|
-
children:
|
|
5618
|
+
children: DATA_TABLE_CALC_LABEL[candidate]
|
|
5243
5619
|
})
|
|
5244
|
-
})
|
|
5245
|
-
]
|
|
5620
|
+
}, candidate))
|
|
5246
5621
|
})
|
|
5247
5622
|
})
|
|
5248
5623
|
})
|
|
@@ -5383,10 +5758,9 @@ const DEFAULT_SORT_ICON = {
|
|
|
5383
5758
|
});
|
|
5384
5759
|
const [renamingKey, setRenamingKey] = React__namespace.useState(null);
|
|
5385
5760
|
return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
5386
|
-
children: effective.map((entry
|
|
5761
|
+
children: effective.map((entry)=>{
|
|
5387
5762
|
const { column, label, width } = entry;
|
|
5388
|
-
const
|
|
5389
|
-
const sticky = pinnedCellProps(entry, stickyLast, isLast);
|
|
5763
|
+
const sticky = pinnedCellProps(entry, stickyLast);
|
|
5390
5764
|
return /*#__PURE__*/ jsxRuntime.jsxs(DataTableHeaderCell, {
|
|
5391
5765
|
columnKey: column.key,
|
|
5392
5766
|
sortable: column.sortable,
|
|
@@ -10507,6 +10881,18 @@ ContinuousDatePicker.displayName = "ContinuousDatePicker";
|
|
|
10507
10881
|
// value list) down to `is`/`is not`/`empty`/`not empty`. `"isanyof"` is appended to any
|
|
10508
10882
|
// of the four whenever the column supplies `filterValues` -- a faceted checkbox list,
|
|
10509
10883
|
// independent of the column's own kind.
|
|
10884
|
+
//
|
|
10885
|
+
// Multi-select fix (DATATABLE-ATTIO-SPEC.md gap #12, live-measured 2026-09-30): a
|
|
10886
|
+
// `kind: "select"` column whose CELL is multi-valued (`type: "tags"`/`"chip-list"` --
|
|
10887
|
+
// a chip-list/tag column, not a single status pill) offers Attio's own
|
|
10888
|
+
// `contains`/`does not contain` instead of `is`/`is not` -- "is" reads as an exact-
|
|
10889
|
+
// set-equality check against an array value, which is not what Attio's own multi-
|
|
10890
|
+
// select filter means or what `applyToolbarFilters`' `is`/`isnot` branch (a plain
|
|
10891
|
+
// string-equality compare via `asText`) computes. `contains`/`doesnotcontain` are
|
|
10892
|
+
// already correct here unmodified: `applyToolbarFilters` already runs them against
|
|
10893
|
+
// `asText(raw)` (an array's own values joined), which is exactly "does any tag
|
|
10894
|
+
// match". Single-select (no `filterValues`-array cell type) keeps `is`/`is not` --
|
|
10895
|
+
// not re-measured against Attio, so left alone per the discovery doc's own hedge.
|
|
10510
10896
|
////////////////////////////////////////////////////////////////////////////////////
|
|
10511
10897
|
const OP_ORDER = [
|
|
10512
10898
|
"contains",
|
|
@@ -10540,9 +10926,19 @@ const SELECT_OP_ORDER = [
|
|
|
10540
10926
|
"empty",
|
|
10541
10927
|
"notempty"
|
|
10542
10928
|
];
|
|
10929
|
+
const MULTI_SELECT_OP_ORDER = [
|
|
10930
|
+
"contains",
|
|
10931
|
+
"doesnotcontain",
|
|
10932
|
+
"empty",
|
|
10933
|
+
"notempty"
|
|
10934
|
+
];
|
|
10543
10935
|
/** The operators a column of this `kind` offers, in display order -- `hasValues`
|
|
10544
|
-
* (the column supplies `filterValues`) appends `"isanyof"` regardless of kind.
|
|
10545
|
-
|
|
10936
|
+
* (the column supplies `filterValues`) appends `"isanyof"` regardless of kind.
|
|
10937
|
+
* `multiValue` (the column's CELL type is a chip-list/tags column, not just its
|
|
10938
|
+
* filter `kind`) swaps `SELECT_OP_ORDER`'s `is`/`is not` for `contains`/`does not
|
|
10939
|
+
* contain`, matching Attio's own multi-select filter -- see the operator-sets
|
|
10940
|
+
* comment above. */ function opsForKind(kind, hasValues, multiValue = false) {
|
|
10941
|
+
const base = kind === "number" ? NUMBER_OP_ORDER : kind === "date" ? DATE_OP_ORDER : kind === "select" ? multiValue ? MULTI_SELECT_OP_ORDER : SELECT_OP_ORDER : OP_ORDER;
|
|
10546
10942
|
return hasValues ? [
|
|
10547
10943
|
...base,
|
|
10548
10944
|
"isanyof"
|
|
@@ -10910,66 +11306,58 @@ const formatFilterDate = (iso)=>{
|
|
|
10910
11306
|
return `${OPERATOR_LABELS[filter.op]} ${value}`;
|
|
10911
11307
|
}
|
|
10912
11308
|
/**
|
|
10913
|
-
* One filter condition, INSIDE the Filter popover --
|
|
10914
|
-
* (
|
|
10915
|
-
*
|
|
10916
|
-
*
|
|
10917
|
-
*
|
|
10918
|
-
*
|
|
10919
|
-
*
|
|
10920
|
-
*
|
|
10921
|
-
*
|
|
10922
|
-
|
|
11309
|
+
* One filter condition, INSIDE the Filter popover -- Attio's own compact chip shape
|
|
11310
|
+
* (DATATABLE-ATTIO-SPEC.md gap #12, re-measured live 2026-09-30): `[attribute ▾]
|
|
11311
|
+
* [operator …] [value] [remove ×]`, ALL of it visible at once, never behind a click-
|
|
11312
|
+
* to-expand accordion. Supersedes this file's earlier 2026-09-28 note (which read
|
|
11313
|
+
* Attio as keeping conditions collapsed behind a bare "Filter · N" count and put them
|
|
11314
|
+
* in an accordion for that reason) -- the fresh read found the opposite: every active
|
|
11315
|
+
* condition shows attribute/operator/value simultaneously. This keeps the outer shell
|
|
11316
|
+
* (the "Filter"/"Filter · N" trigger opening ONE popover, `SortControl`'s own
|
|
11317
|
+
* list-of-rows shape) rather than moving chips into the toolbar row itself, so the
|
|
11318
|
+
* already-covered trigger/`Add filter` DOM (`DataTable.test.tsx`) stays put; only the
|
|
11319
|
+
* PER-CONDITION row tightens, from an accordion to an always-open card. The operator
|
|
11320
|
+
* set stays a row of small pill buttons (not a dropdown) so every existing test that
|
|
11321
|
+
* clicks an operator by its exact button name keeps working unchanged.
|
|
11322
|
+
*/ function FilterConditionRow({ filter, columns }) {
|
|
10923
11323
|
const { patchToolbarFilter, changeToolbarFilterField, removeToolbarFilter } = useDataTableContext();
|
|
10924
11324
|
const column = columns.find((c)=>c.key === filter.key);
|
|
10925
11325
|
const kind = column?.kind;
|
|
11326
|
+
const multiValue = column?.type === "tags" || column?.type === "chip-list";
|
|
10926
11327
|
const values = column?.filterValues ?? [];
|
|
10927
|
-
const ops = opsForKind(kind, values.length > 0);
|
|
10928
|
-
return /*#__PURE__*/ jsxRuntime.jsxs("
|
|
11328
|
+
const ops = opsForKind(kind, values.length > 0, multiValue);
|
|
11329
|
+
return /*#__PURE__*/ jsxRuntime.jsxs("fieldset", {
|
|
11330
|
+
"aria-label": `${column ? columnLabel(column) : filter.key} filter: ${conditionSummary(filter, column)}`,
|
|
10929
11331
|
style: {
|
|
11332
|
+
margin: 0,
|
|
10930
11333
|
display: "flex",
|
|
10931
11334
|
flexDirection: "column",
|
|
10932
|
-
gap:
|
|
11335
|
+
gap: 8,
|
|
10933
11336
|
borderRadius: 6,
|
|
10934
|
-
|
|
10935
|
-
|
|
11337
|
+
border: "1px solid var(--seed-color-border-neutral)",
|
|
11338
|
+
background: "var(--seed-color-bg-neutral-weak)",
|
|
11339
|
+
padding: 6
|
|
10936
11340
|
},
|
|
10937
11341
|
children: [
|
|
10938
11342
|
/*#__PURE__*/ jsxRuntime.jsxs("div", {
|
|
10939
11343
|
style: {
|
|
10940
11344
|
display: "flex",
|
|
10941
11345
|
alignItems: "center",
|
|
10942
|
-
gap:
|
|
11346
|
+
gap: 4
|
|
10943
11347
|
},
|
|
10944
11348
|
children: [
|
|
10945
|
-
/*#__PURE__*/ jsxRuntime.
|
|
10946
|
-
|
|
10947
|
-
|
|
11349
|
+
/*#__PURE__*/ jsxRuntime.jsx(InlineSelect, {
|
|
11350
|
+
ariaLabel: "Filter by field",
|
|
11351
|
+
value: filter.key,
|
|
11352
|
+
onChange: (key)=>changeToolbarFilterField(filter.id, key),
|
|
11353
|
+
options: columns.map((c)=>({
|
|
11354
|
+
value: c.key,
|
|
11355
|
+
label: columnLabel(c)
|
|
11356
|
+
})),
|
|
10948
11357
|
style: {
|
|
10949
11358
|
flex: 1,
|
|
10950
|
-
minWidth: 0
|
|
10951
|
-
|
|
10952
|
-
padding: "6px 8px",
|
|
10953
|
-
border: "none",
|
|
10954
|
-
borderRadius: 6,
|
|
10955
|
-
background: "transparent",
|
|
10956
|
-
cursor: "pointer",
|
|
10957
|
-
fontSize: 13,
|
|
10958
|
-
overflow: "hidden",
|
|
10959
|
-
textOverflow: "ellipsis",
|
|
10960
|
-
whiteSpace: "nowrap"
|
|
10961
|
-
},
|
|
10962
|
-
children: [
|
|
10963
|
-
/*#__PURE__*/ jsxRuntime.jsx("strong", {
|
|
10964
|
-
style: {
|
|
10965
|
-
fontWeight: 500
|
|
10966
|
-
},
|
|
10967
|
-
children: column ? columnLabel(column) : filter.key
|
|
10968
|
-
}),
|
|
10969
|
-
":",
|
|
10970
|
-
" ",
|
|
10971
|
-
conditionSummary(filter, column)
|
|
10972
|
-
]
|
|
11359
|
+
minWidth: 0
|
|
11360
|
+
}
|
|
10973
11361
|
}),
|
|
10974
11362
|
/*#__PURE__*/ jsxRuntime.jsx("button", {
|
|
10975
11363
|
type: "button",
|
|
@@ -10983,136 +11371,103 @@ const formatFilterDate = (iso)=>{
|
|
|
10983
11371
|
})
|
|
10984
11372
|
]
|
|
10985
11373
|
}),
|
|
10986
|
-
|
|
11374
|
+
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
10987
11375
|
style: {
|
|
10988
|
-
padding: "0 8px 4px",
|
|
10989
11376
|
display: "flex",
|
|
10990
|
-
|
|
10991
|
-
gap:
|
|
11377
|
+
flexWrap: "wrap",
|
|
11378
|
+
gap: 2
|
|
10992
11379
|
},
|
|
10993
|
-
children:
|
|
10994
|
-
|
|
10995
|
-
|
|
10996
|
-
|
|
10997
|
-
|
|
10998
|
-
|
|
10999
|
-
children: "Field"
|
|
11000
|
-
}),
|
|
11001
|
-
/*#__PURE__*/ jsxRuntime.jsx(InlineSelect, {
|
|
11002
|
-
ariaLabel: "Filter by field",
|
|
11003
|
-
value: filter.key,
|
|
11004
|
-
onChange: (key)=>changeToolbarFilterField(filter.id, key),
|
|
11005
|
-
options: columns.map((c)=>({
|
|
11006
|
-
value: c.key,
|
|
11007
|
-
label: columnLabel(c)
|
|
11008
|
-
}))
|
|
11009
|
-
}),
|
|
11010
|
-
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
11011
|
-
style: {
|
|
11012
|
-
fontSize: 12,
|
|
11013
|
-
color: "var(--seed-color-fg-neutral-subtle)"
|
|
11014
|
-
},
|
|
11015
|
-
children: "Condition"
|
|
11016
|
-
}),
|
|
11017
|
-
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
11380
|
+
children: ops.map((op)=>/*#__PURE__*/ jsxRuntime.jsx("button", {
|
|
11381
|
+
type: "button",
|
|
11382
|
+
"data-active": filter.op === op ? "" : undefined,
|
|
11383
|
+
onClick: ()=>patchToolbarFilter(filter.id, {
|
|
11384
|
+
op
|
|
11385
|
+
}),
|
|
11018
11386
|
style: {
|
|
11019
|
-
|
|
11020
|
-
|
|
11021
|
-
|
|
11387
|
+
textAlign: "left",
|
|
11388
|
+
padding: "4px 8px",
|
|
11389
|
+
borderRadius: 999,
|
|
11390
|
+
border: "none",
|
|
11391
|
+
cursor: "pointer",
|
|
11392
|
+
background: filter.op === op ? "var(--seed-color-bg-layer-default)" : "transparent",
|
|
11393
|
+
fontSize: 12
|
|
11022
11394
|
},
|
|
11023
|
-
children:
|
|
11024
|
-
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
11028
|
-
|
|
11029
|
-
|
|
11030
|
-
|
|
11031
|
-
|
|
11032
|
-
|
|
11033
|
-
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
|
|
11041
|
-
|
|
11395
|
+
children: OPERATOR_LABELS[op]
|
|
11396
|
+
}, op))
|
|
11397
|
+
}),
|
|
11398
|
+
opNeedsValues(filter.op) && /*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
11399
|
+
style: {
|
|
11400
|
+
display: "flex",
|
|
11401
|
+
flexDirection: "column",
|
|
11402
|
+
gap: 4,
|
|
11403
|
+
maxHeight: 160,
|
|
11404
|
+
overflow: "auto"
|
|
11405
|
+
},
|
|
11406
|
+
children: values.map((value)=>{
|
|
11407
|
+
const checked = (filter.values ?? []).includes(value);
|
|
11408
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(CheckboxRoot, {
|
|
11409
|
+
checked: checked,
|
|
11410
|
+
onCheckedChange: ()=>patchToolbarFilter(filter.id, {
|
|
11411
|
+
values: checked ? (filter.values ?? []).filter((v)=>v !== value) : [
|
|
11412
|
+
...filter.values ?? [],
|
|
11413
|
+
value
|
|
11414
|
+
]
|
|
11415
|
+
}),
|
|
11042
11416
|
style: {
|
|
11043
11417
|
display: "flex",
|
|
11044
|
-
|
|
11045
|
-
gap:
|
|
11046
|
-
|
|
11047
|
-
|
|
11418
|
+
alignItems: "center",
|
|
11419
|
+
gap: 8,
|
|
11420
|
+
padding: "4px 0",
|
|
11421
|
+
cursor: "pointer"
|
|
11048
11422
|
},
|
|
11049
|
-
children:
|
|
11050
|
-
|
|
11051
|
-
|
|
11052
|
-
|
|
11053
|
-
|
|
11054
|
-
values: checked ? (filter.values ?? []).filter((v)=>v !== value) : [
|
|
11055
|
-
...filter.values ?? [],
|
|
11056
|
-
value
|
|
11057
|
-
]
|
|
11058
|
-
}),
|
|
11059
|
-
style: {
|
|
11060
|
-
display: "flex",
|
|
11061
|
-
alignItems: "center",
|
|
11062
|
-
gap: 8,
|
|
11063
|
-
padding: "4px 0",
|
|
11064
|
-
cursor: "pointer"
|
|
11065
|
-
},
|
|
11066
|
-
children: [
|
|
11067
|
-
/*#__PURE__*/ jsxRuntime.jsx(CheckboxControl, {
|
|
11068
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(CheckboxIndicator, {
|
|
11069
|
-
checked: /*#__PURE__*/ jsxRuntime.jsx(IconCheckmarkLine_default, {
|
|
11070
|
-
size: 12
|
|
11071
|
-
})
|
|
11072
|
-
})
|
|
11073
|
-
}),
|
|
11074
|
-
/*#__PURE__*/ jsxRuntime.jsx(CheckboxLabel, {
|
|
11075
|
-
children: value
|
|
11076
|
-
}),
|
|
11077
|
-
/*#__PURE__*/ jsxRuntime.jsx(CheckboxHiddenInput, {
|
|
11078
|
-
"aria-label": value
|
|
11423
|
+
children: [
|
|
11424
|
+
/*#__PURE__*/ jsxRuntime.jsx(CheckboxControl, {
|
|
11425
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(CheckboxIndicator, {
|
|
11426
|
+
checked: /*#__PURE__*/ jsxRuntime.jsx(IconCheckmarkLine_default, {
|
|
11427
|
+
size: 12
|
|
11079
11428
|
})
|
|
11080
|
-
|
|
11081
|
-
}, value);
|
|
11082
|
-
})
|
|
11083
|
-
}),
|
|
11084
|
-
opNeedsValue(filter.op) && kind === "date" && /*#__PURE__*/ jsxRuntime.jsx(DatePicker, {
|
|
11085
|
-
value: filter.value ? toDatePickerDate(isoToDate(filter.value) ?? new Date()) : undefined,
|
|
11086
|
-
onValueChange: (d)=>d && patchToolbarFilter(filter.id, {
|
|
11087
|
-
value: dateToISO(fromDatePickerDate(d))
|
|
11088
|
-
})
|
|
11089
|
-
}),
|
|
11090
|
-
opNeedsValue(filter.op) && kind === "select" && /*#__PURE__*/ jsxRuntime.jsx(InlineSelect, {
|
|
11091
|
-
ariaLabel: "Filter value",
|
|
11092
|
-
placeholder: "Value…",
|
|
11093
|
-
value: filter.value || undefined,
|
|
11094
|
-
onChange: (value)=>patchToolbarFilter(filter.id, {
|
|
11095
|
-
value
|
|
11429
|
+
})
|
|
11096
11430
|
}),
|
|
11097
|
-
|
|
11098
|
-
value
|
|
11099
|
-
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
|
|
11106
|
-
|
|
11107
|
-
|
|
11108
|
-
|
|
11109
|
-
|
|
11110
|
-
|
|
11111
|
-
placeholder: "Value…",
|
|
11112
|
-
"aria-label": "Filter value"
|
|
11113
|
-
})
|
|
11431
|
+
/*#__PURE__*/ jsxRuntime.jsx(CheckboxLabel, {
|
|
11432
|
+
children: value
|
|
11433
|
+
}),
|
|
11434
|
+
/*#__PURE__*/ jsxRuntime.jsx(CheckboxHiddenInput, {
|
|
11435
|
+
"aria-label": value
|
|
11436
|
+
})
|
|
11437
|
+
]
|
|
11438
|
+
}, value);
|
|
11439
|
+
})
|
|
11440
|
+
}),
|
|
11441
|
+
opNeedsValue(filter.op) && kind === "date" && /*#__PURE__*/ jsxRuntime.jsx(DatePicker, {
|
|
11442
|
+
value: filter.value ? toDatePickerDate(isoToDate(filter.value) ?? new Date()) : undefined,
|
|
11443
|
+
onValueChange: (d)=>d && patchToolbarFilter(filter.id, {
|
|
11444
|
+
value: dateToISO(fromDatePickerDate(d))
|
|
11114
11445
|
})
|
|
11115
|
-
|
|
11446
|
+
}),
|
|
11447
|
+
opNeedsValue(filter.op) && kind === "select" && /*#__PURE__*/ jsxRuntime.jsx(InlineSelect, {
|
|
11448
|
+
ariaLabel: "Filter value",
|
|
11449
|
+
placeholder: "Value…",
|
|
11450
|
+
value: filter.value || undefined,
|
|
11451
|
+
onChange: (value)=>patchToolbarFilter(filter.id, {
|
|
11452
|
+
value
|
|
11453
|
+
}),
|
|
11454
|
+
options: values.map((value)=>({
|
|
11455
|
+
value,
|
|
11456
|
+
label: value
|
|
11457
|
+
}))
|
|
11458
|
+
}),
|
|
11459
|
+
opNeedsValue(filter.op) && kind !== "date" && kind !== "select" && /*#__PURE__*/ jsxRuntime.jsx(TextFieldRoot, {
|
|
11460
|
+
variant: "outline",
|
|
11461
|
+
size: "medium",
|
|
11462
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(TextFieldInput, {
|
|
11463
|
+
type: kind === "number" ? "number" : "text",
|
|
11464
|
+
value: filter.value,
|
|
11465
|
+
onChange: (e)=>patchToolbarFilter(filter.id, {
|
|
11466
|
+
value: e.target.value
|
|
11467
|
+
}),
|
|
11468
|
+
placeholder: "Value…",
|
|
11469
|
+
"aria-label": "Filter value"
|
|
11470
|
+
})
|
|
11116
11471
|
})
|
|
11117
11472
|
]
|
|
11118
11473
|
});
|
|
@@ -11120,15 +11475,14 @@ const formatFilterDate = (iso)=>{
|
|
|
11120
11475
|
/**
|
|
11121
11476
|
* The toolbar's Filter trigger + popover -- a compact `"Filter"` / `"Filter · N"`
|
|
11122
11477
|
* button (matching `SortControl`'s own `"Sort"` / `"Sort · N"`), opening ONE popover
|
|
11123
|
-
* that holds both the active conditions (compact
|
|
11124
|
-
*
|
|
11125
|
-
* new one
|
|
11126
|
-
*
|
|
11478
|
+
* that holds both the active conditions (compact chips, `FilterConditionRow` above,
|
|
11479
|
+
* ALL open at once -- no accordion) and, behind "+ Add filter", the field picker that
|
|
11480
|
+
* appends a new one. See `FilterConditionRow`'s own doc comment for why the chips
|
|
11481
|
+
* live inside this one popover rather than spread across the toolbar row itself.
|
|
11127
11482
|
*/ function FilterControl({ columns, label = "Filter" }) {
|
|
11128
11483
|
const { toolbarFilters, addToolbarFilter } = useDataTableContext();
|
|
11129
11484
|
const [open, setOpen] = React__namespace.useState(false);
|
|
11130
11485
|
const [pickingField, setPickingField] = React__namespace.useState(false);
|
|
11131
|
-
const [expandedId, setExpandedId] = React__namespace.useState(null);
|
|
11132
11486
|
return /*#__PURE__*/ jsxRuntime.jsxs(MenuRoot, {
|
|
11133
11487
|
open: open,
|
|
11134
11488
|
onOpenChange: (next)=>{
|
|
@@ -11190,8 +11544,7 @@ const formatFilterDate = (iso)=>{
|
|
|
11190
11544
|
columns.map((c)=>/*#__PURE__*/ jsxRuntime.jsx("button", {
|
|
11191
11545
|
type: "button",
|
|
11192
11546
|
onClick: ()=>{
|
|
11193
|
-
|
|
11194
|
-
setExpandedId(id);
|
|
11547
|
+
addToolbarFilter(c.key);
|
|
11195
11548
|
setPickingField(false);
|
|
11196
11549
|
},
|
|
11197
11550
|
style: {
|
|
@@ -11224,9 +11577,7 @@ const formatFilterDate = (iso)=>{
|
|
|
11224
11577
|
}),
|
|
11225
11578
|
toolbarFilters.map((f)=>/*#__PURE__*/ jsxRuntime.jsx(FilterConditionRow, {
|
|
11226
11579
|
filter: f,
|
|
11227
|
-
columns: columns
|
|
11228
|
-
expanded: expandedId === f.id,
|
|
11229
|
-
onToggle: ()=>setExpandedId((id)=>id === f.id ? null : f.id)
|
|
11580
|
+
columns: columns
|
|
11230
11581
|
}, f.id)),
|
|
11231
11582
|
/*#__PURE__*/ jsxRuntime.jsxs("button", {
|
|
11232
11583
|
type: "button",
|
|
@@ -11255,8 +11606,8 @@ const formatFilterDate = (iso)=>{
|
|
|
11255
11606
|
});
|
|
11256
11607
|
}
|
|
11257
11608
|
|
|
11258
|
-
const DataTableToolbar = withContext$
|
|
11259
|
-
const DataTableCount = withContext$
|
|
11609
|
+
const DataTableToolbar = withContext$1(Primitive.div, "toolbar");
|
|
11610
|
+
const DataTableCount = withContext$1(Primitive.span, "count");
|
|
11260
11611
|
/**
|
|
11261
11612
|
* The toolbar's own right-hand group -- `count`'s `marginInlineStart: auto` moved
|
|
11262
11613
|
* here (off the `<span>` itself) so a consumer's `toolbarActions` and the row count
|
|
@@ -11267,7 +11618,7 @@ const DataTableCount = withContext$2(Primitive.span, "count");
|
|
|
11267
11618
|
* it. `DataTable.tsx` always renders this wrapper once either `toolbarActions` or
|
|
11268
11619
|
* `showCount` is on, so it degrades to exactly the old single-count layout when no
|
|
11269
11620
|
* `toolbarActions` is passed.
|
|
11270
|
-
*/ const DataTableToolbarEnd = withContext$
|
|
11621
|
+
*/ const DataTableToolbarEnd = withContext$1(Primitive.div, "toolbarEnd");
|
|
11271
11622
|
/**
|
|
11272
11623
|
* A compact, borderless search box -- crisp's own measured `.crisp-datatable-search`
|
|
11273
11624
|
* (32px, `bgSurface` background, a leading icon, a soft rest-state shadow, a 1px brand
|
|
@@ -11317,7 +11668,7 @@ function RowCount({ shown, total, countLabel }) {
|
|
|
11317
11668
|
}
|
|
11318
11669
|
|
|
11319
11670
|
function DataTableInner(props, ref) {
|
|
11320
|
-
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;
|
|
11671
|
+
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, bulkActions, clearSelectionLabel, 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, cellContextMenu = true, onViewEditHistory, cellContextMenuItems, interactive = false, onRowClick, onAddRow, addRowLabel = "New record", loading = false, loadingLabel = "Loading...", error, empty = "No results.", onLoadMore, hasMore, loadingMore, scrollProps, ...restProps } = props;
|
|
11321
11672
|
const classNames = dataTable({
|
|
11322
11673
|
surface,
|
|
11323
11674
|
interactive
|
|
@@ -11419,6 +11770,12 @@ function DataTableInner(props, ref) {
|
|
|
11419
11770
|
const columnKeys = React__namespace.useMemo(()=>columns.map((column)=>column.key), [
|
|
11420
11771
|
columns
|
|
11421
11772
|
]);
|
|
11773
|
+
// Threaded down to `reconcileColumnOrder` (react-headless's `dom.ts`) so a brand-new
|
|
11774
|
+
// column added to `columns` after mount gets appended BEFORE this one, not past it --
|
|
11775
|
+
// see that function's own doc comment for the bug this prevents.
|
|
11776
|
+
const actionsColumnKey = React__namespace.useMemo(()=>columns.find((column)=>column.actions)?.key, [
|
|
11777
|
+
columns
|
|
11778
|
+
]);
|
|
11422
11779
|
const searchable = React__namespace.useMemo(()=>columns.some((column)=>column.searchable), [
|
|
11423
11780
|
columns
|
|
11424
11781
|
]);
|
|
@@ -11441,7 +11798,7 @@ function DataTableInner(props, ref) {
|
|
|
11441
11798
|
// loading/error/empty body, infinite scroll's sentinel, the add-row footer) reads
|
|
11442
11799
|
// this ONE value rather than each re-deriving it, so they can never drift apart.
|
|
11443
11800
|
const totalCols = columns.length + (selectable ? 1 : 0);
|
|
11444
|
-
return /*#__PURE__*/ jsxRuntime.jsx(ClassNamesProvider
|
|
11801
|
+
return /*#__PURE__*/ jsxRuntime.jsx(ClassNamesProvider, {
|
|
11445
11802
|
value: classNames,
|
|
11446
11803
|
children: /*#__PURE__*/ jsxRuntime.jsxs(DataTableRoot, {
|
|
11447
11804
|
ref: ref,
|
|
@@ -11461,6 +11818,7 @@ function DataTableInner(props, ref) {
|
|
|
11461
11818
|
toolbarFilters: resolvedToolbarFilters,
|
|
11462
11819
|
onToolbarFiltersChange: handleToolbarFiltersChange,
|
|
11463
11820
|
columnKeys: columnKeys,
|
|
11821
|
+
actionsColumnKey: actionsColumnKey,
|
|
11464
11822
|
columnOrder: columnOrder,
|
|
11465
11823
|
defaultColumnOrder: defaultColumnOrder,
|
|
11466
11824
|
onColumnOrderChange: onColumnOrderChange,
|
|
@@ -11597,7 +11955,10 @@ function DataTableInner(props, ref) {
|
|
|
11597
11955
|
locale: locale,
|
|
11598
11956
|
selectable: !!selectable,
|
|
11599
11957
|
stickyFirst: stickyFirst,
|
|
11600
|
-
stickyLast: resolvedStickyLast
|
|
11958
|
+
stickyLast: resolvedStickyLast,
|
|
11959
|
+
cellContextMenu: cellContextMenu,
|
|
11960
|
+
onViewEditHistory: onViewEditHistory,
|
|
11961
|
+
cellContextMenuItems: cellContextMenuItems
|
|
11601
11962
|
})
|
|
11602
11963
|
]
|
|
11603
11964
|
}, row.id)),
|
|
@@ -11636,6 +11997,10 @@ function DataTableInner(props, ref) {
|
|
|
11636
11997
|
})
|
|
11637
11998
|
]
|
|
11638
11999
|
})
|
|
12000
|
+
}),
|
|
12001
|
+
selectable && /*#__PURE__*/ jsxRuntime.jsx(DataTableBulkBar, {
|
|
12002
|
+
clearLabel: clearSelectionLabel,
|
|
12003
|
+
children: bulkActions
|
|
11639
12004
|
})
|
|
11640
12005
|
]
|
|
11641
12006
|
})
|
|
@@ -11689,7 +12054,7 @@ DataTableInner.displayName = "DataTable";
|
|
|
11689
12054
|
// is a SIBLING of the toolbar (both inside `DataTablePrimitiveRoot`'s card `<div>`)
|
|
11690
12055
|
// rather than `DataTablePrimitiveRoot` itself: a `<table>` cannot host the toolbar as a
|
|
11691
12056
|
// child without the HTML parser foster-parenting it back out.
|
|
11692
|
-
const DataTableTable = withContext$
|
|
12057
|
+
const DataTableTable = withContext$1(DataTableTable$1, "table");
|
|
11693
12058
|
/** One `<col>` per rendered column (plus the 40px selection column, if any) -- the
|
|
11694
12059
|
* SINGLE place a column's width is ever set now. Every row's header/body/footer cell
|
|
11695
12060
|
* reads its own width off this shared `<colgroup>` by construction (native table
|
|
@@ -11726,15 +12091,15 @@ const DataTableTable = withContext$2(DataTableTable$1, "table");
|
|
|
11726
12091
|
]
|
|
11727
12092
|
});
|
|
11728
12093
|
}
|
|
11729
|
-
const DataTableHeader = withContext$
|
|
11730
|
-
const DataTableHeaderCell = withContext$
|
|
12094
|
+
const DataTableHeader = withContext$1(DataTableHeader$1, "header");
|
|
12095
|
+
const DataTableHeaderCell = withContext$1(DataTableHeaderCell$1, "headerCell");
|
|
11731
12096
|
// `.crisp-datatable-th-inner` -- the flex row INSIDE a `<th>` (label + filter trigger +
|
|
11732
12097
|
// sort chevron + column menu). See qvism-preset's own `headerCellInner` slot comment
|
|
11733
12098
|
// for why this lives one level below the cell itself rather than on it.
|
|
11734
|
-
const DataTableHeaderCellInner = withContext$
|
|
12099
|
+
const DataTableHeaderCellInner = withContext$1(Primitive.div, "headerCellInner");
|
|
11735
12100
|
/** The label text specifically -- the one thing in `DataTableHeaderCellInner` that
|
|
11736
12101
|
* truncates; the trailing filter/sort/menu icons stay fully visible regardless of how
|
|
11737
|
-
* long a column's own header text is. */ const DataTableHeaderCellLabel = withContext$
|
|
12102
|
+
* long a column's own header text is. */ const DataTableHeaderCellLabel = withContext$1(Primitive.span, "headerCellLabel");
|
|
11738
12103
|
/**
|
|
11739
12104
|
* A selection `<th>`/`<td>`/footer `<td>` composes ITS base slot (`headerCell`/`cell`/
|
|
11740
12105
|
* `footerCell`) together with the `selectionCell` MODIFIER, rather than replacing it --
|
|
@@ -11745,7 +12110,7 @@ const DataTableHeaderCellInner = withContext$2(Primitive.div, "headerCellInner")
|
|
|
11745
12110
|
* a second recipe call.
|
|
11746
12111
|
*/ function withSelectionCell(Component, baseSlot) {
|
|
11747
12112
|
const StyledComponent = /*#__PURE__*/ React.forwardRef((props, ref)=>{
|
|
11748
|
-
const classNames = useClassNames
|
|
12113
|
+
const classNames = useClassNames();
|
|
11749
12114
|
return /*#__PURE__*/ jsxRuntime.jsx(Component, {
|
|
11750
12115
|
ref: ref,
|
|
11751
12116
|
...props,
|
|
@@ -11756,12 +12121,12 @@ const DataTableHeaderCellInner = withContext$2(Primitive.div, "headerCellInner")
|
|
|
11756
12121
|
return StyledComponent;
|
|
11757
12122
|
}
|
|
11758
12123
|
const DataTableSelectionHeaderCell = withSelectionCell(DataTableHeaderCell$1, "headerCell");
|
|
11759
|
-
const DataTableHeaderCellIcon = withContext$
|
|
12124
|
+
const DataTableHeaderCellIcon = withContext$1(Primitive.span, "headerCellIcon");
|
|
11760
12125
|
// body has no CSS slot of its own in the rootage spec -- it is a plain structural
|
|
11761
12126
|
// `<tbody>`, so it is not wrapped in `withContext`.
|
|
11762
12127
|
const DataTableBody = DataTableBody$1;
|
|
11763
|
-
const DataTableRow = withContext$
|
|
11764
|
-
const DataTableCell = withContext$
|
|
12128
|
+
const DataTableRow = withContext$1(DataTableRow$1, "row");
|
|
12129
|
+
const DataTableCell = withContext$1(DataTableCell$1, "cell");
|
|
11765
12130
|
const DataTableSelectionCell = withSelectionCell(DataTableCell$1, "cell");
|
|
11766
12131
|
// Tranche 4 -- column menu + reorder + resize + sticky columns. A scroll boundary
|
|
11767
12132
|
// wrapping the whole `<table>`: `overflowX: auto` is what makes a wide table (more
|
|
@@ -11771,7 +12136,7 @@ const DataTableSelectionCell = withSelectionCell(DataTableCell$1, "cell");
|
|
|
11771
12136
|
// stays out of this slot's own base css (nothing here has a bounded height of its own
|
|
11772
12137
|
// to clip), so it never introduces a second vertical scrollbar next to whatever
|
|
11773
12138
|
// ambient container the whole DataTable already sits in.
|
|
11774
|
-
const DataTableScrollBodyBase = withContext$
|
|
12139
|
+
const DataTableScrollBodyBase = withContext$1(Primitive.div, "scrollArea");
|
|
11775
12140
|
function DataTableScrollBody({ children, scrollProps }) {
|
|
11776
12141
|
const { scrollAreaRef, scrolledStart, scrolledEnd, onScroll } = useDataTableContext();
|
|
11777
12142
|
const { className: scrollClassName, style: scrollStyle, ...otherScrollProps } = scrollProps ?? {};
|
|
@@ -11786,7 +12151,7 @@ function DataTableScrollBody({ children, scrollProps }) {
|
|
|
11786
12151
|
children: children
|
|
11787
12152
|
});
|
|
11788
12153
|
}
|
|
11789
|
-
const DataTableFooterBase = withContext$
|
|
12154
|
+
const DataTableFooterBase = withContext$1(Primitive.tfoot, "footer");
|
|
11790
12155
|
function DataTableFooter({ children, ...props }) {
|
|
11791
12156
|
return /*#__PURE__*/ jsxRuntime.jsx(DataTableFooterBase, {
|
|
11792
12157
|
...props,
|
|
@@ -11795,7 +12160,7 @@ function DataTableFooter({ children, ...props }) {
|
|
|
11795
12160
|
})
|
|
11796
12161
|
});
|
|
11797
12162
|
}
|
|
11798
|
-
const DataTableFooterCell = withContext$
|
|
12163
|
+
const DataTableFooterCell = withContext$1(Primitive.td, "footerCell");
|
|
11799
12164
|
// The selection column's OWN sticky wrappers -- one each for header/body/footer,
|
|
11800
12165
|
// reading the live pinned set via `useSelectionStickyFirst` (column-layout.ts) instead
|
|
11801
12166
|
// of the `stickyFirst` PROP alone, so the checkbox column sticks the moment ANY column
|
|
@@ -15733,6 +16098,7 @@ function RecordPreviewPanel({ open: _open, record, onClose, className, animation
|
|
|
15733
16098
|
RecordPreviewPanel.displayName = "RecordPreviewPanel";
|
|
15734
16099
|
|
|
15735
16100
|
exports.DataTable = DataTable;
|
|
16101
|
+
exports.DataTableBulkBar = DataTableBulkBar;
|
|
15736
16102
|
exports.DataTableViewsControl = DataTableViewsControl;
|
|
15737
16103
|
exports.RecordPreview = RecordPreview;
|
|
15738
16104
|
exports.ResizablePanel = ResizablePanel;
|