@bmsuisse/datagrid 0.35.3 → 0.37.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
@@ -204,12 +204,13 @@ import { forwardRef as forwardRef2 } from "react";
204
204
  import { jsx as jsx2 } from "react/jsx-runtime";
205
205
  var Popover = PopoverPrimitive.Root;
206
206
  var PopoverTrigger = PopoverPrimitive.Trigger;
207
- var PopoverContent = forwardRef2(({ className, align = "start", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx2(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx2(
207
+ var PopoverContent = forwardRef2(({ className, align = "start", sideOffset = 4, collisionPadding = 8, ...props }, ref) => /* @__PURE__ */ jsx2(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx2(
208
208
  PopoverPrimitive.Content,
209
209
  {
210
210
  ref,
211
211
  align,
212
212
  sideOffset,
213
+ collisionPadding,
213
214
  className: cn(
214
215
  "z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none",
215
216
  className
@@ -358,10 +359,91 @@ import { CalendarDaysIcon } from "@heroicons/react/24/outline";
358
359
  import { endOfDay, endOfMonth, format, parseISO as parseISO2, startOfDay, startOfMonth, subDays } from "date-fns";
359
360
 
360
361
  // src/components/ui/calendar.tsx
361
- import { DayPicker } from "react-day-picker";
362
+ import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon } from "lucide-react";
363
+ import { useEffect, useRef } from "react";
364
+ import { DayPicker, getDefaultClassNames } from "react-day-picker";
362
365
  import { jsx as jsx5 } from "react/jsx-runtime";
363
- function Calendar({ className, ...props }) {
364
- return /* @__PURE__ */ jsx5(DayPicker, { className: cn("p-3", className), ...props });
366
+ function Calendar({ className, classNames, ...props }) {
367
+ const defaultClassNames = getDefaultClassNames();
368
+ return /* @__PURE__ */ jsx5(
369
+ DayPicker,
370
+ {
371
+ className: cn("w-fit", className),
372
+ classNames: {
373
+ root: cn("relative", defaultClassNames.root),
374
+ months: cn(
375
+ "flex flex-col gap-4 sm:flex-row sm:divide-x sm:divide-border",
376
+ defaultClassNames.months
377
+ ),
378
+ month: cn("flex flex-col gap-3", defaultClassNames.month),
379
+ month_caption: cn("flex items-center justify-center px-8 h-8", defaultClassNames.month_caption),
380
+ caption_label: cn("text-sm font-medium", defaultClassNames.caption_label),
381
+ nav: cn("flex items-center justify-between absolute inset-x-0 top-0 px-1", defaultClassNames.nav),
382
+ button_previous: cn(
383
+ buttonVariants({ variant: "outline", size: "icon" }),
384
+ "h-7 w-7 shrink-0 text-muted-foreground hover:text-foreground",
385
+ defaultClassNames.button_previous
386
+ ),
387
+ button_next: cn(
388
+ buttonVariants({ variant: "outline", size: "icon" }),
389
+ "h-7 w-7 shrink-0 text-muted-foreground hover:text-foreground",
390
+ defaultClassNames.button_next
391
+ ),
392
+ month_grid: cn("w-full border-collapse", defaultClassNames.month_grid),
393
+ weekdays: cn("flex", defaultClassNames.weekdays),
394
+ weekday: cn(
395
+ "w-8 text-center text-[0.7rem] font-normal text-muted-foreground",
396
+ defaultClassNames.weekday
397
+ ),
398
+ week: cn("flex w-full mt-1", defaultClassNames.week),
399
+ day: cn(
400
+ "relative w-8 h-8 p-0 text-center text-sm focus-within:relative focus-within:z-20",
401
+ "[&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md",
402
+ defaultClassNames.day
403
+ ),
404
+ range_start: cn("rounded-l-md bg-accent", defaultClassNames.range_start),
405
+ range_middle: cn("rounded-none bg-accent/60", defaultClassNames.range_middle),
406
+ range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
407
+ today: cn(
408
+ "[&:not([data-selected])]:text-primary [&:not([data-selected])]:font-semibold",
409
+ defaultClassNames.today
410
+ ),
411
+ outside: cn("text-muted-foreground/50", defaultClassNames.outside),
412
+ disabled: cn("text-muted-foreground/30 line-through", defaultClassNames.disabled),
413
+ hidden: cn("invisible", defaultClassNames.hidden),
414
+ ...classNames
415
+ },
416
+ components: {
417
+ Chevron: ({ className: chevronClassName, orientation }) => {
418
+ const Icon2 = orientation === "up" ? ChevronUpIcon : orientation === "down" ? ChevronDownIcon : orientation === "right" ? ChevronRightIcon : ChevronLeftIcon;
419
+ return /* @__PURE__ */ jsx5(Icon2, { className: cn("h-4 w-4", chevronClassName), "aria-hidden": true });
420
+ },
421
+ DayButton: ({ className: dayClassName, day: _day, modifiers, ...dayProps }) => {
422
+ const ref = useRef(null);
423
+ useEffect(() => {
424
+ if (modifiers.focused) ref.current?.focus();
425
+ }, [modifiers.focused]);
426
+ return /* @__PURE__ */ jsx5(
427
+ "button",
428
+ {
429
+ ref,
430
+ type: "button",
431
+ className: cn(
432
+ "h-8 w-8 rounded-md text-sm font-normal transition-colors hover:bg-accent hover:text-accent-foreground",
433
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
434
+ "data-[selected=true]:bg-primary data-[selected=true]:text-primary-foreground data-[selected=true]:hover:bg-primary data-[selected=true]:hover:text-primary-foreground",
435
+ modifiers.range_middle && "data-[selected=true]:bg-transparent data-[selected=true]:text-foreground data-[selected=true]:hover:bg-accent",
436
+ dayClassName
437
+ ),
438
+ "data-selected": modifiers.selected || void 0,
439
+ ...dayProps
440
+ }
441
+ );
442
+ }
443
+ },
444
+ ...props
445
+ }
446
+ );
365
447
  }
366
448
 
367
449
  // src/filter/DateRangeFilter.tsx
@@ -436,7 +518,7 @@ function DateRangeFilter({
436
518
  )),
437
519
  /* @__PURE__ */ jsx6(Button, { type: "button", variant: "outline", size: "sm", onClick: () => emit(void 0), children: "Custom" })
438
520
  ] }),
439
- /* @__PURE__ */ jsx6(Calendar, { mode: "range", selected: range, onSelect: emit, numberOfMonths: 1 })
521
+ /* @__PURE__ */ jsx6(Calendar, { mode: "range", selected: range, onSelect: emit, numberOfMonths: 2 })
440
522
  ] });
441
523
  if (bare) {
442
524
  return /* @__PURE__ */ jsx6("div", { "data-testid": `filter-${column.id}`, children: panel });
@@ -515,6 +597,27 @@ function selectedValuesOf(value) {
515
597
  function toggle(selected, optionValue) {
516
598
  return selected.includes(optionValue) ? selected.filter((v) => v !== optionValue) : [...selected, optionValue];
517
599
  }
600
+ function buildRenderChunks(options) {
601
+ const chunks = [];
602
+ options.forEach((option, index) => {
603
+ const row = { option, index };
604
+ const last = chunks[chunks.length - 1];
605
+ if (option.group && last?.kind === "group" && last.group === option.group) {
606
+ last.rows.push(row);
607
+ } else if (option.group) {
608
+ chunks.push({ kind: "group", group: option.group, rows: [row] });
609
+ } else {
610
+ chunks.push({ kind: "single", row });
611
+ }
612
+ });
613
+ return chunks;
614
+ }
615
+ function groupCheckState(candidates, selected, group) {
616
+ const members = candidates.filter((o) => o.group === group).map((o) => o.value);
617
+ const selectedCount = members.filter((v) => selected.includes(v)).length;
618
+ if (members.length === 0 || selectedCount === 0) return "unchecked";
619
+ return selectedCount === members.length ? "checked" : "indeterminate";
620
+ }
518
621
  function EnumFilter({
519
622
  column,
520
623
  value,
@@ -528,6 +631,7 @@ function EnumFilter({
528
631
  if (!term) return column.options;
529
632
  return column.options.filter((option) => option.label.toLowerCase().includes(term));
530
633
  }, [column.options, search]);
634
+ const renderChunks = useMemo(() => buildRenderChunks(visibleOptions), [visibleOptions]);
531
635
  function emit(next) {
532
636
  onChange(next.length === 0 ? void 0 : { field: column.id, operator: "in", value: next });
533
637
  }
@@ -544,6 +648,33 @@ function EnumFilter({
544
648
  for (const v of visibleValues) next.add(v);
545
649
  emit([...next]);
546
650
  }
651
+ function toggleGroup(group) {
652
+ const members = visibleOptions.filter((o) => o.group === group).map((o) => o.value);
653
+ if (groupCheckState(visibleOptions, selected, group) === "checked") {
654
+ emit(selected.filter((v) => !members.includes(v)));
655
+ return;
656
+ }
657
+ emit([.../* @__PURE__ */ new Set([...selected, ...members])]);
658
+ }
659
+ function renderOption(option) {
660
+ return /* @__PURE__ */ jsxs4(
661
+ "label",
662
+ {
663
+ className: "flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground",
664
+ children: [
665
+ /* @__PURE__ */ jsx9(
666
+ Checkbox,
667
+ {
668
+ checked: selected.includes(option.value),
669
+ onCheckedChange: () => emit(toggle(selected, option.value))
670
+ }
671
+ ),
672
+ option.label
673
+ ]
674
+ },
675
+ option.value
676
+ );
677
+ }
547
678
  const isFiltered = selected.length > 0;
548
679
  const summary = `${selected.length} selected`;
549
680
  const panel = /* @__PURE__ */ jsxs4("div", { className: bare ? "flex w-full flex-col gap-2" : "flex w-64 flex-col gap-2 p-2", children: [
@@ -567,23 +698,37 @@ function EnumFilter({
567
698
  ),
568
699
  "Select all"
569
700
  ] }),
570
- /* @__PURE__ */ jsx9("div", { className: "flex max-h-60 flex-col gap-1 overflow-y-auto", children: visibleOptions.length === 0 ? /* @__PURE__ */ jsx9("p", { className: "py-2 text-center text-sm text-muted-foreground", children: "No matches." }) : visibleOptions.map((option) => /* @__PURE__ */ jsxs4(
571
- "label",
572
- {
573
- className: "flex items-center gap-2 rounded-sm px-1 py-1 text-sm hover:bg-accent hover:text-accent-foreground",
574
- children: [
575
- /* @__PURE__ */ jsx9(
576
- Checkbox,
701
+ /* @__PURE__ */ jsx9("div", { className: "flex max-h-60 flex-col gap-0.5 overflow-y-auto", children: renderChunks.length === 0 ? /* @__PURE__ */ jsx9("p", { className: "py-2 text-center text-sm text-muted-foreground", children: "No matches." }) : renderChunks.map((chunk) => {
702
+ if (chunk.kind === "single") return renderOption(chunk.row.option);
703
+ const headerState = groupCheckState(visibleOptions, selected, chunk.group);
704
+ return (
705
+ // The header and every one of its group's rows share this wrapper --
706
+ // its bounds are the sticky header's containing block, so `sticky
707
+ // top-0` keeps the header pinned for the group's whole scroll extent
708
+ // instead of just past its first row.
709
+ /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-0.5", children: [
710
+ /* @__PURE__ */ jsxs4(
711
+ "label",
577
712
  {
578
- checked: selected.includes(option.value),
579
- onCheckedChange: () => emit(toggle(selected, option.value))
713
+ "data-group-header": true,
714
+ className: "sticky top-0 z-10 flex items-center gap-2 rounded-sm bg-muted px-2 py-1.5 text-sm font-semibold text-foreground",
715
+ children: [
716
+ /* @__PURE__ */ jsx9(
717
+ Checkbox,
718
+ {
719
+ checked: headerState === "indeterminate" ? "indeterminate" : headerState === "checked",
720
+ onCheckedChange: () => toggleGroup(chunk.group),
721
+ "aria-label": `Select all of ${chunk.group}`
722
+ }
723
+ ),
724
+ chunk.group
725
+ ]
580
726
  }
581
727
  ),
582
- option.label
583
- ]
584
- },
585
- option.value
586
- )) })
728
+ chunk.rows.map((row) => renderOption(row.option))
729
+ ] }, `group-${chunk.group}`)
730
+ );
731
+ }) })
587
732
  ] });
588
733
  if (bare) {
589
734
  return /* @__PURE__ */ jsx9("div", { "data-testid": `filter-${column.id}`, children: panel });
@@ -615,7 +760,7 @@ function EnumFilter({
615
760
 
616
761
  // src/filter/NumberComparisonFilter.tsx
617
762
  import { FunnelIcon as FunnelIcon3 } from "@heroicons/react/24/outline";
618
- import { useEffect, useId, useRef, useState as useState2 } from "react";
763
+ import { useEffect as useEffect2, useId, useRef as useRef2, useState as useState2 } from "react";
619
764
 
620
765
  // src/column/format.ts
621
766
  import { parseISO as parseISO3 } from "date-fns";
@@ -802,8 +947,8 @@ function NumberComparisonFilter({
802
947
  const [text2, setText2] = useState2(initial.text2);
803
948
  const operatorId = useId();
804
949
  const valueId = useId();
805
- const lastEmittedRef = useRef(value);
806
- useEffect(() => {
950
+ const lastEmittedRef = useRef2(value);
951
+ useEffect2(() => {
807
952
  if (value === lastEmittedRef.current) return;
808
953
  lastEmittedRef.current = value;
809
954
  const next = stateFromValue(value);
@@ -919,7 +1064,7 @@ function NumberComparisonFilter({
919
1064
 
920
1065
  // src/filter/NumberRangeFilter.tsx
921
1066
  import { FunnelIcon as FunnelIcon4 } from "@heroicons/react/24/outline";
922
- import { useEffect as useEffect2, useId as useId2, useRef as useRef2, useState as useState3 } from "react";
1067
+ import { useEffect as useEffect3, useId as useId2, useRef as useRef3, useState as useState3 } from "react";
923
1068
  import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
924
1069
  function parseNumber2(raw) {
925
1070
  if (raw.trim() === "") return void 0;
@@ -937,8 +1082,8 @@ function NumberRangeFilter({
937
1082
  const [maxText, setMaxText] = useState3(initial.max?.toString() ?? "");
938
1083
  const minId = useId2();
939
1084
  const maxId = useId2();
940
- const lastEmittedRef = useRef2(value);
941
- useEffect2(() => {
1085
+ const lastEmittedRef = useRef3(value);
1086
+ useEffect3(() => {
942
1087
  if (value === lastEmittedRef.current) return;
943
1088
  lastEmittedRef.current = value;
944
1089
  const next = rangeOf2(value);
@@ -1019,7 +1164,7 @@ function NumberRangeFilter({
1019
1164
 
1020
1165
  // src/filter/NumberHistogramFilter.tsx
1021
1166
  import { FunnelIcon as FunnelIcon5 } from "@heroicons/react/24/outline";
1022
- import { useCallback, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef3, useState as useState4 } from "react";
1167
+ import { useCallback, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
1023
1168
  import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
1024
1169
  var BAR_HEIGHT_PX = 56;
1025
1170
  var DEFAULT_BUCKETS = 24;
@@ -1041,12 +1186,12 @@ function NumberHistogramFilter({
1041
1186
  }) {
1042
1187
  const [openState, setOpen] = useState4(false);
1043
1188
  const open = bare || openState;
1044
- const trackRef = useRef3(null);
1189
+ const trackRef = useRef4(null);
1045
1190
  const [minOnTop, setMinOnTop] = useState4(false);
1046
1191
  const [loadedValues, setLoadedValues] = useState4([]);
1047
1192
  const [loading, setLoading] = useState4(false);
1048
1193
  const { min, max } = rangeOf2(value);
1049
- useEffect3(() => {
1194
+ useEffect4(() => {
1050
1195
  if (!open || !loadValues) return;
1051
1196
  let cancelled = false;
1052
1197
  setLoading(true);
@@ -1070,7 +1215,7 @@ function NumberHistogramFilter({
1070
1215
  const activeMax = max ?? dataMax;
1071
1216
  const [minText, setMinText] = useState4("");
1072
1217
  const [maxText, setMaxText] = useState4("");
1073
- useEffect3(() => {
1218
+ useEffect4(() => {
1074
1219
  if (!open) return;
1075
1220
  setMinText(Number.isFinite(activeMin) ? String(Math.round(activeMin)) : "");
1076
1221
  setMaxText(Number.isFinite(activeMax) ? String(Math.round(activeMax)) : "");
@@ -1283,7 +1428,7 @@ function facetedNumberValues(data, column, filter) {
1283
1428
 
1284
1429
  // src/filter/StringFilter.tsx
1285
1430
  import { FunnelIcon as FunnelIcon6 } from "@heroicons/react/24/outline";
1286
- import { useEffect as useEffect4, useId as useId3, useState as useState5 } from "react";
1431
+ import { useEffect as useEffect5, useId as useId3, useState as useState5 } from "react";
1287
1432
  import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
1288
1433
  var STRING_OPERATORS = [
1289
1434
  { value: "contains", label: "Contains" },
@@ -1302,7 +1447,7 @@ function StringFilter({
1302
1447
  const text = typeof value?.value === "string" ? value.value : "";
1303
1448
  const inputId = useId3();
1304
1449
  const isFiltered = text !== "";
1305
- useEffect4(() => {
1450
+ useEffect5(() => {
1306
1451
  setOperator(value?.operator ?? DEFAULT_OPERATOR2);
1307
1452
  }, [value?.operator]);
1308
1453
  function emit(nextOperator, nextText) {
@@ -1517,7 +1662,7 @@ function EnumEditor({
1517
1662
  }
1518
1663
 
1519
1664
  // src/edit/MultilineStringEditor.tsx
1520
- import { useLayoutEffect, useRef as useRef4 } from "react";
1665
+ import { useLayoutEffect, useRef as useRef5 } from "react";
1521
1666
 
1522
1667
  // src/components/ui/textarea.tsx
1523
1668
  import { forwardRef as forwardRef6 } from "react";
@@ -1548,8 +1693,8 @@ function MultilineStringEditor({
1548
1693
  autoFocus
1549
1694
  }) {
1550
1695
  const errorId = editErrorId(rowId, column.id);
1551
- const textareaRef = useRef4(null);
1552
- const selectionRef = useRef4(null);
1696
+ const textareaRef = useRef5(null);
1697
+ const selectionRef = useRef5(null);
1553
1698
  const text = value === null || value === void 0 ? "" : String(value);
1554
1699
  useLayoutEffect(() => {
1555
1700
  const el = textareaRef.current;
@@ -1584,7 +1729,7 @@ function MultilineStringEditor({
1584
1729
  }
1585
1730
 
1586
1731
  // src/edit/NumberEditor.tsx
1587
- import { useEffect as useEffect5, useRef as useRef5, useState as useState6 } from "react";
1732
+ import { useEffect as useEffect6, useRef as useRef6, useState as useState6 } from "react";
1588
1733
  import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
1589
1734
  function textFromValue(value) {
1590
1735
  return value === null || value === void 0 ? "" : String(value);
@@ -1599,8 +1744,8 @@ function NumberEditor({
1599
1744
  }) {
1600
1745
  const errorId = editErrorId(rowId, column.id);
1601
1746
  const [text, setText] = useState6(() => textFromValue(value));
1602
- const lastEmittedRef = useRef5(value);
1603
- useEffect5(() => {
1747
+ const lastEmittedRef = useRef6(value);
1748
+ useEffect6(() => {
1604
1749
  if (value === lastEmittedRef.current) return;
1605
1750
  lastEmittedRef.current = value;
1606
1751
  setText(textFromValue(value));
@@ -1678,7 +1823,7 @@ function renderDefaultEditWidget(column, rowId, value, onChange, error, autoFocu
1678
1823
  }
1679
1824
 
1680
1825
  // src/edit/editingState.ts
1681
- import { useEffect as useEffect6, useRef as useRef6, useState as useState7 } from "react";
1826
+ import { useEffect as useEffect7, useRef as useRef7, useState as useState7 } from "react";
1682
1827
  function editValuesEqual(a, b) {
1683
1828
  if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
1684
1829
  return a === b;
@@ -1693,7 +1838,7 @@ function useEditingState(editing, getRowId) {
1693
1838
  setActiveRowId(rowId);
1694
1839
  setAutoFocusTarget({ rowId, columnId });
1695
1840
  }
1696
- useEffect6(() => {
1841
+ useEffect7(() => {
1697
1842
  if (autoFocusTarget) setAutoFocusTarget(null);
1698
1843
  }, [autoFocusTarget]);
1699
1844
  function commitEdit(column, row, value) {
@@ -1780,7 +1925,7 @@ function useEditingState(editing, getRowId) {
1780
1925
  editing?.onDiscard?.();
1781
1926
  }
1782
1927
  const ctx = editing ? { pendingEdits, editErrors, activeRowId, autoFocusTarget, getRowId, onEdit: commitEdit, onActivateRow: activateRow } : void 0;
1783
- const ctxRef = useRef6(void 0);
1928
+ const ctxRef = useRef7(void 0);
1784
1929
  ctxRef.current = ctx;
1785
1930
  return { pendingEdits, editErrors, hasEditErrors, ctx, ctxRef, handleSaveEdits, handleDiscardEdits };
1786
1931
  }
@@ -1986,13 +2131,13 @@ function extendRangeForFillToCellRange(base, target, rowIds, columnIds, rowIndex
1986
2131
  }
1987
2132
 
1988
2133
  // src/cell-editing/useCellSelection.ts
1989
- import { useCallback as useCallback2, useMemo as useMemo3, useRef as useRef7, useState as useState8 } from "react";
2134
+ import { useCallback as useCallback2, useMemo as useMemo3, useRef as useRef8, useState as useState8 } from "react";
1990
2135
  function useCellSelection({ rowIds, columnIds, onNavigateToRow }) {
1991
2136
  const [selection, setSelectionState] = useState8(void 0);
1992
2137
  const [isDragging, setIsDragging] = useState8(false);
1993
2138
  const [dragFocus, setDragFocus] = useState8(void 0);
1994
- const draggingRef = useRef7(false);
1995
- const dragFocusRef = useRef7(void 0);
2139
+ const draggingRef = useRef8(false);
2140
+ const dragFocusRef = useRef8(void 0);
1996
2141
  const rowIndex = useMemo3(() => buildIndexMap(rowIds), [rowIds]);
1997
2142
  const columnIndex = useMemo3(() => buildIndexMap(columnIds), [columnIds]);
1998
2143
  const startSelection = useCallback2((cell, options) => {
@@ -2055,9 +2200,9 @@ function useCellSelection({ rowIds, columnIds, onNavigateToRow }) {
2055
2200
  }, [selection, isDragging, dragFocus]);
2056
2201
  const [isFillDragging, setIsFillDragging] = useState8(false);
2057
2202
  const [fillTarget, setFillTarget] = useState8(void 0);
2058
- const fillDraggingRef = useRef7(false);
2059
- const fillTargetRef = useRef7(void 0);
2060
- const fillBaseRef = useRef7(void 0);
2203
+ const fillDraggingRef = useRef8(false);
2204
+ const fillTargetRef = useRef8(void 0);
2205
+ const fillBaseRef = useRef8(void 0);
2061
2206
  const startFillDrag = useCallback2(() => {
2062
2207
  if (!selection) return;
2063
2208
  fillBaseRef.current = selection;
@@ -2107,7 +2252,7 @@ function useCellSelection({ rowIds, columnIds, onNavigateToRow }) {
2107
2252
  }
2108
2253
 
2109
2254
  // src/cell-editing/useCellEditingState.ts
2110
- import { useRef as useRef8, useState as useState9 } from "react";
2255
+ import { useRef as useRef9, useState as useState9 } from "react";
2111
2256
  function cellKey(rowId, columnId) {
2112
2257
  return `${rowId}:${columnId}`;
2113
2258
  }
@@ -2118,7 +2263,7 @@ function useCellEditingState(cellEditing, getRowId) {
2118
2263
  const [draftValue, setDraftValue] = useState9(void 0);
2119
2264
  const [overrides, setOverrides] = useState9(/* @__PURE__ */ new Map());
2120
2265
  const [errors, setErrors] = useState9(/* @__PURE__ */ new Map());
2121
- const justCommittedRef = useRef8(false);
2266
+ const justCommittedRef = useRef9(false);
2122
2267
  function closeEditor() {
2123
2268
  setEditingCell(void 0);
2124
2269
  setInitialText(void 0);
@@ -2216,7 +2361,7 @@ function useCellEditingState(cellEditing, getRowId) {
2216
2361
  applyChange: (change) => applyChanges([change]),
2217
2362
  consumeJustCommitted
2218
2363
  } : void 0;
2219
- const ctxRef = useRef8(void 0);
2364
+ const ctxRef = useRef9(void 0);
2220
2365
  ctxRef.current = ctx;
2221
2366
  return { ctx, ctxRef, applyChanges };
2222
2367
  }
@@ -2277,7 +2422,7 @@ function renderCellModeCell(column, row, rawValue, ctx) {
2277
2422
  }
2278
2423
 
2279
2424
  // src/cell-editing/SelectionOverlay.tsx
2280
- import { useLayoutEffect as useLayoutEffect2, useRef as useRef9, useState as useState10 } from "react";
2425
+ import { useLayoutEffect as useLayoutEffect2, useRef as useRef10, useState as useState10 } from "react";
2281
2426
  import { Fragment as Fragment2, jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
2282
2427
  function cellSelector(rowId, columnId) {
2283
2428
  const escape = (value) => typeof CSS !== "undefined" && CSS.escape ? CSS.escape(value) : value.replace(/["\\]/g, "\\$&");
@@ -2310,7 +2455,7 @@ function SelectionOverlay({
2310
2455
  }) {
2311
2456
  const [rect, setRect] = useState10(void 0);
2312
2457
  const [previewRect, setPreviewRect] = useState10(void 0);
2313
- const recomputeRef = useRef9(() => {
2458
+ const recomputeRef = useRef10(() => {
2314
2459
  });
2315
2460
  recomputeRef.current = () => {
2316
2461
  const container = containerRef.current;
@@ -2557,7 +2702,7 @@ function computeFillChanges(sourceRange, finalRange, rowIds, columnIds, columns,
2557
2702
 
2558
2703
  // src/column-selector/ColumnSelector.tsx
2559
2704
  import { Columns3, GripVertical } from "lucide-react";
2560
- import { useEffect as useEffect7, useState as useState11 } from "react";
2705
+ import { useEffect as useEffect8, useState as useState11 } from "react";
2561
2706
 
2562
2707
  // src/components/ui/dialog.tsx
2563
2708
  import * as DialogPrimitive from "@radix-ui/react-dialog";
@@ -2724,12 +2869,12 @@ function ColumnSelector({
2724
2869
  columnOrder,
2725
2870
  onColumnOrderChange
2726
2871
  }) {
2727
- useEffect7(() => {
2872
+ useEffect8(() => {
2728
2873
  if (!persistKey) return;
2729
2874
  const restored = readPersistedVisibility(persistKey);
2730
2875
  if (restored) onVisibilityChange({ ...visibility, ...restored });
2731
2876
  }, [persistKey]);
2732
- useEffect7(() => {
2877
+ useEffect8(() => {
2733
2878
  if (!persistKey || !onColumnOrderChange) return;
2734
2879
  const restored = readPersistedColumnOrder(persistKey);
2735
2880
  if (restored) onColumnOrderChange(restored);
@@ -2912,11 +3057,11 @@ import { BarsArrowDownIcon, BarsArrowUpIcon, FunnelIcon as FunnelIcon7 } from "@
2912
3057
  import { columnResizingFeature, columnSizingFeature, flexRender, tableFeatures, useTable } from "@tanstack/react-table";
2913
3058
  import { useVirtualizer } from "@tanstack/react-virtual";
2914
3059
  import { ChevronRight, Loader2 } from "lucide-react";
2915
- import { Fragment as Fragment3, useEffect as useEffect11, useMemo as useMemo8, useRef as useRef12, useState as useState16 } from "react";
3060
+ import { Fragment as Fragment3, useEffect as useEffect12, useMemo as useMemo8, useRef as useRef13, useState as useState16 } from "react";
2916
3061
 
2917
3062
  // src/cell-editing/renderAlwaysEditCell.tsx
2918
3063
  import {
2919
- useEffect as useEffect8,
3064
+ useEffect as useEffect9,
2920
3065
  useState as useState12
2921
3066
  } from "react";
2922
3067
  import { jsx as jsx32 } from "react/jsx-runtime";
@@ -2928,7 +3073,7 @@ function AlwaysEditCell(props) {
2928
3073
  const [enumOpen, setEnumOpen] = useState12(false);
2929
3074
  const isBuiltinEnum = column.type === "enum" && !column.renderEditCell;
2930
3075
  const shouldOpenEnumNow = isBuiltinEnum && (atomicGesture?.shouldOpenEnum(rowId, column.id) ?? false);
2931
- useEffect8(() => {
3076
+ useEffect9(() => {
2932
3077
  if (shouldOpenEnumNow) setEnumOpen(true);
2933
3078
  }, [shouldOpenEnumNow]);
2934
3079
  if (!isEditable(column, row)) {
@@ -3051,9 +3196,9 @@ function useGroupExpansion(defaultGroupsExpanded, controlledExpandedGroups, onEx
3051
3196
  }
3052
3197
 
3053
3198
  // src/hooks/useStickyGroupHeaderTop.ts
3054
- import { useLayoutEffect as useLayoutEffect3, useRef as useRef10, useState as useState14 } from "react";
3199
+ import { useLayoutEffect as useLayoutEffect3, useRef as useRef11, useState as useState14 } from "react";
3055
3200
  function useStickyGroupHeaderTop(enabled) {
3056
- const theadRef = useRef10(null);
3201
+ const theadRef = useRef11(null);
3057
3202
  const [groupHeaderTop, setGroupHeaderTop] = useState14(0);
3058
3203
  useLayoutEffect3(() => {
3059
3204
  if (!enabled) return;
@@ -3118,15 +3263,15 @@ function processClientData(data, state) {
3118
3263
  }
3119
3264
 
3120
3265
  // src/grid/useGridState.ts
3121
- import { useCallback as useCallback4, useEffect as useEffect10, useMemo as useMemo7, useState as useState15 } from "react";
3266
+ import { useCallback as useCallback4, useEffect as useEffect11, useMemo as useMemo7, useState as useState15 } from "react";
3122
3267
 
3123
3268
  // src/hooks/useDebouncedCallback.ts
3124
- import { useEffect as useEffect9, useMemo as useMemo6, useRef as useRef11 } from "react";
3269
+ import { useEffect as useEffect10, useMemo as useMemo6, useRef as useRef12 } from "react";
3125
3270
  function useDebouncedCallback(callback, delayMs) {
3126
- const callbackRef = useRef11(callback);
3271
+ const callbackRef = useRef12(callback);
3127
3272
  callbackRef.current = callback;
3128
- const timeoutRef = useRef11(void 0);
3129
- useEffect9(() => {
3273
+ const timeoutRef = useRef12(void 0);
3274
+ useEffect10(() => {
3130
3275
  return () => {
3131
3276
  clearTimeout(timeoutRef.current);
3132
3277
  };
@@ -3179,7 +3324,7 @@ function useGridState(dataSource, initialState, externalState, showPagination =
3179
3324
  },
3180
3325
  [notifyRaw, cancelDebouncedNotify]
3181
3326
  );
3182
- useEffect10(() => {
3327
+ useEffect11(() => {
3183
3328
  if (!externalState) return;
3184
3329
  cancelDebouncedNotify();
3185
3330
  setState(externalState);
@@ -3388,7 +3533,7 @@ function DataGrid({
3388
3533
  hasCellEditing ? cellEditing : void 0,
3389
3534
  getRowId
3390
3535
  );
3391
- const atomicGestureRef = useRef12(void 0);
3536
+ const atomicGestureRef = useRef13(void 0);
3392
3537
  const visibleColumns = useVisibleColumns(columns, columnVisibility);
3393
3538
  const serverRowCount = dataSource.mode === "server" ? dataSource.rowCount : void 0;
3394
3539
  const { rows, rowCount } = useMemo8(() => {
@@ -3543,8 +3688,8 @@ function DataGrid({
3543
3688
  return map;
3544
3689
  }, [visibleColumns, enableColumnResizing, leftPinnedOffsets, rightPinnedOffsets, columnSizing]);
3545
3690
  const tableRows = table.getRowModel().rows;
3546
- const truncationWarnedRef = useRef12(false);
3547
- useEffect11(() => {
3691
+ const truncationWarnedRef = useRef13(false);
3692
+ useEffect12(() => {
3548
3693
  if (process.env.NODE_ENV === "production") return;
3549
3694
  if (showPagination) return;
3550
3695
  if (truncationWarnedRef.current) return;
@@ -3574,7 +3719,7 @@ function DataGrid({
3574
3719
  }
3575
3720
  return items;
3576
3721
  }, [shouldVirtualize, groupedBuckets, tableRows, isGroupExpanded]);
3577
- const scrollRef = useRef12(null);
3722
+ const scrollRef = useRef13(null);
3578
3723
  const virtualizer = useVirtualizer({
3579
3724
  count: flatItems.length,
3580
3725
  getScrollElement: () => scrollRef.current,
@@ -3586,11 +3731,11 @@ function DataGrid({
3586
3731
  const paddingTop = virtualItems.length > 0 ? virtualItems[0].start : 0;
3587
3732
  const paddingBottom = virtualItems.length > 0 ? virtualizer.getTotalSize() - virtualItems[virtualItems.length - 1].end : 0;
3588
3733
  const lastVisibleIndex = virtualItems.length > 0 ? virtualItems[virtualItems.length - 1].index : -1;
3589
- const notifiedForLengthRef = useRef12(-1);
3590
- useEffect11(() => {
3734
+ const notifiedForLengthRef = useRef13(-1);
3735
+ useEffect12(() => {
3591
3736
  notifiedForLengthRef.current = -1;
3592
3737
  }, [state.filter, state.sort]);
3593
- useEffect11(() => {
3738
+ useEffect12(() => {
3594
3739
  if (!virtualize?.onEndReached) return;
3595
3740
  if (lastVisibleIndex < 0 || lastVisibleIndex < flatItems.length - 1) return;
3596
3741
  if (virtualize.hasMore === false) return;
@@ -3616,8 +3761,8 @@ function DataGrid({
3616
3761
  if (index !== void 0) virtualizer.scrollToIndex(index);
3617
3762
  }
3618
3763
  });
3619
- const clickCellRef = useRef12(null);
3620
- const dragMovedRef = useRef12(false);
3764
+ const clickCellRef = useRef13(null);
3765
+ const dragMovedRef = useRef13(false);
3621
3766
  const [pendingOpenEnumCell, setPendingOpenEnumCell] = useState16(void 0);
3622
3767
  atomicGestureRef.current = {
3623
3768
  shouldOpenEnum: (rowId, columnId) => pendingOpenEnumCell?.rowId === rowId && pendingOpenEnumCell?.columnId === columnId,
@@ -3641,9 +3786,9 @@ function DataGrid({
3641
3786
  if (!column || row === void 0 || !isEditable(column, row)) return;
3642
3787
  cellEditingCtx.onBeginEdit(cell);
3643
3788
  }
3644
- const pendingDragCellRef = useRef12(null);
3645
- const dragRafRef = useRef12(null);
3646
- useEffect11(() => {
3789
+ const pendingDragCellRef = useRef13(null);
3790
+ const dragRafRef = useRef13(null);
3791
+ useEffect12(() => {
3647
3792
  if (!cellSelection.isDragging) return;
3648
3793
  function handleMouseMove(event) {
3649
3794
  const cellEl = event.target?.closest("[data-cell-row]");
@@ -3682,9 +3827,9 @@ function DataGrid({
3682
3827
  dragRafRef.current = null;
3683
3828
  };
3684
3829
  }, [cellSelection.isDragging, cellSelection.updateDrag, cellSelection.endDrag]);
3685
- const pendingFillCellRef = useRef12(null);
3686
- const fillRafRef = useRef12(null);
3687
- useEffect11(() => {
3830
+ const pendingFillCellRef = useRef13(null);
3831
+ const fillRafRef = useRef13(null);
3832
+ useEffect12(() => {
3688
3833
  if (!cellSelection.isFillDragging) return;
3689
3834
  function handleMouseMove(event) {
3690
3835
  const cellEl = event.target?.closest("[data-cell-row]");
@@ -3720,8 +3865,8 @@ function DataGrid({
3720
3865
  fillRafRef.current = null;
3721
3866
  };
3722
3867
  }, [cellSelection.isFillDragging, cellSelection.updateFillDrag, cellSelection.endFillDrag]);
3723
- const wasEditingCellRef = useRef12(void 0);
3724
- useEffect11(() => {
3868
+ const wasEditingCellRef = useRef13(void 0);
3869
+ useEffect12(() => {
3725
3870
  const wasEditing = wasEditingCellRef.current !== void 0;
3726
3871
  wasEditingCellRef.current = cellEditingCtx?.editingCell;
3727
3872
  if (!wasEditing || cellEditingCtx?.editingCell) return;
@@ -4144,7 +4289,7 @@ function DataGrid({
4144
4289
  )
4145
4290
  }
4146
4291
  ) }),
4147
- /* @__PURE__ */ jsx33(PopoverContent, { children: renderFilterWidget(column) })
4292
+ /* @__PURE__ */ jsx33(PopoverContent, { className: "w-auto", children: renderFilterWidget(column) })
4148
4293
  ] })
4149
4294
  ] }),
4150
4295
  enableColumnResizing && /* @__PURE__ */ jsx33(
@@ -4352,7 +4497,7 @@ function DataGrid({
4352
4497
  // src/tree/TreeDataGrid.tsx
4353
4498
  import { useVirtualizer as useVirtualizer2 } from "@tanstack/react-virtual";
4354
4499
  import { AlertCircle, ChevronDown as ChevronDown2, ChevronRight as ChevronRight2, Loader2 as Loader22 } from "lucide-react";
4355
- import { Fragment as Fragment5, useEffect as useEffect12, useMemo as useMemo10, useRef as useRef13 } from "react";
4500
+ import { Fragment as Fragment5, useEffect as useEffect13, useMemo as useMemo10, useRef as useRef14 } from "react";
4356
4501
 
4357
4502
  // src/tree/flattenTree.ts
4358
4503
  function flattenTree(roots, accessors, expanded, childrenOverride) {
@@ -4606,8 +4751,8 @@ function TreeDataGrid({
4606
4751
  childrenMap: controlledChildrenMap,
4607
4752
  onChildrenMapChange
4608
4753
  });
4609
- const didAutoExpand = useRef13(false);
4610
- useEffect12(() => {
4754
+ const didAutoExpand = useRef14(false);
4755
+ useEffect13(() => {
4611
4756
  if (didAutoExpand.current) return;
4612
4757
  didAutoExpand.current = true;
4613
4758
  if (initialExpandedLevel > 0) void expandToLevel(initialExpandedLevel);
@@ -4686,7 +4831,7 @@ function TreeDataGrid({
4686
4831
  function renderGroupSummaryCells(rows) {
4687
4832
  return visibleColumns.map((column) => /* @__PURE__ */ jsx34("td", { className: cn(bodyTdClassByColumn.get(column.id), "font-medium"), children: column.summary?.(rows) }, column.id));
4688
4833
  }
4689
- const scrollRef = useRef13(null);
4834
+ const scrollRef = useRef14(null);
4690
4835
  const shouldVirtualize = !groupBy && flatRows.length > virtualizeThreshold;
4691
4836
  const virtualizer = useVirtualizer2({
4692
4837
  count: flatRows.length,