@crispy-seed/data-table 0.10.4 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data-table-recipe.css +58 -0
- package/dist/data-table-recipe.layered.css +63 -0
- package/dist/index.cjs +702 -328
- package/dist/index.d.ts +119 -55
- package/dist/index.js +702 -329
- 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)));
|
|
@@ -1653,6 +1672,17 @@ function useDataTableSelection(props) {
|
|
|
1653
1672
|
rowIds,
|
|
1654
1673
|
setSelectedIds
|
|
1655
1674
|
]);
|
|
1675
|
+
// Bulk-action bar's own "×" (gap #4, DATATABLE-ATTIO-SPEC's Attio review) --
|
|
1676
|
+
// deliberately its own function rather than reusing `toggleAll`: `toggleAll` only
|
|
1677
|
+
// clears from an "all" selection, and otherwise SELECTS every row (`selectionState
|
|
1678
|
+
// === "some"` -> `rowIds`, above) -- exactly the wrong direction for a "clear
|
|
1679
|
+
// selection" affordance shown while `selectionState` is "some". This always empties
|
|
1680
|
+
// the set, regardless of `selectionState`.
|
|
1681
|
+
const clearSelection = React.useCallback(()=>{
|
|
1682
|
+
setSelectedIds([]);
|
|
1683
|
+
}, [
|
|
1684
|
+
setSelectedIds
|
|
1685
|
+
]);
|
|
1656
1686
|
const getRowProps = React.useCallback((rowId)=>{
|
|
1657
1687
|
const isRowSelected = isSelected(rowId);
|
|
1658
1688
|
return domUtils.elementProps({
|
|
@@ -1671,6 +1701,7 @@ function useDataTableSelection(props) {
|
|
|
1671
1701
|
isSelected,
|
|
1672
1702
|
toggleRow,
|
|
1673
1703
|
toggleAll,
|
|
1704
|
+
clearSelection,
|
|
1674
1705
|
getRowProps
|
|
1675
1706
|
};
|
|
1676
1707
|
}
|
|
@@ -1696,24 +1727,33 @@ function useDataTableSort(props) {
|
|
|
1696
1727
|
// already passes its "cleared" shape through unconditionally; this now matches.
|
|
1697
1728
|
onChange: onSortChange
|
|
1698
1729
|
});
|
|
1730
|
+
// 3-state cycle (DATATABLE-ATTIO-SPEC.md: "asc/desc/none cycle") -- clicking a
|
|
1731
|
+
// DIFFERENT column always starts it fresh at asc, discarding whatever the previous
|
|
1732
|
+
// column's direction was (this stays a SINGLE-column secondary affordance, never a
|
|
1733
|
+
// second multi-sort list of its own). Clicking the SAME column steps asc -> desc ->
|
|
1734
|
+
// undefined ("none", i.e. this column drops out of the sort entirely) -> asc again.
|
|
1735
|
+
// Before this, the cycle wrapped desc -> asc forever, with no click-driven way back
|
|
1736
|
+
// to unsorted at all (a reported gap: "sort asc/desc has no option for no sort on
|
|
1737
|
+
// columns") -- `clearSort` below was the ONLY way there, now it's one of two.
|
|
1699
1738
|
const toggleSort = React.useCallback((key)=>{
|
|
1700
1739
|
setSort((current)=>{
|
|
1701
1740
|
if (!current || current.key !== key) return {
|
|
1702
1741
|
key,
|
|
1703
1742
|
dir: "asc"
|
|
1704
1743
|
};
|
|
1705
|
-
return {
|
|
1744
|
+
if (current.dir === "asc") return {
|
|
1706
1745
|
key,
|
|
1707
|
-
dir:
|
|
1746
|
+
dir: "desc"
|
|
1708
1747
|
};
|
|
1748
|
+
return undefined;
|
|
1709
1749
|
});
|
|
1710
1750
|
}, [
|
|
1711
1751
|
setSort
|
|
1712
1752
|
]);
|
|
1713
|
-
/** Attio/GRC's "Remove sort" --
|
|
1714
|
-
*
|
|
1715
|
-
*
|
|
1716
|
-
*
|
|
1753
|
+
/** Attio/GRC's "Remove sort" -- a second way back to no sort at all (the header
|
|
1754
|
+
* click cycle above reaches it too, on a column's third click), exposed for a
|
|
1755
|
+
* column's own header menu (`column-menu.tsx`'s `ColumnMenu`) to offer as a
|
|
1756
|
+
* "Clear sort" item when that column is the sorted one, without three clicks. */ const clearSort = React.useCallback(()=>setSort(undefined), [
|
|
1717
1757
|
setSort
|
|
1718
1758
|
]);
|
|
1719
1759
|
const getHeaderCellProps = React.useCallback((columnKey, sortable)=>{
|
|
@@ -1746,7 +1786,12 @@ function useDataTableSort(props) {
|
|
|
1746
1786
|
sort,
|
|
1747
1787
|
toggleSort,
|
|
1748
1788
|
clearSort,
|
|
1749
|
-
getHeaderCellProps
|
|
1789
|
+
getHeaderCellProps,
|
|
1790
|
+
// Exposed for `useDataTable.ts`'s own composition ONLY (unifying this single
|
|
1791
|
+
// click-to-sort column with `useDataTableToolbarSort`'s ordered list) -- not part
|
|
1792
|
+
// of the documented header-click contract (`toggleSort`/`clearSort` above are),
|
|
1793
|
+
// so no consumer-facing doc comment promotes it as a control of its own.
|
|
1794
|
+
setSort
|
|
1750
1795
|
};
|
|
1751
1796
|
}
|
|
1752
1797
|
|
|
@@ -1850,11 +1895,14 @@ const EMPTY_SORTS = [];
|
|
|
1850
1895
|
* concern rather than folded into `useDataTableSort` (DATATABLE-ATTIO-SPEC.md: "compose,
|
|
1851
1896
|
* don't fatten one hook"). `useDataTableSort` still owns the single click-to-sort
|
|
1852
1897
|
* column/direction a header's own click toggles -- that stays Attio's SECONDARY sort
|
|
1853
|
-
* affordance,
|
|
1854
|
-
*
|
|
1855
|
-
*
|
|
1856
|
-
*
|
|
1857
|
-
* toolbar
|
|
1898
|
+
* affordance, a separate hook from this one. They are NOT independent state, though:
|
|
1899
|
+
* `useDataTable.ts`'s own composition keeps a header-driven column's entry in THIS
|
|
1900
|
+
* array in sync (added/updated/removed as that column's header cycles asc/desc/none),
|
|
1901
|
+
* so a consumer controlling only `toolbarSorts`/`onToolbarSortsChange` still sees a
|
|
1902
|
+
* header click, and the toolbar's own "Remove sort" x on that same entry clears the
|
|
1903
|
+
* header's side too. Multiple conditions apply in list order (sort[0] wins, later ones
|
|
1904
|
+
* break ties; see the styled layer's `applyToolbarSorts`). The styled layer
|
|
1905
|
+
* (`DataTable.tsx`) decides how the merged result actually sorts `data`.
|
|
1858
1906
|
*/ function useDataTableToolbarSort(props) {
|
|
1859
1907
|
const { toolbarSorts: sortsProp, defaultToolbarSorts = EMPTY_SORTS, onToolbarSortsChange } = props;
|
|
1860
1908
|
const [toolbarSorts = EMPTY_SORTS, setToolbarSorts] = useControllableState$1({
|
|
@@ -1939,8 +1987,13 @@ const EMPTY_SORTS = [];
|
|
|
1939
1987
|
// header "is/is not" picker) -- DATATABLE-ATTIO-SPEC.md's Attio/crisp `TableToolbar`
|
|
1940
1988
|
// model is now the PRIMARY filter/sort UX, not a per-column header affordance. They stay
|
|
1941
1989
|
// SEPARATE sub-hooks from `useDataTableSort` rather than folded into it ("compose, don't
|
|
1942
|
-
// fatten one hook") --
|
|
1943
|
-
//
|
|
1990
|
+
// fatten one hook") -- but this composition point below DOES reconcile the two into one
|
|
1991
|
+
// state (the two `useEffect`s after `infiniteScroll`), so a header click and the
|
|
1992
|
+
// toolbar's own Sort popover always agree on what's sorted, regardless of which prop
|
|
1993
|
+
// pair (`sort`/`onSortChange` or `toolbarSorts`/`onToolbarSortsChange`) a consumer
|
|
1994
|
+
// actually controls. `DataTable.tsx` (styled) still decides how the RESULT actually
|
|
1995
|
+
// sorts `data` (`effectiveSorts`/`applyToolbarSorts`) -- this layer only keeps the two
|
|
1996
|
+
// STATE pools in agreement.
|
|
1944
1997
|
function useDataTable(props) {
|
|
1945
1998
|
const sort = useDataTableSort(props);
|
|
1946
1999
|
const selection = useDataTableSelection(props);
|
|
@@ -1963,6 +2016,105 @@ function useDataTable(props) {
|
|
|
1963
2016
|
...props,
|
|
1964
2017
|
scrollRootRef: scroll.elementRef
|
|
1965
2018
|
});
|
|
2019
|
+
// Unifies `sort` (the header's own single click-to-sort column, above) with
|
|
2020
|
+
// `toolbarSort.toolbarSorts` (the toolbar Sort popover's ordered list, above) into
|
|
2021
|
+
// ONE state instead of two -- before this, a header click only ever moved `sort`,
|
|
2022
|
+
// invisible to a consumer controlling `toolbarSorts`/`onToolbarSortsChange` (the
|
|
2023
|
+
// reported bug: clicking a header did nothing to the array the consumer's own Sort
|
|
2024
|
+
// popover reads, so the toolbar's "Sort" trigger/count and its popover rows silently
|
|
2025
|
+
// ignored every header click).
|
|
2026
|
+
//
|
|
2027
|
+
// ONE effect, not two -- an earlier version split this into a forward
|
|
2028
|
+
// (`sort` -> `toolbarSorts`) and a reverse (`toolbarSorts` -> `sort`) effect, each
|
|
2029
|
+
// keyed off its own dependency. That raced on the very first render: `useEffect`
|
|
2030
|
+
// runs every effect once on mount regardless of what "changed", so with
|
|
2031
|
+
// `defaultSort` set, the reverse effect ran in the SAME commit as the forward one,
|
|
2032
|
+
// read `toolbarSorts` BEFORE the forward effect's own (still-queued, not yet
|
|
2033
|
+
// re-rendered) write had landed, saw no entry for the column yet, and immediately
|
|
2034
|
+
// cleared `sort` right back out -- the defaultSort silently never took effect.
|
|
2035
|
+
// `settledRef` sidesteps this: it remembers the last `{key,dir}` this effect itself
|
|
2036
|
+
// confirmed, so on every run it can tell WHICH side moved since then, instead of
|
|
2037
|
+
// guessing from which dependency happens to have triggered the re-run.
|
|
2038
|
+
const settledRef = React.useRef({
|
|
2039
|
+
key: undefined,
|
|
2040
|
+
dir: undefined
|
|
2041
|
+
});
|
|
2042
|
+
React.useEffect(()=>{
|
|
2043
|
+
const curSort = sort.sort;
|
|
2044
|
+
const curEntry = curSort ? toolbarSort.toolbarSorts.find((s)=>s.key === curSort.key) : undefined;
|
|
2045
|
+
const settled = settledRef.current;
|
|
2046
|
+
const sortUnchangedSinceSettled = settled.key === curSort?.key && settled.dir === curSort?.dir;
|
|
2047
|
+
if (sortUnchangedSinceSettled) {
|
|
2048
|
+
// `sort` itself hasn't moved since we last settled -- if this effect is running
|
|
2049
|
+
// at all, `toolbarSorts` is what changed, so REVERSE-sync: the toolbar Sort
|
|
2050
|
+
// popover's own "Remove sort" x, or its direction select, touching this exact
|
|
2051
|
+
// column. Never reaches across to adopt some OTHER column added independently
|
|
2052
|
+
// via that popover -- only the column `sort` is already tracking.
|
|
2053
|
+
if (!curSort) return;
|
|
2054
|
+
if (!curEntry) {
|
|
2055
|
+
sort.clearSort();
|
|
2056
|
+
settledRef.current = {
|
|
2057
|
+
key: undefined,
|
|
2058
|
+
dir: undefined
|
|
2059
|
+
};
|
|
2060
|
+
} else if (curEntry.dir !== curSort.dir) {
|
|
2061
|
+
sort.setSort({
|
|
2062
|
+
key: curSort.key,
|
|
2063
|
+
dir: curEntry.dir
|
|
2064
|
+
});
|
|
2065
|
+
settledRef.current = {
|
|
2066
|
+
key: curSort.key,
|
|
2067
|
+
dir: curEntry.dir
|
|
2068
|
+
};
|
|
2069
|
+
}
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
// `sort` moved (a header click, Enter/Space, or `clearSort` -- column-menu.tsx's
|
|
2073
|
+
// menu item calls that directly, bypassing `toggleSort`) -- FORWARD-sync:
|
|
2074
|
+
// add/update/remove THIS column's own entry in `toolbarSorts`, leaving every
|
|
2075
|
+
// OTHER entry (added independently via the toolbar's own "+ Add sort") untouched.
|
|
2076
|
+
// The functional updater reads the CURRENT array off `current`, never off
|
|
2077
|
+
// `toolbarSort.toolbarSorts` in this closure, so a stale render can never clobber
|
|
2078
|
+
// an entry the toolbar's own popover added a moment earlier.
|
|
2079
|
+
const prevKey = settled.key;
|
|
2080
|
+
toolbarSort.setToolbarSorts((current)=>{
|
|
2081
|
+
let updated = current;
|
|
2082
|
+
if (prevKey && prevKey !== curSort?.key) {
|
|
2083
|
+
updated = updated.filter((s)=>s.key !== prevKey);
|
|
2084
|
+
}
|
|
2085
|
+
if (curSort) {
|
|
2086
|
+
const idx = updated.findIndex((s)=>s.key === curSort.key);
|
|
2087
|
+
if (idx === -1) {
|
|
2088
|
+
updated = [
|
|
2089
|
+
...updated,
|
|
2090
|
+
{
|
|
2091
|
+
key: curSort.key,
|
|
2092
|
+
dir: curSort.dir
|
|
2093
|
+
}
|
|
2094
|
+
];
|
|
2095
|
+
} else if (updated[idx].dir !== curSort.dir) {
|
|
2096
|
+
updated = updated.map((s, i)=>i === idx ? {
|
|
2097
|
+
...s,
|
|
2098
|
+
dir: curSort.dir
|
|
2099
|
+
} : s);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
return updated;
|
|
2103
|
+
});
|
|
2104
|
+
settledRef.current = curSort ? {
|
|
2105
|
+
key: curSort.key,
|
|
2106
|
+
dir: curSort.dir
|
|
2107
|
+
} : {
|
|
2108
|
+
key: undefined,
|
|
2109
|
+
dir: undefined
|
|
2110
|
+
};
|
|
2111
|
+
}, [
|
|
2112
|
+
sort.sort,
|
|
2113
|
+
toolbarSort.toolbarSorts,
|
|
2114
|
+
toolbarSort.setToolbarSorts,
|
|
2115
|
+
sort.clearSort,
|
|
2116
|
+
sort.setSort
|
|
2117
|
+
]);
|
|
1966
2118
|
return {
|
|
1967
2119
|
...sort,
|
|
1968
2120
|
...selection,
|
|
@@ -2558,11 +2710,70 @@ CheckboxIndicator.displayName = "CheckboxIndicator";
|
|
|
2558
2710
|
const CheckboxLabel = withContext$6(withStateProps$4(Primitive.span), "label");
|
|
2559
2711
|
const CheckboxHiddenInput = reactCheckbox.Checkbox.HiddenInput;
|
|
2560
2712
|
|
|
2561
|
-
const {
|
|
2713
|
+
const { ClassNamesProvider: ClassNamesProvider$2, withContext: withContext$5, useClassNames: useClassNames$2 } = createSlotRecipeContext(menu.menu);
|
|
2714
|
+
const { PropsProvider: ItemPropsProvider$1, useProps: useItemProps$1, withContext: withItemContext$1, ClassNamesProvider: ItemClassNamesProvider$1 } = createSlotRecipeContext(menuItem.menuItem);
|
|
2715
|
+
const withStateProps$3 = createWithStateProps([
|
|
2716
|
+
reactMenu.useMenuContext
|
|
2717
|
+
]);
|
|
2718
|
+
const withItemStateProps$1 = createWithStateProps([
|
|
2719
|
+
reactMenu.useMenuItemContext
|
|
2720
|
+
]);
|
|
2721
|
+
const MenuRoot = (props)=>{
|
|
2722
|
+
const [variantProps, otherProps] = menu.menu.splitVariantProps(props);
|
|
2723
|
+
const classNames = menu.menu(variantProps);
|
|
2724
|
+
return /*#__PURE__*/ jsxRuntime.jsx(ClassNamesProvider$2, {
|
|
2725
|
+
value: classNames,
|
|
2726
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(ItemPropsProvider$1, {
|
|
2727
|
+
value: {
|
|
2728
|
+
size: variantProps.size
|
|
2729
|
+
},
|
|
2730
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(reactMenu.Menu.Root, {
|
|
2731
|
+
...otherProps
|
|
2732
|
+
})
|
|
2733
|
+
})
|
|
2734
|
+
});
|
|
2735
|
+
};
|
|
2736
|
+
const MenuAnchor = reactMenu.Menu.Anchor;
|
|
2737
|
+
const MenuTrigger = reactMenu.Menu.Trigger;
|
|
2738
|
+
const MenuPositioner = /*#__PURE__*/ React__namespace.forwardRef(({ className, ...props }, ref)=>{
|
|
2739
|
+
const classNames = useClassNames$2();
|
|
2740
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactMenu.Menu.Positioner, {
|
|
2741
|
+
ref: ref,
|
|
2742
|
+
className: clsx(classNames.positioner, className),
|
|
2743
|
+
...props
|
|
2744
|
+
});
|
|
2745
|
+
});
|
|
2746
|
+
MenuPositioner.displayName = "MenuPositioner";
|
|
2747
|
+
const MenuContent = withContext$5(reactMenu.Menu.Content, "content");
|
|
2748
|
+
const MenuScrollArea = withContext$5(withStateProps$3(Primitive.div), "scrollArea");
|
|
2749
|
+
withContext$5(reactMenu.Menu.Group, "group");
|
|
2750
|
+
withContext$5(reactMenu.Menu.GroupLabel, "groupLabel");
|
|
2751
|
+
const MenuItem = /*#__PURE__*/ React__namespace.forwardRef(({ className: propClassName, ...props }, ref)=>{
|
|
2752
|
+
const [variantProps, otherProps] = menuItem.menuItem.splitVariantProps(props);
|
|
2753
|
+
const parentProps = useItemProps$1();
|
|
2754
|
+
const classNames = menuItem.menuItem({
|
|
2755
|
+
...parentProps,
|
|
2756
|
+
...variantProps
|
|
2757
|
+
});
|
|
2758
|
+
return /*#__PURE__*/ jsxRuntime.jsx(ItemClassNamesProvider$1, {
|
|
2759
|
+
value: classNames,
|
|
2760
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(reactMenu.Menu.Item, {
|
|
2761
|
+
ref: ref,
|
|
2762
|
+
className: clsx(classNames.root, propClassName),
|
|
2763
|
+
...otherProps
|
|
2764
|
+
})
|
|
2765
|
+
});
|
|
2766
|
+
});
|
|
2767
|
+
MenuItem.displayName = "MenuItem";
|
|
2768
|
+
withItemContext$1(withItemStateProps$1(Primitive.div), "body");
|
|
2769
|
+
const MenuItemLabel = withItemContext$1(withItemStateProps$1(Primitive.span), "label");
|
|
2770
|
+
withItemContext$1(withItemStateProps$1(Primitive.span), "description");
|
|
2771
|
+
|
|
2772
|
+
const { withProvider: withProvider$2, withContext: withContext$4 } = createSlotRecipeContext(avatar.avatar);
|
|
2562
2773
|
const AvatarRoot = withProvider$2(reactImage.Image.Root, "root");
|
|
2563
|
-
const AvatarImage = withContext$
|
|
2564
|
-
const AvatarFallback = withContext$
|
|
2565
|
-
withContext$
|
|
2774
|
+
const AvatarImage = withContext$4(reactImage.Image.Content, "image");
|
|
2775
|
+
const AvatarFallback = withContext$4(reactImage.Image.Fallback, "fallback");
|
|
2776
|
+
withContext$4(Primitive.div, "badge");
|
|
2566
2777
|
|
|
2567
2778
|
const Badge = /*#__PURE__*/ React.forwardRef(({ className, children, ...props }, ref)=>{
|
|
2568
2779
|
const [variantProps, restProps] = badge.badge.splitVariantProps(props);
|
|
@@ -3106,6 +3317,141 @@ function RatingCell({ value, maxRating = 5 }) {
|
|
|
3106
3317
|
});
|
|
3107
3318
|
}
|
|
3108
3319
|
|
|
3320
|
+
/** Clear is withheld for `chip-list`: that column already owns its own per-tag remove
|
|
3321
|
+
* affordance (`ChipListEditor`) and commits a JSON-STRINGIFIED array through `onEdit`
|
|
3322
|
+
* (`DataTable.chips.test.tsx`'s own `TagsHarness` -- and this package's own Storybook
|
|
3323
|
+
* demo, `CellFeaturesDemo`, does exactly `JSON.parse(value)` on commit) -- committing
|
|
3324
|
+
* a bare `""` through that same path throws in the consumer's `onEdit`, it doesn't
|
|
3325
|
+
* clear anything. Every OTHER editable shape's commit value is a plain string
|
|
3326
|
+
* (`"true"`/`"false"`, a stringified rating, an option's own `value`, free text) that
|
|
3327
|
+
* a consumer's `onEdit` already has to accept a possibly-empty version of. */ function isClearableEditableCell(column) {
|
|
3328
|
+
return !!column.editable && column.type !== "chip-list";
|
|
3329
|
+
}
|
|
3330
|
+
/** Paste is narrower still -- restricted to a PLAIN `editable` column (no `editor`,
|
|
3331
|
+
* and not one of the always-live widget types) whose committed value IS the raw
|
|
3332
|
+
* text/number a user typed. `select`/`reference`/`actor` expect one of THEIR OWN
|
|
3333
|
+
* option values (not arbitrary clipboard text), `switch`/`rating`/`checkbox` are
|
|
3334
|
+
* always-live widgets with their own encoding, and `chip-list` is excluded for the
|
|
3335
|
+
* same JSON reason `isClearableEditableCell` documents above. This is the task's own
|
|
3336
|
+
* "only for simple editable text/number cells" guard -- committing pasted text
|
|
3337
|
+
* through any of the excluded shapes would corrupt the row rather than edit it
|
|
3338
|
+
* (crispy-seed's own #1094 lesson: never assume an editor's commit shape).
|
|
3339
|
+
*/ function isSimpleEditableCell(column) {
|
|
3340
|
+
if (!column.editable) return false;
|
|
3341
|
+
if (column.editor) return false;
|
|
3342
|
+
if (column.type === "chip-list" || column.type === "checkbox" || column.type === "rating") {
|
|
3343
|
+
return false;
|
|
3344
|
+
}
|
|
3345
|
+
return true;
|
|
3346
|
+
}
|
|
3347
|
+
/** Copy's own text representation -- deliberately mirrors `DisplayCellContent`'s
|
|
3348
|
+
* (body-cells.tsx) switch closely enough to read the same as what's on screen, but
|
|
3349
|
+
* returns a plain string (`navigator.clipboard.writeText`) rather than JSX. Not
|
|
3350
|
+
* exported -- it exists only to feed Copy, not as a general-purpose formatter. */ function cellValueAsText(column, value, locale) {
|
|
3351
|
+
if (value == null) return "";
|
|
3352
|
+
switch(column.type){
|
|
3353
|
+
case "entity":
|
|
3354
|
+
if (typeof value === "object") return String(value.name ?? "");
|
|
3355
|
+
return String(value);
|
|
3356
|
+
case "tags":
|
|
3357
|
+
case "chip-list":
|
|
3358
|
+
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
3359
|
+
case "number":
|
|
3360
|
+
return typeof value === "number" ? String(formatNumberCell(value, locale) ?? "") : String(value);
|
|
3361
|
+
case "currency":
|
|
3362
|
+
return typeof value === "number" ? String(formatCurrencyCell(value, column.symbol ?? "$", locale) ?? "") : String(value);
|
|
3363
|
+
case "date":
|
|
3364
|
+
return String(formatDateCell(value, locale) ?? "");
|
|
3365
|
+
case "datetime":
|
|
3366
|
+
return String(formatDateTimeCell(value, locale) ?? "");
|
|
3367
|
+
case "checkbox":
|
|
3368
|
+
return value === true || value === "true" ? "true" : "false";
|
|
3369
|
+
default:
|
|
3370
|
+
return String(value);
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
/**
|
|
3374
|
+
* One cell's right-click menu -- mounted by `body-cells.tsx`'s `DataTableBodyCell`
|
|
3375
|
+
* only while actually open (the same "don't keep an unused floating-ui instance alive
|
|
3376
|
+
* per cell" reasoning as that file's own portaled chip-list popover), so this never
|
|
3377
|
+
* costs anything for the row×column cells a user never right-clicks.
|
|
3378
|
+
*/ function CellContextMenu({ column, row, value, locale, point, open, onOpenChange, onCommit, onViewEditHistory, cellContextMenuItems }) {
|
|
3379
|
+
const clearable = isClearableEditableCell(column);
|
|
3380
|
+
const pasteable = isSimpleEditableCell(column);
|
|
3381
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(MenuRoot, {
|
|
3382
|
+
open: open,
|
|
3383
|
+
onOpenChange: onOpenChange,
|
|
3384
|
+
placement: "bottom-start",
|
|
3385
|
+
strategy: "fixed",
|
|
3386
|
+
gutter: 2,
|
|
3387
|
+
children: [
|
|
3388
|
+
/*#__PURE__*/ jsxRuntime.jsx(MenuAnchor, {
|
|
3389
|
+
"aria-hidden": true,
|
|
3390
|
+
style: {
|
|
3391
|
+
position: "fixed",
|
|
3392
|
+
top: point.y,
|
|
3393
|
+
left: point.x,
|
|
3394
|
+
width: 0,
|
|
3395
|
+
height: 0,
|
|
3396
|
+
pointerEvents: "none"
|
|
3397
|
+
}
|
|
3398
|
+
}),
|
|
3399
|
+
/*#__PURE__*/ jsxRuntime.jsx(MenuPositioner, {
|
|
3400
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(MenuContent, {
|
|
3401
|
+
style: {
|
|
3402
|
+
minWidth: 180
|
|
3403
|
+
},
|
|
3404
|
+
children: /*#__PURE__*/ jsxRuntime.jsxs(MenuScrollArea, {
|
|
3405
|
+
children: [
|
|
3406
|
+
/*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
|
|
3407
|
+
onClick: ()=>{
|
|
3408
|
+
const text = cellValueAsText(column, value, locale);
|
|
3409
|
+
// Best-effort: an insecure context or a denied permission rejects
|
|
3410
|
+
// this silently (no `MenuItem` state depends on the outcome) --
|
|
3411
|
+
// there's nothing else for a plain "Copy" item to do about a
|
|
3412
|
+
// browser that refused the write.
|
|
3413
|
+
void navigator.clipboard?.writeText?.(text);
|
|
3414
|
+
},
|
|
3415
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
|
|
3416
|
+
children: "Copy"
|
|
3417
|
+
})
|
|
3418
|
+
}),
|
|
3419
|
+
pasteable && /*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
|
|
3420
|
+
onClick: ()=>{
|
|
3421
|
+
void navigator.clipboard?.readText?.().then((text)=>onCommit(text)).catch(()=>{
|
|
3422
|
+
// Clipboard read denied/unavailable -- best-effort, same
|
|
3423
|
+
// reasoning as Copy above.
|
|
3424
|
+
});
|
|
3425
|
+
},
|
|
3426
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
|
|
3427
|
+
children: "Paste"
|
|
3428
|
+
})
|
|
3429
|
+
}),
|
|
3430
|
+
clearable && /*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
|
|
3431
|
+
onClick: ()=>onCommit(""),
|
|
3432
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
|
|
3433
|
+
children: "Clear value"
|
|
3434
|
+
})
|
|
3435
|
+
}),
|
|
3436
|
+
onViewEditHistory && /*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
|
|
3437
|
+
onClick: ()=>onViewEditHistory(row, column.key),
|
|
3438
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
|
|
3439
|
+
children: "View edit history"
|
|
3440
|
+
})
|
|
3441
|
+
}),
|
|
3442
|
+
cellContextMenuItems?.({
|
|
3443
|
+
row,
|
|
3444
|
+
column,
|
|
3445
|
+
value
|
|
3446
|
+
})
|
|
3447
|
+
]
|
|
3448
|
+
})
|
|
3449
|
+
})
|
|
3450
|
+
})
|
|
3451
|
+
]
|
|
3452
|
+
});
|
|
3453
|
+
}
|
|
3454
|
+
|
|
3109
3455
|
/** Fallback width (px) used to compute a pinned column's cumulative sticky offset when
|
|
3110
3456
|
* it has no explicit `width` and hasn't been drag-resized -- pinning needs a STATIC
|
|
3111
3457
|
* number to put in an inline `insetInlineStart`, and `table-layout: fixed` only
|
|
@@ -3264,11 +3610,11 @@ function RatingCell({ value, maxRating = 5 }) {
|
|
|
3264
3610
|
// recipe, so a per-instance variant can override the root's default.
|
|
3265
3611
|
const { ClassNamesProvider: TriggerClassNamesProvider, PropsProvider: TriggerPropsProvider, useProps: useTriggerProps, withContext: withTriggerContext, useClassNames: useTriggerClassNames } = createSlotRecipeContext(selectTrigger.selectTrigger);
|
|
3266
3612
|
const { ClassNamesProvider: ContentClassNamesProvider, withContext: withContentContext, useClassNames: useContentClassNames } = createSlotRecipeContext(select.select);
|
|
3267
|
-
const { ClassNamesProvider: ItemClassNamesProvider
|
|
3268
|
-
const withStateProps$
|
|
3613
|
+
const { ClassNamesProvider: ItemClassNamesProvider, PropsProvider: ItemPropsProvider, useProps: useItemProps, withContext: withItemContext, useClassNames: useItemClassNames } = createSlotRecipeContext(selectItem.selectItem);
|
|
3614
|
+
const withStateProps$2 = createWithStateProps([
|
|
3269
3615
|
reactSelect.useSelectContext
|
|
3270
3616
|
]);
|
|
3271
|
-
const withItemStateProps
|
|
3617
|
+
const withItemStateProps = createWithStateProps([
|
|
3272
3618
|
reactSelect.useSelectItemContext
|
|
3273
3619
|
]);
|
|
3274
3620
|
// NOTE: `gutter` and `overflowPadding` are specified in Rootage (`select.yaml`,
|
|
@@ -3289,7 +3635,7 @@ const SelectRoot = (props)=>{
|
|
|
3289
3635
|
value: contentClassNames,
|
|
3290
3636
|
children: /*#__PURE__*/ jsxRuntime.jsx(TriggerPropsProvider, {
|
|
3291
3637
|
value: triggerVariantProps,
|
|
3292
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(ItemPropsProvider
|
|
3638
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(ItemPropsProvider, {
|
|
3293
3639
|
value: itemVariantProps,
|
|
3294
3640
|
children: /*#__PURE__*/ jsxRuntime.jsx(reactSelect.Select.Root, {
|
|
3295
3641
|
...otherProps
|
|
@@ -3329,8 +3675,8 @@ const SelectTrigger = /*#__PURE__*/ React__namespace.forwardRef(({ className, ..
|
|
|
3329
3675
|
});
|
|
3330
3676
|
});
|
|
3331
3677
|
SelectTrigger.displayName = "SelectTrigger";
|
|
3332
|
-
const SelectValue = withTriggerContext(withStateProps$
|
|
3333
|
-
const SelectPlaceholder = withTriggerContext(withStateProps$
|
|
3678
|
+
const SelectValue = withTriggerContext(withStateProps$2(reactSelect.Select.Value), "value");
|
|
3679
|
+
const SelectPlaceholder = withTriggerContext(withStateProps$2(reactSelect.Select.Placeholder), "placeholder");
|
|
3334
3680
|
const SelectPrefixIcon = /*#__PURE__*/ React__namespace.forwardRef(({ fallback, className, ...otherProps }, ref)=>{
|
|
3335
3681
|
const { selectedItem, stateProps } = reactSelect.useSelectContext();
|
|
3336
3682
|
const classNames = useTriggerClassNames();
|
|
@@ -3345,7 +3691,7 @@ const SelectPrefixIcon = /*#__PURE__*/ React__namespace.forwardRef(({ fallback,
|
|
|
3345
3691
|
});
|
|
3346
3692
|
});
|
|
3347
3693
|
SelectPrefixIcon.displayName = "SelectPrefixIcon";
|
|
3348
|
-
const SelectSuffixIcon = withTriggerContext(withStateProps$
|
|
3694
|
+
const SelectSuffixIcon = withTriggerContext(withStateProps$2(InternalIcon), "suffixIcon");
|
|
3349
3695
|
const SelectPositioner = /*#__PURE__*/ React__namespace.forwardRef(({ className, ...props }, ref)=>{
|
|
3350
3696
|
const classNames = useContentClassNames();
|
|
3351
3697
|
return /*#__PURE__*/ jsxRuntime.jsx(reactSelect.Select.Positioner, {
|
|
@@ -3376,12 +3722,12 @@ withContentContext(reactSelect.Select.Group, "group");
|
|
|
3376
3722
|
withContentContext(reactSelect.Select.GroupLabel, "groupLabel");
|
|
3377
3723
|
const SelectItem = /*#__PURE__*/ React__namespace.forwardRef(({ prefixIcon, className, ...props }, ref)=>{
|
|
3378
3724
|
const [variantProps, otherProps] = selectItem.selectItem.splitVariantProps(props);
|
|
3379
|
-
const rootProps = useItemProps
|
|
3725
|
+
const rootProps = useItemProps();
|
|
3380
3726
|
const classNames = selectItem.selectItem({
|
|
3381
3727
|
...rootProps,
|
|
3382
3728
|
...variantProps
|
|
3383
3729
|
});
|
|
3384
|
-
return /*#__PURE__*/ jsxRuntime.jsx(ItemClassNamesProvider
|
|
3730
|
+
return /*#__PURE__*/ jsxRuntime.jsx(ItemClassNamesProvider, {
|
|
3385
3731
|
value: classNames,
|
|
3386
3732
|
children: /*#__PURE__*/ jsxRuntime.jsx(reactSelect.Select.Item, {
|
|
3387
3733
|
ref: ref,
|
|
@@ -3406,7 +3752,7 @@ const SelectItemPrefixIcon = /*#__PURE__*/ React__namespace.forwardRef(({ svg: s
|
|
|
3406
3752
|
});
|
|
3407
3753
|
});
|
|
3408
3754
|
SelectItemPrefixIcon.displayName = "SelectItemPrefixIcon";
|
|
3409
|
-
const SelectItemBody = withItemContext
|
|
3755
|
+
const SelectItemBody = withItemContext(withItemStateProps(Primitive.div), "body");
|
|
3410
3756
|
const SelectItemLabel = /*#__PURE__*/ React__namespace.forwardRef(({ children, className, ...otherProps }, ref)=>{
|
|
3411
3757
|
const { label, stateProps } = reactSelect.useSelectItemContext();
|
|
3412
3758
|
const classNames = useItemClassNames();
|
|
@@ -3421,7 +3767,7 @@ const SelectItemLabel = /*#__PURE__*/ React__namespace.forwardRef(({ children, c
|
|
|
3421
3767
|
});
|
|
3422
3768
|
});
|
|
3423
3769
|
SelectItemLabel.displayName = "SelectItemLabel";
|
|
3424
|
-
withItemContext
|
|
3770
|
+
withItemContext(withItemStateProps(Primitive.span), "description");
|
|
3425
3771
|
const SelectItemIndicator = /*#__PURE__*/ React__namespace.forwardRef(({ selected: selectedSvg, unselected: unselectedSvg, className, ...otherProps }, ref)=>{
|
|
3426
3772
|
const { isSelected, stateProps } = reactSelect.useSelectItemContext();
|
|
3427
3773
|
const classNames = useItemClassNames();
|
|
@@ -3453,9 +3799,9 @@ const SelectHiddenSelect = /*#__PURE__*/ React__namespace.forwardRef((props, ref
|
|
|
3453
3799
|
});
|
|
3454
3800
|
SelectHiddenSelect.displayName = "SelectHiddenSelect";
|
|
3455
3801
|
|
|
3456
|
-
const { withContext: withContext$
|
|
3802
|
+
const { withContext: withContext$3, ClassNamesProvider: ClassNamesProvider$1 } = createSlotRecipeContext(_switch.switchStyle);
|
|
3457
3803
|
const { withContext: withControlContext, PropsProvider: ControlPropsProvider, withProvider: withControlProvider } = createSlotRecipeContext(switchmark.switchmark);
|
|
3458
|
-
const withStateProps$
|
|
3804
|
+
const withStateProps$1 = createWithStateProps([
|
|
3459
3805
|
reactSwitch.useSwitchContext
|
|
3460
3806
|
]);
|
|
3461
3807
|
const SwitchRoot = /*#__PURE__*/ React__namespace.default.forwardRef(({ className, ...props }, ref)=>{
|
|
@@ -3466,7 +3812,7 @@ const SwitchRoot = /*#__PURE__*/ React__namespace.default.forwardRef(({ classNam
|
|
|
3466
3812
|
const classNames = _switch.switchStyle(switchVariantProps);
|
|
3467
3813
|
return /*#__PURE__*/ jsxRuntime.jsx(ControlPropsProvider, {
|
|
3468
3814
|
value: switchmarkVariantProps,
|
|
3469
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(ClassNamesProvider$
|
|
3815
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(ClassNamesProvider$1, {
|
|
3470
3816
|
value: classNames,
|
|
3471
3817
|
children: /*#__PURE__*/ jsxRuntime.jsx(reactSwitch.Switch.Root, {
|
|
3472
3818
|
ref: ref,
|
|
@@ -3479,20 +3825,20 @@ const SwitchRoot = /*#__PURE__*/ React__namespace.default.forwardRef(({ classNam
|
|
|
3479
3825
|
SwitchRoot.displayName = "SwitchRoot";
|
|
3480
3826
|
const SwitchControl = withScaleFeedback(withControlProvider(reactSwitch.Switch.Control, "root"));
|
|
3481
3827
|
const SwitchThumb = withControlContext(reactSwitch.Switch.Thumb, "thumb");
|
|
3482
|
-
withContext$
|
|
3828
|
+
withContext$3(withStateProps$1(Primitive.span), "label");
|
|
3483
3829
|
const SwitchHiddenInput = reactSwitch.Switch.HiddenInput;
|
|
3484
3830
|
|
|
3485
3831
|
// src/use-layout-effect.tsx
|
|
3486
3832
|
var useLayoutEffect2 = globalThis?.document ? React__namespace.useLayoutEffect : ()=>{};
|
|
3487
3833
|
|
|
3488
|
-
const { withProvider: withProvider$1, withContext: withContext$
|
|
3834
|
+
const { withProvider: withProvider$1, withContext: withContext$2, useClassNames: useClassNames$1 } = createSlotRecipeContext(textInput.textInput);
|
|
3489
3835
|
const withFieldStateProps = createWithStateProps([
|
|
3490
3836
|
{
|
|
3491
3837
|
useContext: reactField.useFieldContext,
|
|
3492
3838
|
strict: false
|
|
3493
3839
|
}
|
|
3494
3840
|
]);
|
|
3495
|
-
const withStateProps
|
|
3841
|
+
const withStateProps = createWithStateProps([
|
|
3496
3842
|
reactTextField.useTextFieldContext,
|
|
3497
3843
|
{
|
|
3498
3844
|
useContext: reactField.useFieldContext,
|
|
@@ -3500,12 +3846,12 @@ const withStateProps$1 = createWithStateProps([
|
|
|
3500
3846
|
}
|
|
3501
3847
|
]);
|
|
3502
3848
|
const TextFieldRoot = withProvider$1(withFieldStateProps(reactTextField.TextField.Root), "root");
|
|
3503
|
-
withContext$
|
|
3504
|
-
withContext$
|
|
3505
|
-
withContext$
|
|
3506
|
-
withContext$
|
|
3849
|
+
withContext$2(withStateProps(InternalIcon), "prefixIcon");
|
|
3850
|
+
withContext$2(withStateProps(Primitive.span), "prefixText");
|
|
3851
|
+
withContext$2(withStateProps(InternalIcon), "suffixIcon");
|
|
3852
|
+
withContext$2(withStateProps(Primitive.span), "suffixText");
|
|
3507
3853
|
const TextFieldInput = /*#__PURE__*/ React.forwardRef(({ className, ...otherProps }, ref)=>{
|
|
3508
|
-
const classNames = useClassNames$
|
|
3854
|
+
const classNames = useClassNames$1();
|
|
3509
3855
|
const textFieldContext = reactTextField.useTextFieldContext();
|
|
3510
3856
|
const fieldContext = reactField.useFieldContext({
|
|
3511
3857
|
strict: false
|
|
@@ -3523,7 +3869,7 @@ const TextFieldInput = /*#__PURE__*/ React.forwardRef(({ className, ...otherProp
|
|
|
3523
3869
|
});
|
|
3524
3870
|
TextFieldInput.displayName = "TextFieldInput";
|
|
3525
3871
|
const TextFieldTextarea = /*#__PURE__*/ React.forwardRef(({ className, autoresize = true, ...otherProps }, ref)=>{
|
|
3526
|
-
const classNames = useClassNames$
|
|
3872
|
+
const classNames = useClassNames$1();
|
|
3527
3873
|
const textFieldContext = reactTextField.useTextFieldContext();
|
|
3528
3874
|
const fieldContext = reactField.useFieldContext({
|
|
3529
3875
|
strict: false
|
|
@@ -3580,7 +3926,7 @@ const TextFieldTextarea = /*#__PURE__*/ React.forwardRef(({ className, autoresiz
|
|
|
3580
3926
|
});
|
|
3581
3927
|
TextFieldTextarea.displayName = "TextFieldTextarea";
|
|
3582
3928
|
|
|
3583
|
-
__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))}");
|
|
3929
|
+
__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))}");
|
|
3584
3930
|
|
|
3585
3931
|
const createClassName = (className, variants, compoundVariants = [])=>{
|
|
3586
3932
|
const variantKeys = Object.keys(variants);
|
|
@@ -3774,6 +4120,22 @@ const dataTableSlotNames = [
|
|
|
3774
4120
|
[
|
|
3775
4121
|
"selectionCell",
|
|
3776
4122
|
"seed-data-table__selectionCell"
|
|
4123
|
+
],
|
|
4124
|
+
[
|
|
4125
|
+
"bulkBar",
|
|
4126
|
+
"seed-data-table__bulkBar"
|
|
4127
|
+
],
|
|
4128
|
+
[
|
|
4129
|
+
"bulkBarCount",
|
|
4130
|
+
"seed-data-table__bulkBarCount"
|
|
4131
|
+
],
|
|
4132
|
+
[
|
|
4133
|
+
"bulkBarClear",
|
|
4134
|
+
"seed-data-table__bulkBarClear"
|
|
4135
|
+
],
|
|
4136
|
+
[
|
|
4137
|
+
"bulkBarActions",
|
|
4138
|
+
"seed-data-table__bulkBarActions"
|
|
3777
4139
|
]
|
|
3778
4140
|
];
|
|
3779
4141
|
const defaultVariant$6 = {
|
|
@@ -3811,7 +4173,7 @@ Object.assign(dataTable, {
|
|
|
3811
4173
|
// other file (`DataTable.tsx`, `column-menu.tsx`, `resize.tsx`, `column-calc.tsx`,
|
|
3812
4174
|
// `toolbar.tsx`, `body-cells.tsx`, `editors.tsx`) imports its exports from here rather
|
|
3813
4175
|
// than re-deriving its own.
|
|
3814
|
-
const { ClassNamesProvider
|
|
4176
|
+
const { ClassNamesProvider, withContext: withContext$1, useClassNames } = createSlotRecipeContext(dataTable);
|
|
3815
4177
|
|
|
3816
4178
|
/**
|
|
3817
4179
|
* The pure filter itself, split out of `useSelectSearch` below so it can be
|
|
@@ -4519,7 +4881,7 @@ function isCellTruncated(cell) {
|
|
|
4519
4881
|
* actually reported against a pinned column. */ function isChipListEditable(column) {
|
|
4520
4882
|
return !!column.editable && column.type === "chip-list";
|
|
4521
4883
|
}
|
|
4522
|
-
function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyFirst, stickyLast }) {
|
|
4884
|
+
function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyFirst, stickyLast, cellContextMenu, onViewEditHistory, cellContextMenuItems }) {
|
|
4523
4885
|
const effective = useEffectiveColumns(columns, {
|
|
4524
4886
|
selectable,
|
|
4525
4887
|
stickyFirst
|
|
@@ -4534,7 +4896,10 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4534
4896
|
row: row,
|
|
4535
4897
|
classNames: classNames,
|
|
4536
4898
|
locale: locale,
|
|
4537
|
-
sticky: sticky
|
|
4899
|
+
sticky: sticky,
|
|
4900
|
+
cellContextMenu: cellContextMenu,
|
|
4901
|
+
onViewEditHistory: onViewEditHistory,
|
|
4902
|
+
cellContextMenuItems: cellContextMenuItems
|
|
4538
4903
|
}, column.key);
|
|
4539
4904
|
})
|
|
4540
4905
|
});
|
|
@@ -4546,7 +4911,7 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4546
4911
|
* on every row's render. React keeps this instance stable across re-renders because
|
|
4547
4912
|
* `ColumnBodyCells` keys it by `column.key` the same way it always keyed the bare
|
|
4548
4913
|
* `<DataTableCell>` before this split.
|
|
4549
|
-
*/ function DataTableBodyCell({ column, row, classNames, locale, sticky }) {
|
|
4914
|
+
*/ function DataTableBodyCell({ column, row, classNames, locale, sticky, cellContextMenu, onViewEditHistory, cellContextMenuItems }) {
|
|
4550
4915
|
const { startEdit, cancelEdit, isEditing, isPending, commitEdit, isPeeking, openPeek, closePeek } = useDataTableContext();
|
|
4551
4916
|
const cellRef = React__namespace.useRef(null);
|
|
4552
4917
|
// Feature B rework (#8) -- the chip-list popover's own live position, in VIEWPORT
|
|
@@ -4562,6 +4927,16 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4562
4927
|
// editable cell's existing double-click-to-edit (tranche 5, unchanged) must keep
|
|
4563
4928
|
// rendering exactly as it always has, not suddenly gain overlay chrome.
|
|
4564
4929
|
const [overlayOpen, setOverlayOpen] = React__namespace.useState(false);
|
|
4930
|
+
// Attio parity (attio-column-features-full.md gap #1) -- the right-click menu's own
|
|
4931
|
+
// point + open state. `contextMenuPoint` is frozen at the moment of the right-click
|
|
4932
|
+
// (never re-read live), same reasoning as `overlayOpen` above: the menu shouldn't
|
|
4933
|
+
// chase the cursor after it opens. `<CellContextMenu>` itself is only rendered below
|
|
4934
|
+
// while `contextMenuOpen` is true (not permanently mounted per cell) -- unlike
|
|
4935
|
+
// `ColumnMenu` (one per COLUMN, header row only), this component runs once per
|
|
4936
|
+
// row×column cell, and a floating-ui instance genuinely idle in every one of
|
|
4937
|
+
// thousands of cells would be real, avoidable overhead.
|
|
4938
|
+
const [contextMenuPoint, setContextMenuPoint] = React__namespace.useState(null);
|
|
4939
|
+
const [contextMenuOpen, setContextMenuOpen] = React__namespace.useState(false);
|
|
4565
4940
|
const alwaysLive = isAlwaysLiveEditable(column);
|
|
4566
4941
|
const chipListEditable = isChipListEditable(column);
|
|
4567
4942
|
// A gated `editable` column (everything except the always-live widgets AND the
|
|
@@ -4613,6 +4988,19 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4613
4988
|
setOverlayOpen(isCellTruncated(event.currentTarget));
|
|
4614
4989
|
startEdit(row.id, column.key);
|
|
4615
4990
|
}
|
|
4991
|
+
function handleContextMenu(event) {
|
|
4992
|
+
if (!cellContextMenu) return;
|
|
4993
|
+
// Replaces the browser's own native context menu (Attio's own gesture) -- and
|
|
4994
|
+
// must not also reach the row's own `onRowClick`, same reasoning as every other
|
|
4995
|
+
// cell-local click handler in this file.
|
|
4996
|
+
event.preventDefault();
|
|
4997
|
+
event.stopPropagation();
|
|
4998
|
+
setContextMenuPoint({
|
|
4999
|
+
x: event.clientX,
|
|
5000
|
+
y: event.clientY
|
|
5001
|
+
});
|
|
5002
|
+
setContextMenuOpen(true);
|
|
5003
|
+
}
|
|
4616
5004
|
function handleClick(event) {
|
|
4617
5005
|
if (chipListEditable) {
|
|
4618
5006
|
// Attio's own chip-list gesture: click opens the editor regardless of
|
|
@@ -4716,7 +5104,7 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4716
5104
|
const pending = isPending(row.id, column.key);
|
|
4717
5105
|
return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
4718
5106
|
children: [
|
|
4719
|
-
/*#__PURE__*/ jsxRuntime.
|
|
5107
|
+
/*#__PURE__*/ jsxRuntime.jsxs(DataTableCell, {
|
|
4720
5108
|
ref: cellRef,
|
|
4721
5109
|
"data-numeric": domUtils.dataAttr(column.type === "number" || column.type === "currency"),
|
|
4722
5110
|
"data-editable": domUtils.dataAttr(!!column.editable),
|
|
@@ -4727,14 +5115,34 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
|
|
|
4727
5115
|
style: sticky.style,
|
|
4728
5116
|
onClick: handleClick,
|
|
4729
5117
|
onDoubleClick: handleDoubleClick,
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
5118
|
+
onContextMenu: handleContextMenu,
|
|
5119
|
+
children: [
|
|
5120
|
+
/*#__PURE__*/ jsxRuntime.jsx(CellContent, {
|
|
5121
|
+
column: column,
|
|
5122
|
+
row: row,
|
|
5123
|
+
rowId: row.id,
|
|
5124
|
+
classNames: classNames,
|
|
5125
|
+
locale: locale,
|
|
5126
|
+
overlayActive: overlayActive
|
|
5127
|
+
}),
|
|
5128
|
+
cellContextMenu && contextMenuOpen && contextMenuPoint && // A `<td>` (unlike its own parent `<tr>`) can validly hold any flow
|
|
5129
|
+
// content, so `CellContextMenu`'s own 0x0 `MenuAnchor` -- itself never
|
|
5130
|
+
// portaled, only `MenuPositioner`'s actual dropdown content is (via
|
|
5131
|
+
// floating-ui's own `FloatingPortal`, straight to `document.body`) --
|
|
5132
|
+
// renders here, INSIDE this cell, rather than as a sibling of it.
|
|
5133
|
+
/*#__PURE__*/ jsxRuntime.jsx(CellContextMenu, {
|
|
5134
|
+
column: column,
|
|
5135
|
+
row: row,
|
|
5136
|
+
value: rawValue,
|
|
5137
|
+
locale: locale,
|
|
5138
|
+
point: contextMenuPoint,
|
|
5139
|
+
open: contextMenuOpen,
|
|
5140
|
+
onOpenChange: setContextMenuOpen,
|
|
5141
|
+
onCommit: (value)=>commitEdit(row.id, column.key, value),
|
|
5142
|
+
onViewEditHistory: onViewEditHistory,
|
|
5143
|
+
cellContextMenuItems: cellContextMenuItems
|
|
5144
|
+
})
|
|
5145
|
+
]
|
|
4738
5146
|
}),
|
|
4739
5147
|
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.
|
|
4740
5148
|
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
@@ -4964,64 +5372,52 @@ function DisplayCellContent({ column, row, value, classNames, locale }) {
|
|
|
4964
5372
|
}
|
|
4965
5373
|
}
|
|
4966
5374
|
|
|
4967
|
-
const
|
|
4968
|
-
const
|
|
4969
|
-
const
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
5375
|
+
const DataTableBulkBarRoot = withContext$1(Primitive.div, "bulkBar");
|
|
5376
|
+
const DataTableBulkBarCount = withContext$1(Primitive.span, "bulkBarCount");
|
|
5377
|
+
const DataTableBulkBarClear = withContext$1(Primitive.button, "bulkBarClear");
|
|
5378
|
+
/** Wraps whatever the CONSUMER passes as this bar's own action buttons -- the bar
|
|
5379
|
+
* itself only ever supplies chrome (count + clear); every actual action (Add to
|
|
5380
|
+
* list, Send email, …) is the consumer's own `<ActionButton>`/`<Menu>`, the same
|
|
5381
|
+
* "chrome vs. consumer content" split `toolbarActions`/`toolbarEnd` already draw for
|
|
5382
|
+
* the toolbar's own custom actions. */ const DataTableBulkBarActions = withContext$1(Primitive.div, "bulkBarActions");
|
|
5383
|
+
/**
|
|
5384
|
+
* The floating bulk-action pill (gap #4) -- renders nothing while no row is selected
|
|
5385
|
+
* (reads `selectedIds` off the table-wide context itself, so a consumer doesn't have
|
|
5386
|
+
* to gate this on `selectable`/`selectedIds` on their own). Composed as the LAST
|
|
5387
|
+
* child of the table's own root (`DataTable.tsx`), which is `position: relative` for
|
|
5388
|
+
* exactly this reason -- see `data-table.ts`'s own `bulkBar` slot comment for why its
|
|
5389
|
+
* geometry borrows `contextual-floating-button`'s already-measured vars rather than a
|
|
5390
|
+
* guessed literal.
|
|
5391
|
+
*/ function DataTableBulkBar({ clearLabel = "Clear selection", children }) {
|
|
5392
|
+
const { selectedIds, clearSelection } = useDataTableContext();
|
|
5393
|
+
if (selectedIds.length === 0) return null;
|
|
5394
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(DataTableBulkBarRoot, {
|
|
5395
|
+
role: "toolbar",
|
|
5396
|
+
"aria-label": "Bulk actions",
|
|
5397
|
+
"aria-orientation": "horizontal",
|
|
5398
|
+
children: [
|
|
5399
|
+
/*#__PURE__*/ jsxRuntime.jsxs(DataTableBulkBarCount, {
|
|
5400
|
+
"aria-live": "polite",
|
|
5401
|
+
children: [
|
|
5402
|
+
selectedIds.length,
|
|
5403
|
+
" selected"
|
|
5404
|
+
]
|
|
5405
|
+
}),
|
|
5406
|
+
/*#__PURE__*/ jsxRuntime.jsx(DataTableBulkBarClear, {
|
|
5407
|
+
type: "button",
|
|
5408
|
+
"aria-label": clearLabel,
|
|
5409
|
+
onClick: clearSelection,
|
|
5410
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(IconXmarkLine_default, {
|
|
5411
|
+
size: 12,
|
|
5412
|
+
"aria-hidden": "true"
|
|
5413
|
+
})
|
|
5414
|
+
}),
|
|
5415
|
+
children && /*#__PURE__*/ jsxRuntime.jsx(DataTableBulkBarActions, {
|
|
5416
|
+
children: children(selectedIds)
|
|
4986
5417
|
})
|
|
4987
|
-
|
|
4988
|
-
});
|
|
4989
|
-
};
|
|
4990
|
-
reactMenu.Menu.Anchor;
|
|
4991
|
-
const MenuTrigger = reactMenu.Menu.Trigger;
|
|
4992
|
-
const MenuPositioner = /*#__PURE__*/ React__namespace.forwardRef(({ className, ...props }, ref)=>{
|
|
4993
|
-
const classNames = useClassNames();
|
|
4994
|
-
return /*#__PURE__*/ jsxRuntime.jsx(reactMenu.Menu.Positioner, {
|
|
4995
|
-
ref: ref,
|
|
4996
|
-
className: clsx(classNames.positioner, className),
|
|
4997
|
-
...props
|
|
4998
|
-
});
|
|
4999
|
-
});
|
|
5000
|
-
MenuPositioner.displayName = "MenuPositioner";
|
|
5001
|
-
const MenuContent = withContext$1(reactMenu.Menu.Content, "content");
|
|
5002
|
-
const MenuScrollArea = withContext$1(withStateProps(Primitive.div), "scrollArea");
|
|
5003
|
-
withContext$1(reactMenu.Menu.Group, "group");
|
|
5004
|
-
withContext$1(reactMenu.Menu.GroupLabel, "groupLabel");
|
|
5005
|
-
const MenuItem = /*#__PURE__*/ React__namespace.forwardRef(({ className: propClassName, ...props }, ref)=>{
|
|
5006
|
-
const [variantProps, otherProps] = menuItem.menuItem.splitVariantProps(props);
|
|
5007
|
-
const parentProps = useItemProps();
|
|
5008
|
-
const classNames = menuItem.menuItem({
|
|
5009
|
-
...parentProps,
|
|
5010
|
-
...variantProps
|
|
5011
|
-
});
|
|
5012
|
-
return /*#__PURE__*/ jsxRuntime.jsx(ItemClassNamesProvider, {
|
|
5013
|
-
value: classNames,
|
|
5014
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(reactMenu.Menu.Item, {
|
|
5015
|
-
ref: ref,
|
|
5016
|
-
className: clsx(classNames.root, propClassName),
|
|
5017
|
-
...otherProps
|
|
5018
|
-
})
|
|
5418
|
+
]
|
|
5019
5419
|
});
|
|
5020
|
-
}
|
|
5021
|
-
MenuItem.displayName = "MenuItem";
|
|
5022
|
-
withItemContext(withItemStateProps(Primitive.div), "body");
|
|
5023
|
-
const MenuItemLabel = withItemContext(withItemStateProps(Primitive.span), "label");
|
|
5024
|
-
withItemContext(withItemStateProps(Primitive.span), "description");
|
|
5420
|
+
}
|
|
5025
5421
|
|
|
5026
5422
|
function ColumnCalcCells({ columns, rows, selectable, stickyFirst, stickyLast }) {
|
|
5027
5423
|
const effective = useEffectiveColumns(columns, {
|
|
@@ -5048,10 +5444,11 @@ function ColumnCalcCells({ columns, rows, selectable, stickyFirst, stickyLast })
|
|
|
5048
5444
|
})
|
|
5049
5445
|
});
|
|
5050
5446
|
}
|
|
5051
|
-
function formatCalcValue(value) {
|
|
5052
|
-
|
|
5447
|
+
function formatCalcValue(value, op) {
|
|
5448
|
+
const formatted = value.toLocaleString(undefined, {
|
|
5053
5449
|
maximumFractionDigits: 2
|
|
5054
5450
|
});
|
|
5451
|
+
return op === "percentEmpty" || op === "percentFilled" ? `${formatted}%` : formatted;
|
|
5055
5452
|
}
|
|
5056
5453
|
/**
|
|
5057
5454
|
* One ColumnCalc footer cell -- a click-anywhere-in-the-cell trigger (crisp's own
|
|
@@ -5086,7 +5483,7 @@ function formatCalcValue(value) {
|
|
|
5086
5483
|
children: [
|
|
5087
5484
|
/*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
5088
5485
|
className: "seed-data-table-column-calc-value",
|
|
5089
|
-
children: formatCalcValue(result)
|
|
5486
|
+
children: formatCalcValue(result, op)
|
|
5090
5487
|
}),
|
|
5091
5488
|
/*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
5092
5489
|
className: "seed-data-table-column-calc-op",
|
|
@@ -5107,21 +5504,13 @@ function formatCalcValue(value) {
|
|
|
5107
5504
|
style: {
|
|
5108
5505
|
minWidth: 160
|
|
5109
5506
|
},
|
|
5110
|
-
children: /*#__PURE__*/ jsxRuntime.
|
|
5111
|
-
children:
|
|
5112
|
-
|
|
5113
|
-
onClick: ()=>setColumnCalcOp(column.key, candidate),
|
|
5114
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
|
|
5115
|
-
children: DATA_TABLE_CALC_LABEL[candidate]
|
|
5116
|
-
})
|
|
5117
|
-
}, candidate)),
|
|
5118
|
-
op && /*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
|
|
5119
|
-
onClick: ()=>setColumnCalcOp(column.key, undefined),
|
|
5507
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(MenuScrollArea, {
|
|
5508
|
+
children: ops.map((candidate)=>/*#__PURE__*/ jsxRuntime.jsx(MenuItem, {
|
|
5509
|
+
onClick: ()=>setColumnCalcOp(column.key, candidate),
|
|
5120
5510
|
children: /*#__PURE__*/ jsxRuntime.jsx(MenuItemLabel, {
|
|
5121
|
-
children:
|
|
5511
|
+
children: DATA_TABLE_CALC_LABEL[candidate]
|
|
5122
5512
|
})
|
|
5123
|
-
})
|
|
5124
|
-
]
|
|
5513
|
+
}, candidate))
|
|
5125
5514
|
})
|
|
5126
5515
|
})
|
|
5127
5516
|
})
|
|
@@ -5400,9 +5789,9 @@ function ColumnRenameInput({ column, initialLabel, onDone }) {
|
|
|
5400
5789
|
const columnLabel = typeof label === "string" ? label : column.key;
|
|
5401
5790
|
const pinned = isColumnPinned(column.key);
|
|
5402
5791
|
// Attio/GRC's "Remove sort" (live-review fix D) -- the header's own click-to-sort
|
|
5403
|
-
// (`SortIndicator`/`toggleSort`, above)
|
|
5404
|
-
//
|
|
5405
|
-
// sense to show on the column that IS currently sorted.
|
|
5792
|
+
// (`SortIndicator`/`toggleSort`, above) already cycles asc -> desc -> none on its
|
|
5793
|
+
// own third click, but this stays as a one-click shortcut to the same place, so it
|
|
5794
|
+
// only makes sense to show on the column that IS currently sorted.
|
|
5406
5795
|
const isSorted = sort?.key === column.key;
|
|
5407
5796
|
const stopPropagation = (event)=>event.stopPropagation();
|
|
5408
5797
|
return(// Live-review fix (D): a `MenuItem` inside `MenuPositioner` renders through a
|
|
@@ -10386,6 +10775,18 @@ ContinuousDatePicker.displayName = "ContinuousDatePicker";
|
|
|
10386
10775
|
// value list) down to `is`/`is not`/`empty`/`not empty`. `"isanyof"` is appended to any
|
|
10387
10776
|
// of the four whenever the column supplies `filterValues` -- a faceted checkbox list,
|
|
10388
10777
|
// independent of the column's own kind.
|
|
10778
|
+
//
|
|
10779
|
+
// Multi-select fix (DATATABLE-ATTIO-SPEC.md gap #12, live-measured 2026-09-30): a
|
|
10780
|
+
// `kind: "select"` column whose CELL is multi-valued (`type: "tags"`/`"chip-list"` --
|
|
10781
|
+
// a chip-list/tag column, not a single status pill) offers Attio's own
|
|
10782
|
+
// `contains`/`does not contain` instead of `is`/`is not` -- "is" reads as an exact-
|
|
10783
|
+
// set-equality check against an array value, which is not what Attio's own multi-
|
|
10784
|
+
// select filter means or what `applyToolbarFilters`' `is`/`isnot` branch (a plain
|
|
10785
|
+
// string-equality compare via `asText`) computes. `contains`/`doesnotcontain` are
|
|
10786
|
+
// already correct here unmodified: `applyToolbarFilters` already runs them against
|
|
10787
|
+
// `asText(raw)` (an array's own values joined), which is exactly "does any tag
|
|
10788
|
+
// match". Single-select (no `filterValues`-array cell type) keeps `is`/`is not` --
|
|
10789
|
+
// not re-measured against Attio, so left alone per the discovery doc's own hedge.
|
|
10389
10790
|
////////////////////////////////////////////////////////////////////////////////////
|
|
10390
10791
|
const OP_ORDER = [
|
|
10391
10792
|
"contains",
|
|
@@ -10419,9 +10820,19 @@ const SELECT_OP_ORDER = [
|
|
|
10419
10820
|
"empty",
|
|
10420
10821
|
"notempty"
|
|
10421
10822
|
];
|
|
10823
|
+
const MULTI_SELECT_OP_ORDER = [
|
|
10824
|
+
"contains",
|
|
10825
|
+
"doesnotcontain",
|
|
10826
|
+
"empty",
|
|
10827
|
+
"notempty"
|
|
10828
|
+
];
|
|
10422
10829
|
/** The operators a column of this `kind` offers, in display order -- `hasValues`
|
|
10423
|
-
* (the column supplies `filterValues`) appends `"isanyof"` regardless of kind.
|
|
10424
|
-
|
|
10830
|
+
* (the column supplies `filterValues`) appends `"isanyof"` regardless of kind.
|
|
10831
|
+
* `multiValue` (the column's CELL type is a chip-list/tags column, not just its
|
|
10832
|
+
* filter `kind`) swaps `SELECT_OP_ORDER`'s `is`/`is not` for `contains`/`does not
|
|
10833
|
+
* contain`, matching Attio's own multi-select filter -- see the operator-sets
|
|
10834
|
+
* comment above. */ function opsForKind(kind, hasValues, multiValue = false) {
|
|
10835
|
+
const base = kind === "number" ? NUMBER_OP_ORDER : kind === "date" ? DATE_OP_ORDER : kind === "select" ? multiValue ? MULTI_SELECT_OP_ORDER : SELECT_OP_ORDER : OP_ORDER;
|
|
10425
10836
|
return hasValues ? [
|
|
10426
10837
|
...base,
|
|
10427
10838
|
"isanyof"
|
|
@@ -10789,66 +11200,58 @@ const formatFilterDate = (iso)=>{
|
|
|
10789
11200
|
return `${OPERATOR_LABELS[filter.op]} ${value}`;
|
|
10790
11201
|
}
|
|
10791
11202
|
/**
|
|
10792
|
-
* One filter condition, INSIDE the Filter popover --
|
|
10793
|
-
* (
|
|
10794
|
-
*
|
|
10795
|
-
*
|
|
10796
|
-
*
|
|
10797
|
-
*
|
|
10798
|
-
*
|
|
10799
|
-
*
|
|
10800
|
-
*
|
|
10801
|
-
|
|
11203
|
+
* One filter condition, INSIDE the Filter popover -- Attio's own compact chip shape
|
|
11204
|
+
* (DATATABLE-ATTIO-SPEC.md gap #12, re-measured live 2026-09-30): `[attribute ▾]
|
|
11205
|
+
* [operator …] [value] [remove ×]`, ALL of it visible at once, never behind a click-
|
|
11206
|
+
* to-expand accordion. Supersedes this file's earlier 2026-09-28 note (which read
|
|
11207
|
+
* Attio as keeping conditions collapsed behind a bare "Filter · N" count and put them
|
|
11208
|
+
* in an accordion for that reason) -- the fresh read found the opposite: every active
|
|
11209
|
+
* condition shows attribute/operator/value simultaneously. This keeps the outer shell
|
|
11210
|
+
* (the "Filter"/"Filter · N" trigger opening ONE popover, `SortControl`'s own
|
|
11211
|
+
* list-of-rows shape) rather than moving chips into the toolbar row itself, so the
|
|
11212
|
+
* already-covered trigger/`Add filter` DOM (`DataTable.test.tsx`) stays put; only the
|
|
11213
|
+
* PER-CONDITION row tightens, from an accordion to an always-open card. The operator
|
|
11214
|
+
* set stays a row of small pill buttons (not a dropdown) so every existing test that
|
|
11215
|
+
* clicks an operator by its exact button name keeps working unchanged.
|
|
11216
|
+
*/ function FilterConditionRow({ filter, columns }) {
|
|
10802
11217
|
const { patchToolbarFilter, changeToolbarFilterField, removeToolbarFilter } = useDataTableContext();
|
|
10803
11218
|
const column = columns.find((c)=>c.key === filter.key);
|
|
10804
11219
|
const kind = column?.kind;
|
|
11220
|
+
const multiValue = column?.type === "tags" || column?.type === "chip-list";
|
|
10805
11221
|
const values = column?.filterValues ?? [];
|
|
10806
|
-
const ops = opsForKind(kind, values.length > 0);
|
|
10807
|
-
return /*#__PURE__*/ jsxRuntime.jsxs("
|
|
11222
|
+
const ops = opsForKind(kind, values.length > 0, multiValue);
|
|
11223
|
+
return /*#__PURE__*/ jsxRuntime.jsxs("fieldset", {
|
|
11224
|
+
"aria-label": `${column ? columnLabel(column) : filter.key} filter: ${conditionSummary(filter, column)}`,
|
|
10808
11225
|
style: {
|
|
11226
|
+
margin: 0,
|
|
10809
11227
|
display: "flex",
|
|
10810
11228
|
flexDirection: "column",
|
|
10811
|
-
gap:
|
|
11229
|
+
gap: 8,
|
|
10812
11230
|
borderRadius: 6,
|
|
10813
|
-
|
|
10814
|
-
|
|
11231
|
+
border: "1px solid var(--seed-color-border-neutral)",
|
|
11232
|
+
background: "var(--seed-color-bg-neutral-weak)",
|
|
11233
|
+
padding: 6
|
|
10815
11234
|
},
|
|
10816
11235
|
children: [
|
|
10817
11236
|
/*#__PURE__*/ jsxRuntime.jsxs("div", {
|
|
10818
11237
|
style: {
|
|
10819
11238
|
display: "flex",
|
|
10820
11239
|
alignItems: "center",
|
|
10821
|
-
gap:
|
|
11240
|
+
gap: 4
|
|
10822
11241
|
},
|
|
10823
11242
|
children: [
|
|
10824
|
-
/*#__PURE__*/ jsxRuntime.
|
|
10825
|
-
|
|
10826
|
-
|
|
11243
|
+
/*#__PURE__*/ jsxRuntime.jsx(InlineSelect, {
|
|
11244
|
+
ariaLabel: "Filter by field",
|
|
11245
|
+
value: filter.key,
|
|
11246
|
+
onChange: (key)=>changeToolbarFilterField(filter.id, key),
|
|
11247
|
+
options: columns.map((c)=>({
|
|
11248
|
+
value: c.key,
|
|
11249
|
+
label: columnLabel(c)
|
|
11250
|
+
})),
|
|
10827
11251
|
style: {
|
|
10828
11252
|
flex: 1,
|
|
10829
|
-
minWidth: 0
|
|
10830
|
-
|
|
10831
|
-
padding: "6px 8px",
|
|
10832
|
-
border: "none",
|
|
10833
|
-
borderRadius: 6,
|
|
10834
|
-
background: "transparent",
|
|
10835
|
-
cursor: "pointer",
|
|
10836
|
-
fontSize: 13,
|
|
10837
|
-
overflow: "hidden",
|
|
10838
|
-
textOverflow: "ellipsis",
|
|
10839
|
-
whiteSpace: "nowrap"
|
|
10840
|
-
},
|
|
10841
|
-
children: [
|
|
10842
|
-
/*#__PURE__*/ jsxRuntime.jsx("strong", {
|
|
10843
|
-
style: {
|
|
10844
|
-
fontWeight: 500
|
|
10845
|
-
},
|
|
10846
|
-
children: column ? columnLabel(column) : filter.key
|
|
10847
|
-
}),
|
|
10848
|
-
":",
|
|
10849
|
-
" ",
|
|
10850
|
-
conditionSummary(filter, column)
|
|
10851
|
-
]
|
|
11253
|
+
minWidth: 0
|
|
11254
|
+
}
|
|
10852
11255
|
}),
|
|
10853
11256
|
/*#__PURE__*/ jsxRuntime.jsx("button", {
|
|
10854
11257
|
type: "button",
|
|
@@ -10862,136 +11265,103 @@ const formatFilterDate = (iso)=>{
|
|
|
10862
11265
|
})
|
|
10863
11266
|
]
|
|
10864
11267
|
}),
|
|
10865
|
-
|
|
11268
|
+
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
10866
11269
|
style: {
|
|
10867
|
-
padding: "0 8px 4px",
|
|
10868
11270
|
display: "flex",
|
|
10869
|
-
|
|
10870
|
-
gap:
|
|
11271
|
+
flexWrap: "wrap",
|
|
11272
|
+
gap: 2
|
|
10871
11273
|
},
|
|
10872
|
-
children:
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
|
|
10877
|
-
|
|
10878
|
-
children: "Field"
|
|
10879
|
-
}),
|
|
10880
|
-
/*#__PURE__*/ jsxRuntime.jsx(InlineSelect, {
|
|
10881
|
-
ariaLabel: "Filter by field",
|
|
10882
|
-
value: filter.key,
|
|
10883
|
-
onChange: (key)=>changeToolbarFilterField(filter.id, key),
|
|
10884
|
-
options: columns.map((c)=>({
|
|
10885
|
-
value: c.key,
|
|
10886
|
-
label: columnLabel(c)
|
|
10887
|
-
}))
|
|
10888
|
-
}),
|
|
10889
|
-
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
10890
|
-
style: {
|
|
10891
|
-
fontSize: 12,
|
|
10892
|
-
color: "var(--seed-color-fg-neutral-subtle)"
|
|
10893
|
-
},
|
|
10894
|
-
children: "Condition"
|
|
10895
|
-
}),
|
|
10896
|
-
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
11274
|
+
children: ops.map((op)=>/*#__PURE__*/ jsxRuntime.jsx("button", {
|
|
11275
|
+
type: "button",
|
|
11276
|
+
"data-active": filter.op === op ? "" : undefined,
|
|
11277
|
+
onClick: ()=>patchToolbarFilter(filter.id, {
|
|
11278
|
+
op
|
|
11279
|
+
}),
|
|
10897
11280
|
style: {
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
11281
|
+
textAlign: "left",
|
|
11282
|
+
padding: "4px 8px",
|
|
11283
|
+
borderRadius: 999,
|
|
11284
|
+
border: "none",
|
|
11285
|
+
cursor: "pointer",
|
|
11286
|
+
background: filter.op === op ? "var(--seed-color-bg-layer-default)" : "transparent",
|
|
11287
|
+
fontSize: 12
|
|
10901
11288
|
},
|
|
10902
|
-
children:
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
11289
|
+
children: OPERATOR_LABELS[op]
|
|
11290
|
+
}, op))
|
|
11291
|
+
}),
|
|
11292
|
+
opNeedsValues(filter.op) && /*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
11293
|
+
style: {
|
|
11294
|
+
display: "flex",
|
|
11295
|
+
flexDirection: "column",
|
|
11296
|
+
gap: 4,
|
|
11297
|
+
maxHeight: 160,
|
|
11298
|
+
overflow: "auto"
|
|
11299
|
+
},
|
|
11300
|
+
children: values.map((value)=>{
|
|
11301
|
+
const checked = (filter.values ?? []).includes(value);
|
|
11302
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(CheckboxRoot, {
|
|
11303
|
+
checked: checked,
|
|
11304
|
+
onCheckedChange: ()=>patchToolbarFilter(filter.id, {
|
|
11305
|
+
values: checked ? (filter.values ?? []).filter((v)=>v !== value) : [
|
|
11306
|
+
...filter.values ?? [],
|
|
11307
|
+
value
|
|
11308
|
+
]
|
|
11309
|
+
}),
|
|
10921
11310
|
style: {
|
|
10922
11311
|
display: "flex",
|
|
10923
|
-
|
|
10924
|
-
gap:
|
|
10925
|
-
|
|
10926
|
-
|
|
11312
|
+
alignItems: "center",
|
|
11313
|
+
gap: 8,
|
|
11314
|
+
padding: "4px 0",
|
|
11315
|
+
cursor: "pointer"
|
|
10927
11316
|
},
|
|
10928
|
-
children:
|
|
10929
|
-
|
|
10930
|
-
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
values: checked ? (filter.values ?? []).filter((v)=>v !== value) : [
|
|
10934
|
-
...filter.values ?? [],
|
|
10935
|
-
value
|
|
10936
|
-
]
|
|
10937
|
-
}),
|
|
10938
|
-
style: {
|
|
10939
|
-
display: "flex",
|
|
10940
|
-
alignItems: "center",
|
|
10941
|
-
gap: 8,
|
|
10942
|
-
padding: "4px 0",
|
|
10943
|
-
cursor: "pointer"
|
|
10944
|
-
},
|
|
10945
|
-
children: [
|
|
10946
|
-
/*#__PURE__*/ jsxRuntime.jsx(CheckboxControl, {
|
|
10947
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(CheckboxIndicator, {
|
|
10948
|
-
checked: /*#__PURE__*/ jsxRuntime.jsx(IconCheckmarkLine_default, {
|
|
10949
|
-
size: 12
|
|
10950
|
-
})
|
|
10951
|
-
})
|
|
10952
|
-
}),
|
|
10953
|
-
/*#__PURE__*/ jsxRuntime.jsx(CheckboxLabel, {
|
|
10954
|
-
children: value
|
|
10955
|
-
}),
|
|
10956
|
-
/*#__PURE__*/ jsxRuntime.jsx(CheckboxHiddenInput, {
|
|
10957
|
-
"aria-label": value
|
|
11317
|
+
children: [
|
|
11318
|
+
/*#__PURE__*/ jsxRuntime.jsx(CheckboxControl, {
|
|
11319
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(CheckboxIndicator, {
|
|
11320
|
+
checked: /*#__PURE__*/ jsxRuntime.jsx(IconCheckmarkLine_default, {
|
|
11321
|
+
size: 12
|
|
10958
11322
|
})
|
|
10959
|
-
|
|
10960
|
-
}, value);
|
|
10961
|
-
})
|
|
10962
|
-
}),
|
|
10963
|
-
opNeedsValue(filter.op) && kind === "date" && /*#__PURE__*/ jsxRuntime.jsx(DatePicker, {
|
|
10964
|
-
value: filter.value ? toDatePickerDate(isoToDate(filter.value) ?? new Date()) : undefined,
|
|
10965
|
-
onValueChange: (d)=>d && patchToolbarFilter(filter.id, {
|
|
10966
|
-
value: dateToISO(fromDatePickerDate(d))
|
|
10967
|
-
})
|
|
10968
|
-
}),
|
|
10969
|
-
opNeedsValue(filter.op) && kind === "select" && /*#__PURE__*/ jsxRuntime.jsx(InlineSelect, {
|
|
10970
|
-
ariaLabel: "Filter value",
|
|
10971
|
-
placeholder: "Value…",
|
|
10972
|
-
value: filter.value || undefined,
|
|
10973
|
-
onChange: (value)=>patchToolbarFilter(filter.id, {
|
|
10974
|
-
value
|
|
11323
|
+
})
|
|
10975
11324
|
}),
|
|
10976
|
-
|
|
10977
|
-
value
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
|
|
10982
|
-
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
placeholder: "Value…",
|
|
10991
|
-
"aria-label": "Filter value"
|
|
10992
|
-
})
|
|
11325
|
+
/*#__PURE__*/ jsxRuntime.jsx(CheckboxLabel, {
|
|
11326
|
+
children: value
|
|
11327
|
+
}),
|
|
11328
|
+
/*#__PURE__*/ jsxRuntime.jsx(CheckboxHiddenInput, {
|
|
11329
|
+
"aria-label": value
|
|
11330
|
+
})
|
|
11331
|
+
]
|
|
11332
|
+
}, value);
|
|
11333
|
+
})
|
|
11334
|
+
}),
|
|
11335
|
+
opNeedsValue(filter.op) && kind === "date" && /*#__PURE__*/ jsxRuntime.jsx(DatePicker, {
|
|
11336
|
+
value: filter.value ? toDatePickerDate(isoToDate(filter.value) ?? new Date()) : undefined,
|
|
11337
|
+
onValueChange: (d)=>d && patchToolbarFilter(filter.id, {
|
|
11338
|
+
value: dateToISO(fromDatePickerDate(d))
|
|
10993
11339
|
})
|
|
10994
|
-
|
|
11340
|
+
}),
|
|
11341
|
+
opNeedsValue(filter.op) && kind === "select" && /*#__PURE__*/ jsxRuntime.jsx(InlineSelect, {
|
|
11342
|
+
ariaLabel: "Filter value",
|
|
11343
|
+
placeholder: "Value…",
|
|
11344
|
+
value: filter.value || undefined,
|
|
11345
|
+
onChange: (value)=>patchToolbarFilter(filter.id, {
|
|
11346
|
+
value
|
|
11347
|
+
}),
|
|
11348
|
+
options: values.map((value)=>({
|
|
11349
|
+
value,
|
|
11350
|
+
label: value
|
|
11351
|
+
}))
|
|
11352
|
+
}),
|
|
11353
|
+
opNeedsValue(filter.op) && kind !== "date" && kind !== "select" && /*#__PURE__*/ jsxRuntime.jsx(TextFieldRoot, {
|
|
11354
|
+
variant: "outline",
|
|
11355
|
+
size: "medium",
|
|
11356
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(TextFieldInput, {
|
|
11357
|
+
type: kind === "number" ? "number" : "text",
|
|
11358
|
+
value: filter.value,
|
|
11359
|
+
onChange: (e)=>patchToolbarFilter(filter.id, {
|
|
11360
|
+
value: e.target.value
|
|
11361
|
+
}),
|
|
11362
|
+
placeholder: "Value…",
|
|
11363
|
+
"aria-label": "Filter value"
|
|
11364
|
+
})
|
|
10995
11365
|
})
|
|
10996
11366
|
]
|
|
10997
11367
|
});
|
|
@@ -10999,15 +11369,14 @@ const formatFilterDate = (iso)=>{
|
|
|
10999
11369
|
/**
|
|
11000
11370
|
* The toolbar's Filter trigger + popover -- a compact `"Filter"` / `"Filter · N"`
|
|
11001
11371
|
* button (matching `SortControl`'s own `"Sort"` / `"Sort · N"`), opening ONE popover
|
|
11002
|
-
* that holds both the active conditions (compact
|
|
11003
|
-
*
|
|
11004
|
-
* new one
|
|
11005
|
-
*
|
|
11372
|
+
* that holds both the active conditions (compact chips, `FilterConditionRow` above,
|
|
11373
|
+
* ALL open at once -- no accordion) and, behind "+ Add filter", the field picker that
|
|
11374
|
+
* appends a new one. See `FilterConditionRow`'s own doc comment for why the chips
|
|
11375
|
+
* live inside this one popover rather than spread across the toolbar row itself.
|
|
11006
11376
|
*/ function FilterControl({ columns, label = "Filter" }) {
|
|
11007
11377
|
const { toolbarFilters, addToolbarFilter } = useDataTableContext();
|
|
11008
11378
|
const [open, setOpen] = React__namespace.useState(false);
|
|
11009
11379
|
const [pickingField, setPickingField] = React__namespace.useState(false);
|
|
11010
|
-
const [expandedId, setExpandedId] = React__namespace.useState(null);
|
|
11011
11380
|
return /*#__PURE__*/ jsxRuntime.jsxs(MenuRoot, {
|
|
11012
11381
|
open: open,
|
|
11013
11382
|
onOpenChange: (next)=>{
|
|
@@ -11069,8 +11438,7 @@ const formatFilterDate = (iso)=>{
|
|
|
11069
11438
|
columns.map((c)=>/*#__PURE__*/ jsxRuntime.jsx("button", {
|
|
11070
11439
|
type: "button",
|
|
11071
11440
|
onClick: ()=>{
|
|
11072
|
-
|
|
11073
|
-
setExpandedId(id);
|
|
11441
|
+
addToolbarFilter(c.key);
|
|
11074
11442
|
setPickingField(false);
|
|
11075
11443
|
},
|
|
11076
11444
|
style: {
|
|
@@ -11103,9 +11471,7 @@ const formatFilterDate = (iso)=>{
|
|
|
11103
11471
|
}),
|
|
11104
11472
|
toolbarFilters.map((f)=>/*#__PURE__*/ jsxRuntime.jsx(FilterConditionRow, {
|
|
11105
11473
|
filter: f,
|
|
11106
|
-
columns: columns
|
|
11107
|
-
expanded: expandedId === f.id,
|
|
11108
|
-
onToggle: ()=>setExpandedId((id)=>id === f.id ? null : f.id)
|
|
11474
|
+
columns: columns
|
|
11109
11475
|
}, f.id)),
|
|
11110
11476
|
/*#__PURE__*/ jsxRuntime.jsxs("button", {
|
|
11111
11477
|
type: "button",
|
|
@@ -11134,8 +11500,8 @@ const formatFilterDate = (iso)=>{
|
|
|
11134
11500
|
});
|
|
11135
11501
|
}
|
|
11136
11502
|
|
|
11137
|
-
const DataTableToolbar = withContext$
|
|
11138
|
-
const DataTableCount = withContext$
|
|
11503
|
+
const DataTableToolbar = withContext$1(Primitive.div, "toolbar");
|
|
11504
|
+
const DataTableCount = withContext$1(Primitive.span, "count");
|
|
11139
11505
|
/**
|
|
11140
11506
|
* The toolbar's own right-hand group -- `count`'s `marginInlineStart: auto` moved
|
|
11141
11507
|
* here (off the `<span>` itself) so a consumer's `toolbarActions` and the row count
|
|
@@ -11146,7 +11512,7 @@ const DataTableCount = withContext$2(Primitive.span, "count");
|
|
|
11146
11512
|
* it. `DataTable.tsx` always renders this wrapper once either `toolbarActions` or
|
|
11147
11513
|
* `showCount` is on, so it degrades to exactly the old single-count layout when no
|
|
11148
11514
|
* `toolbarActions` is passed.
|
|
11149
|
-
*/ const DataTableToolbarEnd = withContext$
|
|
11515
|
+
*/ const DataTableToolbarEnd = withContext$1(Primitive.div, "toolbarEnd");
|
|
11150
11516
|
/**
|
|
11151
11517
|
* A compact, borderless search box -- crisp's own measured `.crisp-datatable-search`
|
|
11152
11518
|
* (32px, `bgSurface` background, a leading icon, a soft rest-state shadow, a 1px brand
|
|
@@ -11196,7 +11562,7 @@ function RowCount({ shown, total, countLabel }) {
|
|
|
11196
11562
|
}
|
|
11197
11563
|
|
|
11198
11564
|
function DataTableInner(props, ref) {
|
|
11199
|
-
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;
|
|
11565
|
+
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;
|
|
11200
11566
|
const classNames = dataTable({
|
|
11201
11567
|
surface,
|
|
11202
11568
|
interactive
|
|
@@ -11320,7 +11686,7 @@ function DataTableInner(props, ref) {
|
|
|
11320
11686
|
// loading/error/empty body, infinite scroll's sentinel, the add-row footer) reads
|
|
11321
11687
|
// this ONE value rather than each re-deriving it, so they can never drift apart.
|
|
11322
11688
|
const totalCols = columns.length + (selectable ? 1 : 0);
|
|
11323
|
-
return /*#__PURE__*/ jsxRuntime.jsx(ClassNamesProvider
|
|
11689
|
+
return /*#__PURE__*/ jsxRuntime.jsx(ClassNamesProvider, {
|
|
11324
11690
|
value: classNames,
|
|
11325
11691
|
children: /*#__PURE__*/ jsxRuntime.jsxs(DataTableRoot, {
|
|
11326
11692
|
ref: ref,
|
|
@@ -11476,7 +11842,10 @@ function DataTableInner(props, ref) {
|
|
|
11476
11842
|
locale: locale,
|
|
11477
11843
|
selectable: !!selectable,
|
|
11478
11844
|
stickyFirst: stickyFirst,
|
|
11479
|
-
stickyLast: resolvedStickyLast
|
|
11845
|
+
stickyLast: resolvedStickyLast,
|
|
11846
|
+
cellContextMenu: cellContextMenu,
|
|
11847
|
+
onViewEditHistory: onViewEditHistory,
|
|
11848
|
+
cellContextMenuItems: cellContextMenuItems
|
|
11480
11849
|
})
|
|
11481
11850
|
]
|
|
11482
11851
|
}, row.id)),
|
|
@@ -11515,6 +11884,10 @@ function DataTableInner(props, ref) {
|
|
|
11515
11884
|
})
|
|
11516
11885
|
]
|
|
11517
11886
|
})
|
|
11887
|
+
}),
|
|
11888
|
+
selectable && /*#__PURE__*/ jsxRuntime.jsx(DataTableBulkBar, {
|
|
11889
|
+
clearLabel: clearSelectionLabel,
|
|
11890
|
+
children: bulkActions
|
|
11518
11891
|
})
|
|
11519
11892
|
]
|
|
11520
11893
|
})
|
|
@@ -11568,7 +11941,7 @@ DataTableInner.displayName = "DataTable";
|
|
|
11568
11941
|
// is a SIBLING of the toolbar (both inside `DataTablePrimitiveRoot`'s card `<div>`)
|
|
11569
11942
|
// rather than `DataTablePrimitiveRoot` itself: a `<table>` cannot host the toolbar as a
|
|
11570
11943
|
// child without the HTML parser foster-parenting it back out.
|
|
11571
|
-
const DataTableTable = withContext$
|
|
11944
|
+
const DataTableTable = withContext$1(DataTableTable$1, "table");
|
|
11572
11945
|
/** One `<col>` per rendered column (plus the 40px selection column, if any) -- the
|
|
11573
11946
|
* SINGLE place a column's width is ever set now. Every row's header/body/footer cell
|
|
11574
11947
|
* reads its own width off this shared `<colgroup>` by construction (native table
|
|
@@ -11605,15 +11978,15 @@ const DataTableTable = withContext$2(DataTableTable$1, "table");
|
|
|
11605
11978
|
]
|
|
11606
11979
|
});
|
|
11607
11980
|
}
|
|
11608
|
-
const DataTableHeader = withContext$
|
|
11609
|
-
const DataTableHeaderCell = withContext$
|
|
11981
|
+
const DataTableHeader = withContext$1(DataTableHeader$1, "header");
|
|
11982
|
+
const DataTableHeaderCell = withContext$1(DataTableHeaderCell$1, "headerCell");
|
|
11610
11983
|
// `.crisp-datatable-th-inner` -- the flex row INSIDE a `<th>` (label + filter trigger +
|
|
11611
11984
|
// sort chevron + column menu). See qvism-preset's own `headerCellInner` slot comment
|
|
11612
11985
|
// for why this lives one level below the cell itself rather than on it.
|
|
11613
|
-
const DataTableHeaderCellInner = withContext$
|
|
11986
|
+
const DataTableHeaderCellInner = withContext$1(Primitive.div, "headerCellInner");
|
|
11614
11987
|
/** The label text specifically -- the one thing in `DataTableHeaderCellInner` that
|
|
11615
11988
|
* truncates; the trailing filter/sort/menu icons stay fully visible regardless of how
|
|
11616
|
-
* long a column's own header text is. */ const DataTableHeaderCellLabel = withContext$
|
|
11989
|
+
* long a column's own header text is. */ const DataTableHeaderCellLabel = withContext$1(Primitive.span, "headerCellLabel");
|
|
11617
11990
|
/**
|
|
11618
11991
|
* A selection `<th>`/`<td>`/footer `<td>` composes ITS base slot (`headerCell`/`cell`/
|
|
11619
11992
|
* `footerCell`) together with the `selectionCell` MODIFIER, rather than replacing it --
|
|
@@ -11624,7 +11997,7 @@ const DataTableHeaderCellInner = withContext$2(Primitive.div, "headerCellInner")
|
|
|
11624
11997
|
* a second recipe call.
|
|
11625
11998
|
*/ function withSelectionCell(Component, baseSlot) {
|
|
11626
11999
|
const StyledComponent = /*#__PURE__*/ React.forwardRef((props, ref)=>{
|
|
11627
|
-
const classNames = useClassNames
|
|
12000
|
+
const classNames = useClassNames();
|
|
11628
12001
|
return /*#__PURE__*/ jsxRuntime.jsx(Component, {
|
|
11629
12002
|
ref: ref,
|
|
11630
12003
|
...props,
|
|
@@ -11635,12 +12008,12 @@ const DataTableHeaderCellInner = withContext$2(Primitive.div, "headerCellInner")
|
|
|
11635
12008
|
return StyledComponent;
|
|
11636
12009
|
}
|
|
11637
12010
|
const DataTableSelectionHeaderCell = withSelectionCell(DataTableHeaderCell$1, "headerCell");
|
|
11638
|
-
const DataTableHeaderCellIcon = withContext$
|
|
12011
|
+
const DataTableHeaderCellIcon = withContext$1(Primitive.span, "headerCellIcon");
|
|
11639
12012
|
// body has no CSS slot of its own in the rootage spec -- it is a plain structural
|
|
11640
12013
|
// `<tbody>`, so it is not wrapped in `withContext`.
|
|
11641
12014
|
const DataTableBody = DataTableBody$1;
|
|
11642
|
-
const DataTableRow = withContext$
|
|
11643
|
-
const DataTableCell = withContext$
|
|
12015
|
+
const DataTableRow = withContext$1(DataTableRow$1, "row");
|
|
12016
|
+
const DataTableCell = withContext$1(DataTableCell$1, "cell");
|
|
11644
12017
|
const DataTableSelectionCell = withSelectionCell(DataTableCell$1, "cell");
|
|
11645
12018
|
// Tranche 4 -- column menu + reorder + resize + sticky columns. A scroll boundary
|
|
11646
12019
|
// wrapping the whole `<table>`: `overflowX: auto` is what makes a wide table (more
|
|
@@ -11650,7 +12023,7 @@ const DataTableSelectionCell = withSelectionCell(DataTableCell$1, "cell");
|
|
|
11650
12023
|
// stays out of this slot's own base css (nothing here has a bounded height of its own
|
|
11651
12024
|
// to clip), so it never introduces a second vertical scrollbar next to whatever
|
|
11652
12025
|
// ambient container the whole DataTable already sits in.
|
|
11653
|
-
const DataTableScrollBodyBase = withContext$
|
|
12026
|
+
const DataTableScrollBodyBase = withContext$1(Primitive.div, "scrollArea");
|
|
11654
12027
|
function DataTableScrollBody({ children, scrollProps }) {
|
|
11655
12028
|
const { scrollAreaRef, scrolledStart, scrolledEnd, onScroll } = useDataTableContext();
|
|
11656
12029
|
const { className: scrollClassName, style: scrollStyle, ...otherScrollProps } = scrollProps ?? {};
|
|
@@ -11665,7 +12038,7 @@ function DataTableScrollBody({ children, scrollProps }) {
|
|
|
11665
12038
|
children: children
|
|
11666
12039
|
});
|
|
11667
12040
|
}
|
|
11668
|
-
const DataTableFooterBase = withContext$
|
|
12041
|
+
const DataTableFooterBase = withContext$1(Primitive.tfoot, "footer");
|
|
11669
12042
|
function DataTableFooter({ children, ...props }) {
|
|
11670
12043
|
return /*#__PURE__*/ jsxRuntime.jsx(DataTableFooterBase, {
|
|
11671
12044
|
...props,
|
|
@@ -11674,7 +12047,7 @@ function DataTableFooter({ children, ...props }) {
|
|
|
11674
12047
|
})
|
|
11675
12048
|
});
|
|
11676
12049
|
}
|
|
11677
|
-
const DataTableFooterCell = withContext$
|
|
12050
|
+
const DataTableFooterCell = withContext$1(Primitive.td, "footerCell");
|
|
11678
12051
|
// The selection column's OWN sticky wrappers -- one each for header/body/footer,
|
|
11679
12052
|
// reading the live pinned set via `useSelectionStickyFirst` (column-layout.ts) instead
|
|
11680
12053
|
// of the `stickyFirst` PROP alone, so the checkbox column sticks the moment ANY column
|
|
@@ -15612,6 +15985,7 @@ function RecordPreviewPanel({ open: _open, record, onClose, className, animation
|
|
|
15612
15985
|
RecordPreviewPanel.displayName = "RecordPreviewPanel";
|
|
15613
15986
|
|
|
15614
15987
|
exports.DataTable = DataTable;
|
|
15988
|
+
exports.DataTableBulkBar = DataTableBulkBar;
|
|
15615
15989
|
exports.DataTableViewsControl = DataTableViewsControl;
|
|
15616
15990
|
exports.RecordPreview = RecordPreview;
|
|
15617
15991
|
exports.ResizablePanel = ResizablePanel;
|