@crispy-seed/data-table 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2744,6 +2744,292 @@ const TextFieldTextarea = /*#__PURE__*/ forwardRef(({ className, autoresize = tr
2744
2744
  });
2745
2745
  TextFieldTextarea.displayName = "TextFieldTextarea";
2746
2746
 
2747
+ __insertCSS(".seed-data-table__root{box-sizing:border-box;display:flex;flex-direction:column;width:100%;border-width:1px;border-style:solid;font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.seed-data-table__table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.seed-data-table__headerCell{box-sizing:border-box;position:sticky;top:0;z-index:2;vertical-align:middle;text-align:start;padding:0;height:var(--seed-dimension-x10);background-color:var(--seed-color-bg-layer-default);border-top:1px solid var(--seed-color-stroke-neutral-muted);border-bottom:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-inline-start:none;color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-medium);letter-spacing:-.14px}.seed-data-table__headerCell:last-child{border-inline-end:none}.seed-data-table__headerCell[data-sortable]{cursor:pointer;user-select:none}.seed-data-table__headerCell [data-chevron]{opacity:0;transition:opacity .12s}.seed-data-table__headerCell[data-sortable]:hover [data-chevron]{opacity:.6}.seed-data-table__headerCell[data-sorted] [data-chevron]{opacity:1;color:var(--seed-color-fg-neutral)}.seed-data-table__headerCell:hover [data-column-menu]{opacity:1}.seed-data-table__headerCell [data-column-menu]:focus-visible,.seed-data-table__headerCell [data-column-menu][data-open]{opacity:1}.seed-data-table__headerCell[data-dragging]{opacity:.5}.seed-data-table__headerCell[data-sticky]{position:sticky;z-index:3;background-color:var(--seed-color-bg-layer-default)}.seed-data-table__headerCell{outline:var(--seed-dimension-x0_5) solid transparent;outline-offset:calc(var(--seed-dimension-x0_5) * -1)}.seed-data-table__headerCell:is(:focus-visible,[data-focus-visible]){outline:var(--seed-dimension-x0_5) solid var(--seed-color-stroke-focus-ring);outline-offset:calc(var(--seed-dimension-x0_5) * -1)}.seed-data-table__headerCell .seed-data-table-resize-handle{position:absolute;top:0;inset-inline-end:calc(7px / -2);width:7px;height:100%;z-index:4;display:flex;align-items:center;justify-content:center;cursor:col-resize;touch-action:none}.seed-data-table__headerCell .seed-data-table-resize-handle-inner{width:3px;height:100%;border-radius:3px;background-color:#0298d9;opacity:0;transition:opacity .1s}.seed-data-table__headerCell .seed-data-table-resize-handle:hover .seed-data-table-resize-handle-inner,.seed-data-table__headerCell .seed-data-table-resize-handle[data-resizing] .seed-data-table-resize-handle-inner{opacity:1}.seed-data-table__headerCellInner{box-sizing:border-box;display:flex;align-items:center;width:100%;height:100%;min-width:0;gap:var(--seed-dimension-x1_5);padding-inline:var(--seed-dimension-x3)}.seed-data-table__headerCellLabel{min-width:0;flex:1 1 0%;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__headerCellIcon{flex-shrink:0;margin-inline-start:auto;display:inline-flex;align-items:center;justify-content:center;width:var(--seed-dimension-x4);height:var(--seed-dimension-x4);color:var(--seed-color-fg-neutral-subtle);border:none;background:0 0;padding:0;font:inherit;cursor:pointer}.seed-data-table__headerCellIcon[data-active]{color:var(--seed-color-fg-neutral)}.seed-data-table__headerCellIcon[data-column-menu]{opacity:0;transition:opacity .12s}.seed-data-table__row{position:relative;background-color:var(--seed-color-bg-layer-default);--seed-data-table-row-bg:var(--seed-color-bg-layer-default)}.seed-data-table__row[data-clickable]{cursor:pointer}.seed-data-table__row:is([aria-selected=true],[data-selected]){background-color:color-mix(in srgb,#0298d9 10%,var(--seed-color-bg-layer-default));--seed-data-table-row-bg:color-mix(in srgb, #0298d9 10%, var(--seed-color-bg-layer-default))}.seed-data-table__row:is([aria-selected=true],[data-selected]):is(:hover,[data-hover]){background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 3%,color-mix(in srgb,#0298d9 10%,var(--seed-color-bg-layer-default)));--seed-data-table-row-bg:color-mix(in srgb, var(--seed-color-fg-neutral) 3%, color-mix(in srgb, #0298d9 10%, var(--seed-color-bg-layer-default)))}.seed-data-table__cell{box-sizing:border-box;position:relative;vertical-align:middle;text-align:start;height:var(--seed-dimension-x9);border-bottom:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-top:none;border-inline-start:none;padding-block:0;padding-inline:var(--seed-dimension-x3);color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-regular);letter-spacing:-.14px;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__cell:last-child{border-inline-end:none}tbody tr:last-child .seed-data-table__cell{border-bottom:none}.seed-data-table__cell[data-numeric]{text-align:end;font-variant-numeric:tabular-nums}.seed-data-table__cell[data-sticky]{position:sticky;z-index:1;background-color:var(--seed-data-table-row-bg)}.seed-data-table__cell[data-editable]{cursor:default}.seed-data-table__cell .seed-data-table-edit-picker{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);min-width:0}.seed-data-table__cell .seed-data-table-edit-pending{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);animation:rotate .6s linear infinite}.seed-data-table__cell .seed-data-table-edit-error{position:absolute;top:100%;inset-inline-start:var(--seed-dimension-x3);inset-inline-end:var(--seed-dimension-x3);z-index:2;padding-top:2px;font-size:12px;line-height:1.3;color:var(--seed-color-fg-critical);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__entity{display:flex;align-items:center;min-width:0;gap:var(--seed-dimension-x1_5)}.seed-data-table__entityName{min-width:0;font-weight:var(--seed-font-weight-medium);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__tagList{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);overflow:hidden;min-width:0}.seed-data-table__link{color:var(--seed-color-fg-neutral);text-decoration:none;min-width:0;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__link:is(:hover,[data-hover]){text-decoration:underline}.seed-data-table__toolbar{box-sizing:border-box;display:flex;align-items:center;width:100%;flex-shrink:0;min-height:49px;gap:var(--seed-dimension-x2);padding-inline:var(--seed-dimension-x3);border-top:1px solid var(--seed-color-stroke-neutral-muted)}.seed-data-table__search{position:relative;display:inline-flex;align-items:center;flex:1 1 0%;max-width:280px}.seed-data-table__search svg{position:absolute;inset-inline-start:var(--seed-dimension-x2);width:var(--seed-dimension-x4);height:var(--seed-dimension-x4);color:var(--seed-color-fg-neutral-muted);pointer-events:none}.seed-data-table__search input{width:100%;height:var(--seed-dimension-x8);padding-inline-start:var(--seed-dimension-x7);padding-inline-end:var(--seed-dimension-x2);border:none;border-radius:var(--seed-radius-r2);background-color:var(--seed-color-bg-layer-default);box-shadow:inset 0 0 0 1px var(--seed-color-stroke-neutral-weak);font-family:inherit;font-size:var(--seed-font-size-t4);color:var(--seed-color-fg-neutral);outline:0;transition:box-shadow .1s var(--seed-timing-function-easing)}.seed-data-table__search input::placeholder{color:var(--seed-color-fg-neutral-subtle)}.seed-data-table__search input:focus{box-shadow:inset 0 0 0 2px var(--seed-color-stroke-neutral-contrast)}.seed-data-table__count{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);font-size:var(--seed-font-size-t3);font-variant-numeric:tabular-nums}.seed-data-table__toolbarEnd{flex-shrink:0;margin-inline-start:auto;display:inline-flex;align-items:center;gap:var(--seed-dimension-x2)}.seed-data-table__scrollArea{position:relative;display:flex;flex-direction:column;width:100%;min-width:0;flex:1 1 auto;min-height:0;overflow-x:auto;overflow-y:auto}.seed-data-table__scrollArea[data-scrolled-start] [data-sticky-edge]{clip-path:inset(0 -38px 0 0);box-shadow:6px 0 16px 4px rgba(0,0,0,.12)}.seed-data-table__scrollArea[data-scrolled-end] [data-sticky-edge-end]{clip-path:inset(0 0 0 -38px);box-shadow:-6px 0 16px 4px rgba(0,0,0,.12)}.seed-data-table__footerCell{box-sizing:border-box;position:sticky;bottom:0;z-index:2;vertical-align:middle;padding:0;height:var(--seed-dimension-x9);background-color:var(--seed-color-bg-layer-default);border-top:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-inline-start:none}.seed-data-table__footerCell:last-child{border-inline-end:none}.seed-data-table__footerCell .seed-data-table-column-calc-trigger{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);width:100%;height:100%;min-width:0;margin:0;padding:0 var(--seed-dimension-x3);border:none;background:0 0;color:var(--seed-color-fg-neutral-subtle);font-family:inherit;font-size:var(--seed-font-size-t4);font-weight:var(--seed-font-weight-medium);white-space:nowrap;overflow:clip;cursor:pointer;transition:background-color .12s,color .12s}.seed-data-table__footerCell .seed-data-table-column-calc-trigger:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,transparent);color:var(--seed-color-fg-neutral)}.seed-data-table__footerCell .seed-data-table-column-calc-trigger[data-align=right]{justify-content:flex-end}.seed-data-table__footerCell .seed-data-table-column-calc-trigger svg{flex-shrink:0;opacity:.7}.seed-data-table__footerCell .seed-data-table-column-calc-placeholder{overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__footerCell .seed-data-table-column-calc-value{min-width:0;flex-shrink:1;color:var(--seed-color-fg-neutral);font-variant-numeric:tabular-nums;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__footerCell .seed-data-table-column-calc-op{min-width:0;flex-shrink:1;color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__emptyState{box-sizing:border-box;text-align:center;padding-block:var(--seed-dimension-x8);padding-inline:var(--seed-dimension-x3);color:var(--seed-color-fg-neutral-subtle);font-size:var(--seed-font-size-t4)}.seed-data-table__loadingState{box-sizing:border-box;display:flex;align-items:center;justify-content:center;gap:10px;padding-block:var(--seed-dimension-x8);padding-inline:var(--seed-dimension-x3);color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-medium)}.seed-data-table__loadingState[data-inline]{padding-block:0;padding-inline:0;height:var(--seed-dimension-x9)}.seed-data-table__loadingState .seed-data-table-loading-spinner{flex-shrink:0;color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);animation:rotate .6s linear infinite}.seed-data-table__addRowCell{box-sizing:border-box;padding:0;border-top:none}.seed-data-table__addRow{box-sizing:border-box;display:flex;align-items:center;width:100%;margin:0;border:none;border-top:1px solid var(--seed-color-stroke-neutral-muted);background-color:var(--seed-color-bg-layer-default);height:var(--seed-dimension-x9);gap:var(--seed-dimension-x2);padding-inline:var(--seed-dimension-x2);color:var(--seed-color-fg-neutral-subtle);font-family:inherit;font-size:var(--seed-font-size-t4);cursor:pointer;transition:background-color .12s,color .12s}.seed-data-table__addRow:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,var(--seed-color-bg-layer-default));color:var(--seed-color-fg-neutral)}.seed-data-table__addRow svg{flex-shrink:0}.seed-data-table__selectionCell{text-align:center;padding:0}.seed-data-table__root--surface_card{border-color:var(--seed-color-stroke-neutral-muted);background-color:var(--seed-color-bg-layer-default);border-radius:var(--seed-radius-r3)}.seed-data-table__root--surface_bleed{border-color:var(--seed-color-bg-transparent);background-color:var(--seed-color-bg-transparent)}.seed-data-table__row--interactive_true{transition:background-color .12s}.seed-data-table__row--interactive_true:is(:hover,[data-hover]){background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 3%,transparent);--seed-data-table-row-bg:color-mix(in srgb, var(--seed-color-fg-neutral) 3%, var(--seed-color-bg-layer-default))}");
2748
+
2749
+ const createClassName = (className, variants, compoundVariants = [])=>{
2750
+ const variantKeys = Object.keys(variants);
2751
+ const variantValues = variantKeys.map((key)=>variants[key]);
2752
+ const variantClassName = variantKeys.map((key, index)=>`${className}--${key}_${variantValues[index]}`).join(" ");
2753
+ const compountVariantClassName = compoundVariants.filter((compoundVariant)=>Object.keys(compoundVariant).every((key)=>compoundVariant[key] === variants[key])).map((compoundVariant)=>`${className}--${Object.keys(compoundVariant).map((key)=>{
2754
+ return `${key}_${compoundVariant[key]}`;
2755
+ }).join("-")}`).join(" ");
2756
+ return [
2757
+ className,
2758
+ variantClassName,
2759
+ compountVariantClassName
2760
+ ].filter(Boolean).join(" ");
2761
+ };
2762
+ function mergeVariants(a, b) {
2763
+ const result = {
2764
+ ...a
2765
+ };
2766
+ for(const k in b){
2767
+ if (b[k] != null) {
2768
+ result[k] = b[k];
2769
+ }
2770
+ }
2771
+ return result;
2772
+ }
2773
+ function splitVariantProps(props, variantMap) {
2774
+ const variantProps = {};
2775
+ const otherProps = {};
2776
+ for(const key in props){
2777
+ if (variantMap[key] != null) {
2778
+ variantProps[key] = props[key];
2779
+ } else {
2780
+ otherProps[key] = props[key];
2781
+ }
2782
+ }
2783
+ return [
2784
+ variantProps,
2785
+ otherProps
2786
+ ];
2787
+ }
2788
+
2789
+ const dataTableSlotNames = [
2790
+ [
2791
+ "root",
2792
+ "seed-data-table__root"
2793
+ ],
2794
+ [
2795
+ "table",
2796
+ "seed-data-table__table"
2797
+ ],
2798
+ [
2799
+ "header",
2800
+ "seed-data-table__header"
2801
+ ],
2802
+ [
2803
+ "headerCell",
2804
+ "seed-data-table__headerCell"
2805
+ ],
2806
+ [
2807
+ "headerCellInner",
2808
+ "seed-data-table__headerCellInner"
2809
+ ],
2810
+ [
2811
+ "headerCellLabel",
2812
+ "seed-data-table__headerCellLabel"
2813
+ ],
2814
+ [
2815
+ "headerCellIcon",
2816
+ "seed-data-table__headerCellIcon"
2817
+ ],
2818
+ [
2819
+ "row",
2820
+ "seed-data-table__row"
2821
+ ],
2822
+ [
2823
+ "cell",
2824
+ "seed-data-table__cell"
2825
+ ],
2826
+ [
2827
+ "entity",
2828
+ "seed-data-table__entity"
2829
+ ],
2830
+ [
2831
+ "entityName",
2832
+ "seed-data-table__entityName"
2833
+ ],
2834
+ [
2835
+ "tagList",
2836
+ "seed-data-table__tagList"
2837
+ ],
2838
+ [
2839
+ "link",
2840
+ "seed-data-table__link"
2841
+ ],
2842
+ [
2843
+ "toolbar",
2844
+ "seed-data-table__toolbar"
2845
+ ],
2846
+ [
2847
+ "search",
2848
+ "seed-data-table__search"
2849
+ ],
2850
+ [
2851
+ "count",
2852
+ "seed-data-table__count"
2853
+ ],
2854
+ [
2855
+ "toolbarEnd",
2856
+ "seed-data-table__toolbarEnd"
2857
+ ],
2858
+ [
2859
+ "scrollArea",
2860
+ "seed-data-table__scrollArea"
2861
+ ],
2862
+ [
2863
+ "footer",
2864
+ "seed-data-table__footer"
2865
+ ],
2866
+ [
2867
+ "footerCell",
2868
+ "seed-data-table__footerCell"
2869
+ ],
2870
+ [
2871
+ "emptyState",
2872
+ "seed-data-table__emptyState"
2873
+ ],
2874
+ [
2875
+ "loadingState",
2876
+ "seed-data-table__loadingState"
2877
+ ],
2878
+ [
2879
+ "addRow",
2880
+ "seed-data-table__addRow"
2881
+ ],
2882
+ [
2883
+ "addRowCell",
2884
+ "seed-data-table__addRowCell"
2885
+ ],
2886
+ [
2887
+ "selectionCell",
2888
+ "seed-data-table__selectionCell"
2889
+ ]
2890
+ ];
2891
+ const defaultVariant$4 = {
2892
+ "surface": "card",
2893
+ "interactive": false
2894
+ };
2895
+ const compoundVariants$4 = [];
2896
+ const dataTableVariantMap = {
2897
+ "surface": [
2898
+ "card",
2899
+ "bleed"
2900
+ ],
2901
+ "interactive": [
2902
+ true,
2903
+ false
2904
+ ]
2905
+ };
2906
+ function dataTable(props) {
2907
+ return Object.fromEntries(dataTableSlotNames.map(([slot, className])=>{
2908
+ return [
2909
+ slot,
2910
+ createClassName(className, mergeVariants(defaultVariant$4, props), compoundVariants$4)
2911
+ ];
2912
+ }));
2913
+ }
2914
+ Object.assign(dataTable, {
2915
+ splitVariantProps: (props)=>splitVariantProps(props, dataTableVariantMap)
2916
+ }); // @recipe(seed): data-table
2917
+
2918
+ // The one `createSlotRecipeContext(dataTable)` call every sibling file in this
2919
+ // directory shares -- `ClassNamesProvider` and `withContext` must be the SAME
2920
+ // binding everywhere (a slot component built from a second, independent call would
2921
+ // read a DIFFERENT React context and never see the classNames `DataTableInner`
2922
+ // provides), so this is the one place that calls `createSlotRecipeContext`, and every
2923
+ // other file (`DataTable.tsx`, `column-menu.tsx`, `resize.tsx`, `column-calc.tsx`,
2924
+ // `toolbar.tsx`, `body-cells.tsx`, `editors.tsx`) imports its exports from here rather
2925
+ // than re-deriving its own.
2926
+ const { ClassNamesProvider: ClassNamesProvider$1, withContext: withContext$1, useClassNames: useClassNames$1 } = createSlotRecipeContext(dataTable);
2927
+
2928
+ /**
2929
+ * The pure filter itself, split out of `useSelectSearch` below so it can be
2930
+ * mutation-tested directly (the same "small pure function beside its own test" shape
2931
+ * `filtering.ts`'s `matchesSearch`/`getColumnValue` already use in this directory) --
2932
+ * case-insensitive substring match, on whitespace-trimmed input. An empty/whitespace-
2933
+ * only query returns `options` unfiltered rather than matching nothing, the same
2934
+ * "no query yet" case crisp's own `select.tsx` special-cases (`searchable && q`).
2935
+ */ function filterSelectOptions(options, query, getText) {
2936
+ const q = query.trim().toLowerCase();
2937
+ if (!q) return options;
2938
+ return options.filter((option)=>getText(option).toLowerCase().includes(q));
2939
+ }
2940
+ /**
2941
+ * Filters `options` by `getText(option)` against a live query string -- the one
2942
+ * concern every searchable Select popover shares (crisp's own `select.tsx` computes
2943
+ * this inline; this hook is `filterSelectOptions` above plus the query state it reads,
2944
+ * kept generic over `T` so it works for `DataTableEditOption` today and a future
2945
+ * filter-value picker's own option shape without a second copy of the same filter).
2946
+ */ function useSelectSearch(options, getText) {
2947
+ const [query, setQuery] = React.useState("");
2948
+ const filtered = React.useMemo(()=>filterSelectOptions(options, query, getText), [
2949
+ options,
2950
+ query,
2951
+ getText
2952
+ ]);
2953
+ return {
2954
+ query,
2955
+ setQuery,
2956
+ filtered
2957
+ };
2958
+ }
2959
+ /**
2960
+ * The search box itself -- crisp's own top-of-listbox filter field
2961
+ * (`select.tsx`'s `crisp-select-search`), styled with the SAME compact chrome
2962
+ * `toolbar.tsx`'s `SearchBox` already standardized for the table's own toolbar search
2963
+ * (seed's real `text-input.ts` outline-variant tokens, via the `dataTable` recipe's
2964
+ * own `search` slot -- not seed's documented `TextField`, measured too heavy for a
2965
+ * ~32px inline control; see `SearchBox`'s own comment for that measurement). Reusing
2966
+ * the SAME recipe slot here, rather than standing up a second near-identical one,
2967
+ * keeps every "small bordered search input" in this package pixel-identical by
2968
+ * construction -- the slot's `max-width: 280px` (a toolbar-row layout constraint, not
2969
+ * chrome) is overridden inline since this field fills its popover instead.
2970
+ *
2971
+ * Swallows every keydown except Escape before it can reach seed's own listbox
2972
+ * (`SelectContent`'s typeahead-by-keyboard): a search field that ALSO drives the
2973
+ * listbox's letter-jump would fight the query it is supposed to be typing into. Escape
2974
+ * passes through untouched -- `SelectRoot`'s own `onOpenChange` (in every caller) is
2975
+ * what actually closes the editor on Escape, not a handler on this field.
2976
+ *
2977
+ * `autoFocus` is applied imperatively (an effect + ref), not the native `autoFocus`
2978
+ * attribute -- lint (`a11y/noAutofocus`) bars that on a raw `<input>`, and this is the
2979
+ * same ref-and-focus shape crisp's own `select.tsx` already uses for its search field
2980
+ * (`searchRef.current?.focus({ preventScroll: true })` on open), not a workaround
2981
+ * invented for the lint rule.
2982
+ */ function SelectSearchField({ value, onChange, placeholder, "aria-label": ariaLabel, autoFocus, onKeyDown }) {
2983
+ const classNames = dataTable();
2984
+ const inputRef = React.useRef(null);
2985
+ React.useEffect(()=>{
2986
+ if (autoFocus) inputRef.current?.focus({
2987
+ preventScroll: true
2988
+ });
2989
+ }, [
2990
+ autoFocus
2991
+ ]);
2992
+ return /*#__PURE__*/ jsxs("span", {
2993
+ className: classNames.search,
2994
+ style: {
2995
+ display: "flex",
2996
+ maxWidth: "none",
2997
+ margin: 4
2998
+ },
2999
+ children: [
3000
+ /*#__PURE__*/ jsx(IconMagnifyingglassLine_default, {
3001
+ "aria-hidden": "true"
3002
+ }),
3003
+ /*#__PURE__*/ jsx("input", {
3004
+ ref: inputRef,
3005
+ type: "text",
3006
+ value: value,
3007
+ onChange: (event)=>onChange(event.target.value),
3008
+ placeholder: placeholder,
3009
+ "aria-label": ariaLabel ?? placeholder,
3010
+ onClick: (event)=>event.stopPropagation(),
3011
+ onKeyDown: (event)=>{
3012
+ if (event.key !== "Escape") event.stopPropagation();
3013
+ onKeyDown?.(event);
3014
+ }
3015
+ })
3016
+ ]
3017
+ });
3018
+ }
3019
+ /** The empty state shown when a search matches nothing -- crisp's own `searchable`
3020
+ * `emptyLabel` (`crisp-select-empty`), reproduced at the same inset/opacity/size the
3021
+ * ad-hoc `ReferenceEditor` "No users"/"No results" row already used before this file
3022
+ * existed. */ function SelectSearchEmpty({ children }) {
3023
+ return /*#__PURE__*/ jsx("div", {
3024
+ style: {
3025
+ padding: "6px 12px",
3026
+ opacity: 0.63,
3027
+ fontSize: 13
3028
+ },
3029
+ children: children
3030
+ });
3031
+ }
3032
+
2747
3033
  /** The raw value a live editor reads, distinct from `DataTableColumn.value` (the
2748
3034
  * accessor sort/search/filter/export share): `editValue` returns whatever TYPE the
2749
3035
  * editor itself expects -- a real `boolean` for `editor: "switch"`/`type:
@@ -2846,10 +3132,21 @@ function DateEditor({ column, value, pending, onCommit, onCancel }) {
2846
3132
  ////////////////////////////////////////////////////////////////////////////////////
2847
3133
  // -- editor: "select" -- double-click opens seed's own Select, auto-opened (seed's
2848
3134
  // `SelectRoot` takes `defaultOpen` directly -- unlike crisp's closed-API `Select`,
2849
- // which needs a synthetic click on its own trigger to start open). -------------
3135
+ // which needs a synthetic click on its own trigger to start open). A long option
3136
+ // list gets crisp's own search-on-top (`select-search.tsx`) for free, past
3137
+ // `SELECT_EDITOR_SEARCH_THRESHOLD` -- fewer options than that and a filter field
3138
+ // is pure noise above a list you can already scan (crisp's own `searchable` is
3139
+ // opt-in for the identical reason); `column.editorSearchable` overrides either way.
3140
+ /** Above this many options, `SelectEditor` turns its search field on by default --
3141
+ * below it, a filter box adds more chrome than it saves (nothing here claims this
3142
+ * exact number is measured; it is a judgment call, which is why `editorSearchable`
3143
+ * exists to override it either direction). */ const SELECT_EDITOR_SEARCH_THRESHOLD = 8;
2850
3144
  function SelectEditor({ column, value, pending, onCommit, onCancel }) {
2851
3145
  const options = column.options ?? [];
2852
3146
  const current = value == null ? "" : String(value);
3147
+ const searchable = column.editorSearchable ?? options.length > SELECT_EDITOR_SEARCH_THRESHOLD;
3148
+ const { query, setQuery, filtered } = useSelectSearch(options, (option)=>option.label);
3149
+ const visible = searchable ? filtered : options;
2853
3150
  return /*#__PURE__*/ jsxs(SelectRoot, {
2854
3151
  // Controlled open, per docs/examples/react/select/controlled-open.tsx --
2855
3152
  // this editor is only ever mounted while the cell IS editing, so it always
@@ -2881,38 +3178,54 @@ function SelectEditor({ column, value, pending, onCommit, onCancel }) {
2881
3178
  ]
2882
3179
  }),
2883
3180
  /*#__PURE__*/ jsx(SelectPositioner, {
2884
- children: /*#__PURE__*/ jsx(SelectContent, {
2885
- children: /*#__PURE__*/ jsx(SelectScrollArea, {
2886
- children: options.map((option)=>/*#__PURE__*/ jsxs(SelectItem, {
2887
- value: option.value,
2888
- label: option.label,
2889
- children: [
2890
- /*#__PURE__*/ jsx(SelectItemBody, {
2891
- children: /*#__PURE__*/ jsx(SelectItemLabel, {})
2892
- }),
2893
- /*#__PURE__*/ jsx(SelectItemIndicator, {
2894
- selected: /*#__PURE__*/ jsx(IconCheckmarkFatFill_default, {})
2895
- })
2896
- ]
2897
- }, option.value))
2898
- })
3181
+ children: /*#__PURE__*/ jsxs(SelectContent, {
3182
+ children: [
3183
+ searchable && /*#__PURE__*/ jsx(SelectSearchField, {
3184
+ autoFocus: true,
3185
+ value: query,
3186
+ onChange: setQuery,
3187
+ placeholder: column.editorSearchPlaceholder ?? "Search…",
3188
+ "aria-label": `Search ${column.key}`
3189
+ }),
3190
+ /*#__PURE__*/ jsxs(SelectScrollArea, {
3191
+ children: [
3192
+ searchable && visible.length === 0 && /*#__PURE__*/ jsx(SelectSearchEmpty, {
3193
+ children: column.editorEmptyLabel ?? "No results"
3194
+ }),
3195
+ visible.map((option)=>/*#__PURE__*/ jsxs(SelectItem, {
3196
+ value: option.value,
3197
+ label: option.label,
3198
+ children: [
3199
+ /*#__PURE__*/ jsx(SelectItemBody, {
3200
+ children: /*#__PURE__*/ jsx(SelectItemLabel, {})
3201
+ }),
3202
+ /*#__PURE__*/ jsx(SelectItemIndicator, {
3203
+ selected: /*#__PURE__*/ jsx(IconCheckmarkFatFill_default, {})
3204
+ })
3205
+ ]
3206
+ }, option.value))
3207
+ ]
3208
+ })
3209
+ ]
2899
3210
  })
2900
3211
  })
2901
3212
  ]
2902
3213
  });
2903
3214
  }
2904
3215
  ////////////////////////////////////////////////////////////////////////////////////
2905
- // -- editor: "reference" / "actor" -- same picker, search-enabled, each option
2906
- // carrying a small avatar (a photo for a real one, a generic person glyph for
2907
- // none) -- `actor` is `reference` over people specifically (crisp's own #449/
2908
- // #432 `ReferenceCell` shape), so the two share one component; only the search
2909
- // placeholder differs. Seed's `Select` has no built-in search combobox (unlike
2910
- // crisp's own `Select`), so this filters `refOptions` itself against a small
2911
- // `TextField` rendered as the content's own first row. --------------------------
3216
+ // -- editor: "reference" / "actor" -- same picker, ALWAYS search-enabled (unlike
3217
+ // `SelectEditor`'s threshold -- a reference/actor list is people/records, search
3218
+ // is the point regardless of how few there are today), each option carrying a
3219
+ // small avatar (a photo for a real one, a generic person glyph for none) --
3220
+ // `actor` is `reference` over people specifically (crisp's own #449/#432
3221
+ // `ReferenceCell` shape), so the two share one component; only the search
3222
+ // placeholder/empty copy differs. Seed's `Select` has no built-in search combobox
3223
+ // (unlike crisp's own `Select`), so this uses the shared `select-search.tsx`
3224
+ // field/hook -- the same one `SelectEditor` above uses -- rather than its own
3225
+ // copy of the query/filter/empty triangle. --------------------------------------
2912
3226
  function ReferenceEditor({ column, value, pending, onCommit, onCancel }) {
2913
- const [query, setQuery] = React.useState("");
2914
3227
  const options = column.refOptions ?? [];
2915
- const filtered = query.trim() ? options.filter((option)=>option.label.toLowerCase().includes(query.trim().toLowerCase())) : options;
3228
+ const { query, setQuery, filtered } = useSelectSearch(options, (option)=>option.label);
2916
3229
  const current = value == null ? "" : String(value);
2917
3230
  const isActor = column.editor === "actor";
2918
3231
  return /*#__PURE__*/ jsxs(SelectRoot, {
@@ -2942,40 +3255,17 @@ function ReferenceEditor({ column, value, pending, onCommit, onCancel }) {
2942
3255
  /*#__PURE__*/ jsx(SelectPositioner, {
2943
3256
  children: /*#__PURE__*/ jsxs(SelectContent, {
2944
3257
  children: [
2945
- /*#__PURE__*/ jsx(TextFieldRoot, {
2946
- size: "medium",
2947
- style: {
2948
- margin: 4
2949
- },
2950
- onKeyDown: (event)=>{
2951
- // The listbox's own typeahead/arrow handling lives on THIS field's
2952
- // sibling items, not on the field itself -- stop everything except
2953
- // Escape from also driving the listbox's own keyboard nav. Escape
2954
- // itself needs no special-casing to "reach" anything any more: it's
2955
- // SelectContent's own `DismissibleLayer` (Select.tsx) that closes the
2956
- // listbox, and that dismissal is a document-level listener outside
2957
- // this React subtree entirely -- a synthetic `stopPropagation` here
2958
- // was never able to block it either way, so the controlled `open`
2959
- // above (via `onOpenChange`) is what actually ends this cell's edit.
2960
- if (event.key !== "Escape") event.stopPropagation();
2961
- },
2962
- children: /*#__PURE__*/ jsx(TextFieldInput, {
2963
- autoFocus: true,
2964
- "aria-label": isActor ? "Search people" : `Search ${column.key}`,
2965
- placeholder: isActor ? "Search people…" : "Search…",
2966
- value: query,
2967
- onChange: (event)=>setQuery(event.target.value)
2968
- })
3258
+ /*#__PURE__*/ jsx(SelectSearchField, {
3259
+ autoFocus: true,
3260
+ value: query,
3261
+ onChange: setQuery,
3262
+ placeholder: column.refSearchPlaceholder ?? (isActor ? "Search people…" : "Search…"),
3263
+ "aria-label": isActor ? "Search people" : `Search ${column.key}`
2969
3264
  }),
2970
3265
  /*#__PURE__*/ jsxs(SelectScrollArea, {
2971
3266
  children: [
2972
- filtered.length === 0 && /*#__PURE__*/ jsx("div", {
2973
- style: {
2974
- padding: "6px 12px",
2975
- opacity: 0.63,
2976
- fontSize: 13
2977
- },
2978
- children: isActor ? "No users" : "No results"
3267
+ filtered.length === 0 && /*#__PURE__*/ jsx(SelectSearchEmpty, {
3268
+ children: column.refEmptyLabel ?? (isActor ? "No users" : "No results")
2979
3269
  }),
2980
3270
  filtered.map((option)=>/*#__PURE__*/ jsxs(SelectItem, {
2981
3271
  value: option.value,
@@ -3351,7 +3641,7 @@ function DisplayCellContent({ column, row, value, classNames, locale }) {
3351
3641
  }
3352
3642
  }
3353
3643
 
3354
- const { ClassNamesProvider: ClassNamesProvider$1, withContext: withContext$1, useClassNames: useClassNames$1 } = createSlotRecipeContext(menu);
3644
+ const { ClassNamesProvider, withContext, useClassNames } = createSlotRecipeContext(menu);
3355
3645
  const { PropsProvider: ItemPropsProvider, useProps: useItemProps, withContext: withItemContext, ClassNamesProvider: ItemClassNamesProvider } = createSlotRecipeContext(menuItem);
3356
3646
  const withStateProps = createWithStateProps([
3357
3647
  useMenuContext
@@ -3362,7 +3652,7 @@ const withItemStateProps = createWithStateProps([
3362
3652
  const MenuRoot = (props)=>{
3363
3653
  const [variantProps, otherProps] = menu.splitVariantProps(props);
3364
3654
  const classNames = menu(variantProps);
3365
- return /*#__PURE__*/ jsx(ClassNamesProvider$1, {
3655
+ return /*#__PURE__*/ jsx(ClassNamesProvider, {
3366
3656
  value: classNames,
3367
3657
  children: /*#__PURE__*/ jsx(ItemPropsProvider, {
3368
3658
  value: {
@@ -3377,7 +3667,7 @@ const MenuRoot = (props)=>{
3377
3667
  Menu.Anchor;
3378
3668
  const MenuTrigger = Menu.Trigger;
3379
3669
  const MenuPositioner = /*#__PURE__*/ React.forwardRef(({ className, ...props }, ref)=>{
3380
- const classNames = useClassNames$1();
3670
+ const classNames = useClassNames();
3381
3671
  return /*#__PURE__*/ jsx(Menu.Positioner, {
3382
3672
  ref: ref,
3383
3673
  className: clsx(classNames.positioner, className),
@@ -3385,10 +3675,10 @@ const MenuPositioner = /*#__PURE__*/ React.forwardRef(({ className, ...props },
3385
3675
  });
3386
3676
  });
3387
3677
  MenuPositioner.displayName = "MenuPositioner";
3388
- const MenuContent = withContext$1(Menu.Content, "content");
3389
- const MenuScrollArea = withContext$1(withStateProps(Primitive.div), "scrollArea");
3390
- withContext$1(Menu.Group, "group");
3391
- withContext$1(Menu.GroupLabel, "groupLabel");
3678
+ const MenuContent = withContext(Menu.Content, "content");
3679
+ const MenuScrollArea = withContext(withStateProps(Primitive.div), "scrollArea");
3680
+ withContext(Menu.Group, "group");
3681
+ withContext(Menu.GroupLabel, "groupLabel");
3392
3682
  const MenuItem = /*#__PURE__*/ React.forwardRef(({ className: propClassName, ...props }, ref)=>{
3393
3683
  const [variantProps, otherProps] = menuItem.splitVariantProps(props);
3394
3684
  const parentProps = useItemProps();
@@ -3807,187 +4097,6 @@ function ColumnRenameInput({ column, initialLabel, onDone }) {
3807
4097
  });
3808
4098
  }
3809
4099
 
3810
- __insertCSS(".seed-data-table__root{box-sizing:border-box;display:flex;flex-direction:column;width:100%;border-width:1px;border-style:solid;font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.seed-data-table__table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.seed-data-table__headerCell{box-sizing:border-box;position:sticky;top:0;z-index:2;vertical-align:middle;text-align:start;padding:0;height:var(--seed-dimension-x10);background-color:var(--seed-color-bg-layer-default);border-top:1px solid var(--seed-color-stroke-neutral-muted);border-bottom:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-inline-start:none;color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-medium);letter-spacing:-.14px}.seed-data-table__headerCell:last-child{border-inline-end:none}.seed-data-table__headerCell[data-sortable]{cursor:pointer;user-select:none}.seed-data-table__headerCell [data-chevron]{opacity:0;transition:opacity .12s}.seed-data-table__headerCell[data-sortable]:hover [data-chevron]{opacity:.6}.seed-data-table__headerCell[data-sorted] [data-chevron]{opacity:1;color:var(--seed-color-fg-neutral)}.seed-data-table__headerCell:hover [data-column-menu]{opacity:1}.seed-data-table__headerCell [data-column-menu]:focus-visible,.seed-data-table__headerCell [data-column-menu][data-open]{opacity:1}.seed-data-table__headerCell[data-dragging]{opacity:.5}.seed-data-table__headerCell[data-sticky]{position:sticky;z-index:3;background-color:var(--seed-color-bg-layer-default)}.seed-data-table__headerCell{outline:var(--seed-dimension-x0_5) solid transparent;outline-offset:calc(var(--seed-dimension-x0_5) * -1)}.seed-data-table__headerCell:is(:focus-visible,[data-focus-visible]){outline:var(--seed-dimension-x0_5) solid var(--seed-color-stroke-focus-ring);outline-offset:calc(var(--seed-dimension-x0_5) * -1)}.seed-data-table__headerCell .seed-data-table-resize-handle{position:absolute;top:0;inset-inline-end:calc(7px / -2);width:7px;height:100%;z-index:4;display:flex;align-items:center;justify-content:center;cursor:col-resize;touch-action:none}.seed-data-table__headerCell .seed-data-table-resize-handle-inner{width:3px;height:100%;border-radius:3px;background-color:#0298d9;opacity:0;transition:opacity .1s}.seed-data-table__headerCell .seed-data-table-resize-handle:hover .seed-data-table-resize-handle-inner,.seed-data-table__headerCell .seed-data-table-resize-handle[data-resizing] .seed-data-table-resize-handle-inner{opacity:1}.seed-data-table__headerCellInner{box-sizing:border-box;display:flex;align-items:center;width:100%;height:100%;min-width:0;gap:var(--seed-dimension-x1_5);padding-inline:var(--seed-dimension-x3)}.seed-data-table__headerCellLabel{min-width:0;flex:1 1 0%;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__headerCellIcon{flex-shrink:0;margin-inline-start:auto;display:inline-flex;align-items:center;justify-content:center;width:var(--seed-dimension-x4);height:var(--seed-dimension-x4);color:var(--seed-color-fg-neutral-subtle);border:none;background:0 0;padding:0;font:inherit;cursor:pointer}.seed-data-table__headerCellIcon[data-active]{color:var(--seed-color-fg-neutral)}.seed-data-table__headerCellIcon[data-column-menu]{opacity:0;transition:opacity .12s}.seed-data-table__row{position:relative;background-color:var(--seed-color-bg-layer-default);--seed-data-table-row-bg:var(--seed-color-bg-layer-default)}.seed-data-table__row[data-clickable]{cursor:pointer}.seed-data-table__row:is([aria-selected=true],[data-selected]){background-color:color-mix(in srgb,#0298d9 10%,var(--seed-color-bg-layer-default));--seed-data-table-row-bg:color-mix(in srgb, #0298d9 10%, var(--seed-color-bg-layer-default))}.seed-data-table__row:is([aria-selected=true],[data-selected]):is(:hover,[data-hover]){background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 3%,color-mix(in srgb,#0298d9 10%,var(--seed-color-bg-layer-default)));--seed-data-table-row-bg:color-mix(in srgb, var(--seed-color-fg-neutral) 3%, color-mix(in srgb, #0298d9 10%, var(--seed-color-bg-layer-default)))}.seed-data-table__cell{box-sizing:border-box;position:relative;vertical-align:middle;text-align:start;height:var(--seed-dimension-x9);border-bottom:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-top:none;border-inline-start:none;padding-block:0;padding-inline:var(--seed-dimension-x3);color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-regular);letter-spacing:-.14px;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__cell:last-child{border-inline-end:none}tbody tr:last-child .seed-data-table__cell{border-bottom:none}.seed-data-table__cell[data-numeric]{text-align:end;font-variant-numeric:tabular-nums}.seed-data-table__cell[data-sticky]{position:sticky;z-index:1;background-color:var(--seed-data-table-row-bg)}.seed-data-table__cell[data-editable]{cursor:default}.seed-data-table__cell .seed-data-table-edit-picker{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);min-width:0}.seed-data-table__cell .seed-data-table-edit-pending{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);animation:rotate .6s linear infinite}.seed-data-table__cell .seed-data-table-edit-error{position:absolute;top:100%;inset-inline-start:var(--seed-dimension-x3);inset-inline-end:var(--seed-dimension-x3);z-index:2;padding-top:2px;font-size:12px;line-height:1.3;color:var(--seed-color-fg-critical);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__entity{display:flex;align-items:center;min-width:0;gap:var(--seed-dimension-x1_5)}.seed-data-table__entityName{min-width:0;font-weight:var(--seed-font-weight-medium);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__tagList{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);overflow:hidden;min-width:0}.seed-data-table__link{color:var(--seed-color-fg-neutral);text-decoration:none;min-width:0;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__link:is(:hover,[data-hover]){text-decoration:underline}.seed-data-table__toolbar{box-sizing:border-box;display:flex;align-items:center;width:100%;flex-shrink:0;min-height:49px;gap:var(--seed-dimension-x2);padding-inline:var(--seed-dimension-x3);border-top:1px solid var(--seed-color-stroke-neutral-muted)}.seed-data-table__search{position:relative;display:inline-flex;align-items:center;flex:1 1 0%;max-width:280px}.seed-data-table__search svg{position:absolute;inset-inline-start:var(--seed-dimension-x2);width:var(--seed-dimension-x4);height:var(--seed-dimension-x4);color:var(--seed-color-fg-neutral-muted);pointer-events:none}.seed-data-table__search input{width:100%;height:var(--seed-dimension-x8);padding-inline-start:var(--seed-dimension-x7);padding-inline-end:var(--seed-dimension-x2);border:none;border-radius:var(--seed-radius-r2);background-color:var(--seed-color-bg-layer-default);box-shadow:inset 0 0 0 1px var(--seed-color-stroke-neutral-weak);font-family:inherit;font-size:var(--seed-font-size-t4);color:var(--seed-color-fg-neutral);outline:0;transition:box-shadow .1s var(--seed-timing-function-easing)}.seed-data-table__search input::placeholder{color:var(--seed-color-fg-neutral-subtle)}.seed-data-table__search input:focus{box-shadow:inset 0 0 0 2px var(--seed-color-stroke-neutral-contrast)}.seed-data-table__count{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);font-size:var(--seed-font-size-t3);font-variant-numeric:tabular-nums}.seed-data-table__toolbarEnd{flex-shrink:0;margin-inline-start:auto;display:inline-flex;align-items:center;gap:var(--seed-dimension-x2)}.seed-data-table__scrollArea{position:relative;display:flex;flex-direction:column;width:100%;min-width:0;flex:1 1 auto;min-height:0;overflow-x:auto;overflow-y:auto}.seed-data-table__scrollArea[data-scrolled-start] [data-sticky-edge]{clip-path:inset(0 -38px 0 0);box-shadow:6px 0 16px 4px rgba(0,0,0,.12)}.seed-data-table__scrollArea[data-scrolled-end] [data-sticky-edge-end]{clip-path:inset(0 0 0 -38px);box-shadow:-6px 0 16px 4px rgba(0,0,0,.12)}.seed-data-table__footerCell{box-sizing:border-box;position:sticky;bottom:0;z-index:2;vertical-align:middle;padding:0;height:var(--seed-dimension-x9);background-color:var(--seed-color-bg-layer-default);border-top:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-inline-start:none}.seed-data-table__footerCell:last-child{border-inline-end:none}.seed-data-table__footerCell .seed-data-table-column-calc-trigger{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);width:100%;height:100%;min-width:0;margin:0;padding:0 var(--seed-dimension-x3);border:none;background:0 0;color:var(--seed-color-fg-neutral-subtle);font-family:inherit;font-size:var(--seed-font-size-t4);font-weight:var(--seed-font-weight-medium);white-space:nowrap;overflow:clip;cursor:pointer;transition:background-color .12s,color .12s}.seed-data-table__footerCell .seed-data-table-column-calc-trigger:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,transparent);color:var(--seed-color-fg-neutral)}.seed-data-table__footerCell .seed-data-table-column-calc-trigger[data-align=right]{justify-content:flex-end}.seed-data-table__footerCell .seed-data-table-column-calc-trigger svg{flex-shrink:0;opacity:.7}.seed-data-table__footerCell .seed-data-table-column-calc-placeholder{overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__footerCell .seed-data-table-column-calc-value{min-width:0;flex-shrink:1;color:var(--seed-color-fg-neutral);font-variant-numeric:tabular-nums;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__footerCell .seed-data-table-column-calc-op{min-width:0;flex-shrink:1;color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__emptyState{box-sizing:border-box;text-align:center;padding-block:var(--seed-dimension-x8);padding-inline:var(--seed-dimension-x3);color:var(--seed-color-fg-neutral-subtle);font-size:var(--seed-font-size-t4)}.seed-data-table__loadingState{box-sizing:border-box;display:flex;align-items:center;justify-content:center;gap:10px;padding-block:var(--seed-dimension-x8);padding-inline:var(--seed-dimension-x3);color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-medium)}.seed-data-table__loadingState[data-inline]{padding-block:0;padding-inline:0;height:var(--seed-dimension-x9)}.seed-data-table__loadingState .seed-data-table-loading-spinner{flex-shrink:0;color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);animation:rotate .6s linear infinite}.seed-data-table__addRowCell{box-sizing:border-box;padding:0;border-top:none}.seed-data-table__addRow{box-sizing:border-box;display:flex;align-items:center;width:100%;margin:0;border:none;border-top:1px solid var(--seed-color-stroke-neutral-muted);background-color:var(--seed-color-bg-layer-default);height:var(--seed-dimension-x9);gap:var(--seed-dimension-x2);padding-inline:var(--seed-dimension-x2);color:var(--seed-color-fg-neutral-subtle);font-family:inherit;font-size:var(--seed-font-size-t4);cursor:pointer;transition:background-color .12s,color .12s}.seed-data-table__addRow:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,var(--seed-color-bg-layer-default));color:var(--seed-color-fg-neutral)}.seed-data-table__addRow svg{flex-shrink:0}.seed-data-table__selectionCell{text-align:center;padding:0}.seed-data-table__root--surface_card{border-color:var(--seed-color-stroke-neutral-muted);background-color:var(--seed-color-bg-layer-default);border-radius:var(--seed-radius-r3)}.seed-data-table__root--surface_bleed{border-color:var(--seed-color-bg-transparent);background-color:var(--seed-color-bg-transparent)}.seed-data-table__row--interactive_true{transition:background-color .12s}.seed-data-table__row--interactive_true:is(:hover,[data-hover]){background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 3%,transparent);--seed-data-table-row-bg:color-mix(in srgb, var(--seed-color-fg-neutral) 3%, var(--seed-color-bg-layer-default))}");
3811
-
3812
- const createClassName = (className, variants, compoundVariants = [])=>{
3813
- const variantKeys = Object.keys(variants);
3814
- const variantValues = variantKeys.map((key)=>variants[key]);
3815
- const variantClassName = variantKeys.map((key, index)=>`${className}--${key}_${variantValues[index]}`).join(" ");
3816
- const compountVariantClassName = compoundVariants.filter((compoundVariant)=>Object.keys(compoundVariant).every((key)=>compoundVariant[key] === variants[key])).map((compoundVariant)=>`${className}--${Object.keys(compoundVariant).map((key)=>{
3817
- return `${key}_${compoundVariant[key]}`;
3818
- }).join("-")}`).join(" ");
3819
- return [
3820
- className,
3821
- variantClassName,
3822
- compountVariantClassName
3823
- ].filter(Boolean).join(" ");
3824
- };
3825
- function mergeVariants(a, b) {
3826
- const result = {
3827
- ...a
3828
- };
3829
- for(const k in b){
3830
- if (b[k] != null) {
3831
- result[k] = b[k];
3832
- }
3833
- }
3834
- return result;
3835
- }
3836
- function splitVariantProps(props, variantMap) {
3837
- const variantProps = {};
3838
- const otherProps = {};
3839
- for(const key in props){
3840
- if (variantMap[key] != null) {
3841
- variantProps[key] = props[key];
3842
- } else {
3843
- otherProps[key] = props[key];
3844
- }
3845
- }
3846
- return [
3847
- variantProps,
3848
- otherProps
3849
- ];
3850
- }
3851
-
3852
- const dataTableSlotNames = [
3853
- [
3854
- "root",
3855
- "seed-data-table__root"
3856
- ],
3857
- [
3858
- "table",
3859
- "seed-data-table__table"
3860
- ],
3861
- [
3862
- "header",
3863
- "seed-data-table__header"
3864
- ],
3865
- [
3866
- "headerCell",
3867
- "seed-data-table__headerCell"
3868
- ],
3869
- [
3870
- "headerCellInner",
3871
- "seed-data-table__headerCellInner"
3872
- ],
3873
- [
3874
- "headerCellLabel",
3875
- "seed-data-table__headerCellLabel"
3876
- ],
3877
- [
3878
- "headerCellIcon",
3879
- "seed-data-table__headerCellIcon"
3880
- ],
3881
- [
3882
- "row",
3883
- "seed-data-table__row"
3884
- ],
3885
- [
3886
- "cell",
3887
- "seed-data-table__cell"
3888
- ],
3889
- [
3890
- "entity",
3891
- "seed-data-table__entity"
3892
- ],
3893
- [
3894
- "entityName",
3895
- "seed-data-table__entityName"
3896
- ],
3897
- [
3898
- "tagList",
3899
- "seed-data-table__tagList"
3900
- ],
3901
- [
3902
- "link",
3903
- "seed-data-table__link"
3904
- ],
3905
- [
3906
- "toolbar",
3907
- "seed-data-table__toolbar"
3908
- ],
3909
- [
3910
- "search",
3911
- "seed-data-table__search"
3912
- ],
3913
- [
3914
- "count",
3915
- "seed-data-table__count"
3916
- ],
3917
- [
3918
- "toolbarEnd",
3919
- "seed-data-table__toolbarEnd"
3920
- ],
3921
- [
3922
- "scrollArea",
3923
- "seed-data-table__scrollArea"
3924
- ],
3925
- [
3926
- "footer",
3927
- "seed-data-table__footer"
3928
- ],
3929
- [
3930
- "footerCell",
3931
- "seed-data-table__footerCell"
3932
- ],
3933
- [
3934
- "emptyState",
3935
- "seed-data-table__emptyState"
3936
- ],
3937
- [
3938
- "loadingState",
3939
- "seed-data-table__loadingState"
3940
- ],
3941
- [
3942
- "addRow",
3943
- "seed-data-table__addRow"
3944
- ],
3945
- [
3946
- "addRowCell",
3947
- "seed-data-table__addRowCell"
3948
- ],
3949
- [
3950
- "selectionCell",
3951
- "seed-data-table__selectionCell"
3952
- ]
3953
- ];
3954
- const defaultVariant$4 = {
3955
- "surface": "card",
3956
- "interactive": false
3957
- };
3958
- const compoundVariants$4 = [];
3959
- const dataTableVariantMap = {
3960
- "surface": [
3961
- "card",
3962
- "bleed"
3963
- ],
3964
- "interactive": [
3965
- true,
3966
- false
3967
- ]
3968
- };
3969
- function dataTable(props) {
3970
- return Object.fromEntries(dataTableSlotNames.map(([slot, className])=>{
3971
- return [
3972
- slot,
3973
- createClassName(className, mergeVariants(defaultVariant$4, props), compoundVariants$4)
3974
- ];
3975
- }));
3976
- }
3977
- Object.assign(dataTable, {
3978
- splitVariantProps: (props)=>splitVariantProps(props, dataTableVariantMap)
3979
- }); // @recipe(seed): data-table
3980
-
3981
- // The one `createSlotRecipeContext(dataTable)` call every sibling file in this
3982
- // directory shares -- `ClassNamesProvider` and `withContext` must be the SAME
3983
- // binding everywhere (a slot component built from a second, independent call would
3984
- // read a DIFFERENT React context and never see the classNames `DataTableInner`
3985
- // provides), so this is the one place that calls `createSlotRecipeContext`, and every
3986
- // other file (`DataTable.tsx`, `column-menu.tsx`, `resize.tsx`, `column-calc.tsx`,
3987
- // `toolbar.tsx`, `body-cells.tsx`, `editors.tsx`) imports its exports from here rather
3988
- // than re-deriving its own.
3989
- const { ClassNamesProvider, withContext, useClassNames } = createSlotRecipeContext(dataTable);
3990
-
3991
4100
  /**
3992
4101
  * A small inline spinner, not seed's own `ProgressCircle` -- that component's
3993
4102
  * smallest size (24px) is already bigger than crisp's own measured 16px loading
@@ -9630,8 +9739,8 @@ const formatFilterDate = (iso)=>{
9630
9739
  });
9631
9740
  }
9632
9741
 
9633
- const DataTableToolbar = withContext(Primitive.div, "toolbar");
9634
- const DataTableCount = withContext(Primitive.span, "count");
9742
+ const DataTableToolbar = withContext$1(Primitive.div, "toolbar");
9743
+ const DataTableCount = withContext$1(Primitive.span, "count");
9635
9744
  /**
9636
9745
  * The toolbar's own right-hand group -- `count`'s `marginInlineStart: auto` moved
9637
9746
  * here (off the `<span>` itself) so a consumer's `toolbarActions` and the row count
@@ -9642,7 +9751,7 @@ const DataTableCount = withContext(Primitive.span, "count");
9642
9751
  * it. `DataTable.tsx` always renders this wrapper once either `toolbarActions` or
9643
9752
  * `showCount` is on, so it degrades to exactly the old single-count layout when no
9644
9753
  * `toolbarActions` is passed.
9645
- */ const DataTableToolbarEnd = withContext(Primitive.div, "toolbarEnd");
9754
+ */ const DataTableToolbarEnd = withContext$1(Primitive.div, "toolbarEnd");
9646
9755
  /**
9647
9756
  * A compact, borderless search box -- crisp's own measured `.crisp-datatable-search`
9648
9757
  * (32px, `bgSurface` background, a leading icon, a soft rest-state shadow, a 1px brand
@@ -9797,7 +9906,7 @@ function DataTableInner(props, ref) {
9797
9906
  // loading/error/empty body, infinite scroll's sentinel, the add-row footer) reads
9798
9907
  // this ONE value rather than each re-deriving it, so they can never drift apart.
9799
9908
  const totalCols = columns.length + (selectable ? 1 : 0);
9800
- return /*#__PURE__*/ jsx(ClassNamesProvider, {
9909
+ return /*#__PURE__*/ jsx(ClassNamesProvider$1, {
9801
9910
  value: classNames,
9802
9911
  children: /*#__PURE__*/ jsxs(DataTableRoot, {
9803
9912
  ref: ref,
@@ -10052,7 +10161,7 @@ DataTableInner.displayName = "DataTable";
10052
10161
  // is a SIBLING of the toolbar (both inside `DataTablePrimitiveRoot`'s card `<div>`)
10053
10162
  // rather than `DataTablePrimitiveRoot` itself: a `<table>` cannot host the toolbar as a
10054
10163
  // child without the HTML parser foster-parenting it back out.
10055
- const DataTableTable = withContext(DataTableTable$1, "table");
10164
+ const DataTableTable = withContext$1(DataTableTable$1, "table");
10056
10165
  /** One `<col>` per rendered column (plus the 40px selection column, if any) -- the
10057
10166
  * SINGLE place a column's width is ever set now. Every row's header/body/footer cell
10058
10167
  * reads its own width off this shared `<colgroup>` by construction (native table
@@ -10077,15 +10186,15 @@ const DataTableTable = withContext(DataTableTable$1, "table");
10077
10186
  ]
10078
10187
  });
10079
10188
  }
10080
- const DataTableHeader = withContext(DataTableHeader$1, "header");
10081
- const DataTableHeaderCell = withContext(DataTableHeaderCell$1, "headerCell");
10189
+ const DataTableHeader = withContext$1(DataTableHeader$1, "header");
10190
+ const DataTableHeaderCell = withContext$1(DataTableHeaderCell$1, "headerCell");
10082
10191
  // `.crisp-datatable-th-inner` -- the flex row INSIDE a `<th>` (label + filter trigger +
10083
10192
  // sort chevron + column menu). See qvism-preset's own `headerCellInner` slot comment
10084
10193
  // for why this lives one level below the cell itself rather than on it.
10085
- const DataTableHeaderCellInner = withContext(Primitive.div, "headerCellInner");
10194
+ const DataTableHeaderCellInner = withContext$1(Primitive.div, "headerCellInner");
10086
10195
  /** The label text specifically -- the one thing in `DataTableHeaderCellInner` that
10087
10196
  * truncates; the trailing filter/sort/menu icons stay fully visible regardless of how
10088
- * long a column's own header text is. */ const DataTableHeaderCellLabel = withContext(Primitive.span, "headerCellLabel");
10197
+ * long a column's own header text is. */ const DataTableHeaderCellLabel = withContext$1(Primitive.span, "headerCellLabel");
10089
10198
  /**
10090
10199
  * A selection `<th>`/`<td>`/footer `<td>` composes ITS base slot (`headerCell`/`cell`/
10091
10200
  * `footerCell`) together with the `selectionCell` MODIFIER, rather than replacing it --
@@ -10096,7 +10205,7 @@ const DataTableHeaderCellInner = withContext(Primitive.div, "headerCellInner");
10096
10205
  * a second recipe call.
10097
10206
  */ function withSelectionCell(Component, baseSlot) {
10098
10207
  const StyledComponent = /*#__PURE__*/ forwardRef((props, ref)=>{
10099
- const classNames = useClassNames();
10208
+ const classNames = useClassNames$1();
10100
10209
  return /*#__PURE__*/ jsx(Component, {
10101
10210
  ref: ref,
10102
10211
  ...props,
@@ -10107,12 +10216,12 @@ const DataTableHeaderCellInner = withContext(Primitive.div, "headerCellInner");
10107
10216
  return StyledComponent;
10108
10217
  }
10109
10218
  const DataTableSelectionHeaderCell = withSelectionCell(DataTableHeaderCell$1, "headerCell");
10110
- const DataTableHeaderCellIcon = withContext(Primitive.span, "headerCellIcon");
10219
+ const DataTableHeaderCellIcon = withContext$1(Primitive.span, "headerCellIcon");
10111
10220
  // body has no CSS slot of its own in the rootage spec -- it is a plain structural
10112
10221
  // `<tbody>`, so it is not wrapped in `withContext`.
10113
10222
  const DataTableBody = DataTableBody$1;
10114
- const DataTableRow = withContext(DataTableRow$1, "row");
10115
- const DataTableCell = withContext(DataTableCell$1, "cell");
10223
+ const DataTableRow = withContext$1(DataTableRow$1, "row");
10224
+ const DataTableCell = withContext$1(DataTableCell$1, "cell");
10116
10225
  const DataTableSelectionCell = withSelectionCell(DataTableCell$1, "cell");
10117
10226
  // Tranche 4 -- column menu + reorder + resize + sticky columns. A scroll boundary
10118
10227
  // wrapping the whole `<table>`: `overflowX: auto` is what makes a wide table (more
@@ -10122,7 +10231,7 @@ const DataTableSelectionCell = withSelectionCell(DataTableCell$1, "cell");
10122
10231
  // stays out of this slot's own base css (nothing here has a bounded height of its own
10123
10232
  // to clip), so it never introduces a second vertical scrollbar next to whatever
10124
10233
  // ambient container the whole DataTable already sits in.
10125
- const DataTableScrollBodyBase = withContext(Primitive.div, "scrollArea");
10234
+ const DataTableScrollBodyBase = withContext$1(Primitive.div, "scrollArea");
10126
10235
  function DataTableScrollBody({ children, scrollProps }) {
10127
10236
  const { scrollAreaRef, scrolledStart, scrolledEnd, onScroll } = useDataTableContext();
10128
10237
  const { className: scrollClassName, style: scrollStyle, ...otherScrollProps } = scrollProps ?? {};
@@ -10137,7 +10246,7 @@ function DataTableScrollBody({ children, scrollProps }) {
10137
10246
  children: children
10138
10247
  });
10139
10248
  }
10140
- const DataTableFooterBase = withContext(Primitive.tfoot, "footer");
10249
+ const DataTableFooterBase = withContext$1(Primitive.tfoot, "footer");
10141
10250
  function DataTableFooter({ children, ...props }) {
10142
10251
  return /*#__PURE__*/ jsx(DataTableFooterBase, {
10143
10252
  ...props,
@@ -10146,7 +10255,7 @@ function DataTableFooter({ children, ...props }) {
10146
10255
  })
10147
10256
  });
10148
10257
  }
10149
- const DataTableFooterCell = withContext(Primitive.td, "footerCell");
10258
+ const DataTableFooterCell = withContext$1(Primitive.td, "footerCell");
10150
10259
  ////////////////////////////////////////////////////////////////////////////////////
10151
10260
  // Fix (bug report): karrot icons default to a 24px intrinsic SVG attribute size
10152
10261
  // -- see column-menu.tsx's own `SORT_ICON_SIZE` comment for the full mechanism.