@bmsuisse/datagrid 0.37.0 → 0.38.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
@@ -147,6 +147,70 @@ function evaluateFilter(row, filter) {
147
147
  return evaluateLeaf(row, filter);
148
148
  }
149
149
 
150
+ // src/filter/labels.tsx
151
+ import { createContext, useContext, useMemo } from "react";
152
+ import { jsx } from "react/jsx-runtime";
153
+ var defaultFilterLabels = {
154
+ filterAriaLabel: (header) => `Filter ${header}`,
155
+ searchPlaceholder: (header) => `Search ${header.toLowerCase()}...`,
156
+ selectAll: "Select all",
157
+ selectAllOfGroup: (group) => `Select all of ${group}`,
158
+ noMatches: "No matches.",
159
+ selectedCount: (count) => `${count} selected`,
160
+ stringPlaceholder: (header) => `Filter ${header.toLowerCase()}...`,
161
+ stringContains: "Contains",
162
+ stringIs: "Is",
163
+ stringStartsWith: "Starts with",
164
+ stringEndsWith: "Ends with",
165
+ operatorAriaLabel: (header) => `${header} filter operator`,
166
+ booleanAll: "All",
167
+ booleanYes: "Yes",
168
+ booleanNo: "No",
169
+ booleanAriaLabel: (header) => `${header} filter`,
170
+ minPlaceholder: "Min",
171
+ maxPlaceholder: "Max",
172
+ valuePlaceholder: "Value",
173
+ rangeSeparator: "to",
174
+ minimumAriaLabel: (header) => `${header} minimum`,
175
+ maximumAriaLabel: (header) => `${header} maximum`,
176
+ minimumSliderAriaLabel: (header) => `${header} minimum (slider)`,
177
+ maximumSliderAriaLabel: (header) => `${header} maximum (slider)`,
178
+ numberGreaterThan: "Greater than",
179
+ numberGreaterThanOrEqual: "Greater than or equal to",
180
+ numberLessThan: "Less than",
181
+ numberLessThanOrEqual: "Less than or equal to",
182
+ numberEquals: "Equals",
183
+ numberNotEquals: "Does not equal",
184
+ numberBetween: "Between",
185
+ clear: "Clear",
186
+ loading: "Loading\u2026",
187
+ dateToday: "Today",
188
+ dateLast7Days: "Last 7 days",
189
+ dateThisMonth: "This month",
190
+ dateCustom: "Custom"
191
+ };
192
+ function mergeFilterLabels(base, overrides) {
193
+ if (!overrides) return base;
194
+ const merged = { ...base };
195
+ for (const [key, value] of Object.entries(overrides)) {
196
+ if (value !== void 0) merged[key] = value;
197
+ }
198
+ return merged;
199
+ }
200
+ var FilterLabelsContext = createContext(defaultFilterLabels);
201
+ function FilterLabelsProvider({
202
+ labels,
203
+ children
204
+ }) {
205
+ const parent = useContext(FilterLabelsContext);
206
+ const value = useMemo(() => mergeFilterLabels(parent, labels), [parent, labels]);
207
+ return /* @__PURE__ */ jsx(FilterLabelsContext.Provider, { value, children });
208
+ }
209
+ function useFilterLabels(overrides) {
210
+ const fromContext = useContext(FilterLabelsContext);
211
+ return useMemo(() => mergeFilterLabels(fromContext, overrides), [fromContext, overrides]);
212
+ }
213
+
150
214
  // src/filter/BooleanFilter.tsx
151
215
  import { FunnelIcon } from "@heroicons/react/24/outline";
152
216
 
@@ -166,7 +230,7 @@ function stopRowClick(event) {
166
230
  }
167
231
 
168
232
  // src/components/ui/button.tsx
169
- import { jsx } from "react/jsx-runtime";
233
+ import { jsx as jsx2 } from "react/jsx-runtime";
170
234
  var buttonVariants = cva(
171
235
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
172
236
  {
@@ -193,7 +257,7 @@ var Button = forwardRef(
193
257
  ({ className, variant, size, asChild = false, ...props }, ref) => {
194
258
  const Comp = asChild ? Slot : "button";
195
259
  const variantClass = buttonVariants({ variant, size });
196
- return /* @__PURE__ */ jsx(Comp, { className: className ? cn(variantClass, className) : variantClass, ref, ...props });
260
+ return /* @__PURE__ */ jsx2(Comp, { className: className ? cn(variantClass, className) : variantClass, ref, ...props });
197
261
  }
198
262
  );
199
263
  Button.displayName = "Button";
@@ -201,10 +265,10 @@ Button.displayName = "Button";
201
265
  // src/components/ui/popover.tsx
202
266
  import * as PopoverPrimitive from "@radix-ui/react-popover";
203
267
  import { forwardRef as forwardRef2 } from "react";
204
- import { jsx as jsx2 } from "react/jsx-runtime";
268
+ import { jsx as jsx3 } from "react/jsx-runtime";
205
269
  var Popover = PopoverPrimitive.Root;
206
270
  var PopoverTrigger = PopoverPrimitive.Trigger;
207
- var PopoverContent = forwardRef2(({ className, align = "start", sideOffset = 4, collisionPadding = 8, ...props }, ref) => /* @__PURE__ */ jsx2(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx2(
271
+ var PopoverContent = forwardRef2(({ className, align = "start", sideOffset = 4, collisionPadding = 8, ...props }, ref) => /* @__PURE__ */ jsx3(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx3(
208
272
  PopoverPrimitive.Content,
209
273
  {
210
274
  ref,
@@ -224,7 +288,7 @@ PopoverContent.displayName = "PopoverContent";
224
288
  import * as SelectPrimitive from "@radix-ui/react-select";
225
289
  import { Check, ChevronDown } from "lucide-react";
226
290
  import { forwardRef as forwardRef3 } from "react";
227
- import { jsx as jsx3, jsxs } from "react/jsx-runtime";
291
+ import { jsx as jsx4, jsxs } from "react/jsx-runtime";
228
292
  var Select = SelectPrimitive.Root;
229
293
  var SelectValue = SelectPrimitive.Value;
230
294
  var SelectTrigger = forwardRef3(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
@@ -238,12 +302,12 @@ var SelectTrigger = forwardRef3(({ className, children, ...props }, ref) => /* @
238
302
  ...props,
239
303
  children: [
240
304
  children,
241
- /* @__PURE__ */ jsx3(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx3(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
305
+ /* @__PURE__ */ jsx4(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx4(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
242
306
  ]
243
307
  }
244
308
  ));
245
309
  SelectTrigger.displayName = "SelectTrigger";
246
- var SelectContent = forwardRef3(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx3(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsx3(
310
+ var SelectContent = forwardRef3(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx4(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsx4(
247
311
  SelectPrimitive.Content,
248
312
  {
249
313
  ref,
@@ -254,7 +318,7 @@ var SelectContent = forwardRef3(({ className, children, position = "popper", ...
254
318
  className
255
319
  ),
256
320
  ...props,
257
- children: /* @__PURE__ */ jsx3(SelectPrimitive.Viewport, { className: "p-1", children })
321
+ children: /* @__PURE__ */ jsx4(SelectPrimitive.Viewport, { className: "p-1", children })
258
322
  }
259
323
  ) }));
260
324
  SelectContent.displayName = "SelectContent";
@@ -268,19 +332,19 @@ var SelectItem = forwardRef3(({ className, children, ...props }, ref) => /* @__P
268
332
  ),
269
333
  ...props,
270
334
  children: [
271
- /* @__PURE__ */ jsx3("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx3(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx3(Check, { className: "h-4 w-4" }) }) }),
272
- /* @__PURE__ */ jsx3(SelectPrimitive.ItemText, { children })
335
+ /* @__PURE__ */ jsx4("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx4(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx4(Check, { className: "h-4 w-4" }) }) }),
336
+ /* @__PURE__ */ jsx4(SelectPrimitive.ItemText, { children })
273
337
  ]
274
338
  }
275
339
  ));
276
340
  SelectItem.displayName = "SelectItem";
277
341
 
278
342
  // src/filter/BooleanFilter.tsx
279
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
343
+ import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
280
344
  var BOOLEAN_CHOICES = [
281
- { value: "all", label: "All" },
282
- { value: "yes", label: "Yes" },
283
- { value: "no", label: "No" }
345
+ { value: "all", labelKey: "booleanAll" },
346
+ { value: "yes", labelKey: "booleanYes" },
347
+ { value: "no", labelKey: "booleanNo" }
284
348
  ];
285
349
  function choiceOf(value) {
286
350
  if (!value) return "all";
@@ -300,11 +364,13 @@ function BooleanFilter({
300
364
  column,
301
365
  value,
302
366
  onChange,
303
- bare = false
367
+ bare = false,
368
+ labels: labelOverrides
304
369
  }) {
370
+ const labels = useFilterLabels(labelOverrides);
305
371
  const choice = choiceOf(value);
306
372
  const isFiltered = choice !== "all";
307
- const summary = choice === "yes" ? "Yes" : choice === "no" ? "No" : "";
373
+ const summary = choice === "yes" ? labels.booleanYes : choice === "no" ? labels.booleanNo : "";
308
374
  function emit(next) {
309
375
  if (next === "all") {
310
376
  onChange(void 0);
@@ -321,36 +387,36 @@ function BooleanFilter({
321
387
  if (match) emit(match);
322
388
  },
323
389
  children: [
324
- /* @__PURE__ */ jsx4(SelectTrigger, { "aria-label": `${column.header} filter`, children: /* @__PURE__ */ jsx4(SelectValue, {}) }),
325
- /* @__PURE__ */ jsx4(SelectContent, { children: BOOLEAN_CHOICES.map((option) => /* @__PURE__ */ jsx4(SelectItem, { value: option.value, children: option.label }, option.value)) })
390
+ /* @__PURE__ */ jsx5(SelectTrigger, { "aria-label": labels.booleanAriaLabel(column.header), children: /* @__PURE__ */ jsx5(SelectValue, {}) }),
391
+ /* @__PURE__ */ jsx5(SelectContent, { children: BOOLEAN_CHOICES.map((option) => /* @__PURE__ */ jsx5(SelectItem, { value: option.value, children: labels[option.labelKey] }, option.value)) })
326
392
  ]
327
393
  }
328
394
  );
329
395
  if (bare) {
330
- return /* @__PURE__ */ jsx4("div", { "data-testid": `filter-${column.id}`, children: panel });
396
+ return /* @__PURE__ */ jsx5("div", { "data-testid": `filter-${column.id}`, children: panel });
331
397
  }
332
398
  return /* @__PURE__ */ jsxs2(Popover, { children: [
333
- /* @__PURE__ */ jsx4(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs2(
399
+ /* @__PURE__ */ jsx5(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs2(
334
400
  Button,
335
401
  {
336
402
  variant: "outline",
337
403
  size: "sm",
338
404
  className: cn("gap-1", isFiltered ? "max-w-[140px] px-2" : "w-8 justify-center px-0"),
339
- "aria-label": `Filter ${column.header}`,
405
+ "aria-label": labels.filterAriaLabel(column.header),
340
406
  "data-testid": `filter-${column.id}`,
341
407
  children: [
342
- /* @__PURE__ */ jsx4(
408
+ /* @__PURE__ */ jsx5(
343
409
  FunnelIcon,
344
410
  {
345
411
  className: cn("h-3.5 w-3.5 shrink-0", isFiltered ? "opacity-100 text-primary" : "opacity-40"),
346
412
  "aria-hidden": true
347
413
  }
348
414
  ),
349
- isFiltered && /* @__PURE__ */ jsx4("span", { className: "truncate", children: summary })
415
+ isFiltered && /* @__PURE__ */ jsx5("span", { className: "truncate", children: summary })
350
416
  ]
351
417
  }
352
418
  ) }),
353
- /* @__PURE__ */ jsx4(PopoverContent, { className: "w-40 p-2", children: panel })
419
+ /* @__PURE__ */ jsx5(PopoverContent, { className: "w-40 p-2", children: panel })
354
420
  ] });
355
421
  }
356
422
 
@@ -362,10 +428,10 @@ import { endOfDay, endOfMonth, format, parseISO as parseISO2, startOfDay, startO
362
428
  import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon } from "lucide-react";
363
429
  import { useEffect, useRef } from "react";
364
430
  import { DayPicker, getDefaultClassNames } from "react-day-picker";
365
- import { jsx as jsx5 } from "react/jsx-runtime";
431
+ import { jsx as jsx6 } from "react/jsx-runtime";
366
432
  function Calendar({ className, classNames, ...props }) {
367
433
  const defaultClassNames = getDefaultClassNames();
368
- return /* @__PURE__ */ jsx5(
434
+ return /* @__PURE__ */ jsx6(
369
435
  DayPicker,
370
436
  {
371
437
  className: cn("w-fit", className),
@@ -416,14 +482,14 @@ function Calendar({ className, classNames, ...props }) {
416
482
  components: {
417
483
  Chevron: ({ className: chevronClassName, orientation }) => {
418
484
  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 });
485
+ return /* @__PURE__ */ jsx6(Icon2, { className: cn("h-4 w-4", chevronClassName), "aria-hidden": true });
420
486
  },
421
487
  DayButton: ({ className: dayClassName, day: _day, modifiers, ...dayProps }) => {
422
488
  const ref = useRef(null);
423
489
  useEffect(() => {
424
490
  if (modifiers.focused) ref.current?.focus();
425
491
  }, [modifiers.focused]);
426
- return /* @__PURE__ */ jsx5(
492
+ return /* @__PURE__ */ jsx6(
427
493
  "button",
428
494
  {
429
495
  ref,
@@ -447,21 +513,21 @@ function Calendar({ className, classNames, ...props }) {
447
513
  }
448
514
 
449
515
  // src/filter/DateRangeFilter.tsx
450
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
516
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
451
517
  var PRESETS = [
452
518
  {
453
519
  key: "today",
454
- label: "Today",
520
+ labelKey: "dateToday",
455
521
  range: (today) => ({ from: startOfDay(today), to: endOfDay(today) })
456
522
  },
457
523
  {
458
524
  key: "last7",
459
- label: "Last 7 days",
525
+ labelKey: "dateLast7Days",
460
526
  range: (today) => ({ from: startOfDay(subDays(today, 6)), to: endOfDay(today) })
461
527
  },
462
528
  {
463
529
  key: "thisMonth",
464
- label: "This month",
530
+ labelKey: "dateThisMonth",
465
531
  range: (today) => ({ from: startOfMonth(today), to: endOfMonth(today) })
466
532
  }
467
533
  ];
@@ -486,8 +552,11 @@ function DateRangeFilter({
486
552
  value,
487
553
  onChange,
488
554
  today = /* @__PURE__ */ new Date(),
489
- bare = false
555
+ bare = false,
556
+ labels: labelOverrides
490
557
  }) {
558
+ const labels = useFilterLabels(labelOverrides);
559
+ const locale = labels.dateLocale ? { locale: labels.dateLocale } : void 0;
491
560
  const range = rangeOf(value);
492
561
  function emit(next) {
493
562
  if (!next?.from || !next.to) {
@@ -502,56 +571,56 @@ function DateRangeFilter({
502
571
  });
503
572
  }
504
573
  const isFiltered = range?.from !== void 0;
505
- const summary = range?.from ? range.to ? `${format(range.from, "PP")} - ${format(range.to, "PP")}` : format(range.from, "PP") : "";
574
+ const summary = range?.from ? range.to ? `${format(range.from, "PP", locale)} - ${format(range.to, "PP", locale)}` : format(range.from, "PP", locale) : "";
506
575
  const panel = /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
507
576
  /* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap gap-2", children: [
508
- PRESETS.map((preset) => /* @__PURE__ */ jsx6(
577
+ PRESETS.map((preset) => /* @__PURE__ */ jsx7(
509
578
  Button,
510
579
  {
511
580
  type: "button",
512
581
  variant: "outline",
513
582
  size: "sm",
514
583
  onClick: () => emit(preset.range(today)),
515
- children: preset.label
584
+ children: labels[preset.labelKey]
516
585
  },
517
586
  preset.key
518
587
  )),
519
- /* @__PURE__ */ jsx6(Button, { type: "button", variant: "outline", size: "sm", onClick: () => emit(void 0), children: "Custom" })
588
+ /* @__PURE__ */ jsx7(Button, { type: "button", variant: "outline", size: "sm", onClick: () => emit(void 0), children: labels.dateCustom })
520
589
  ] }),
521
- /* @__PURE__ */ jsx6(Calendar, { mode: "range", selected: range, onSelect: emit, numberOfMonths: 2 })
590
+ /* @__PURE__ */ jsx7(Calendar, { mode: "range", selected: range, onSelect: emit, numberOfMonths: 2, locale: labels.dateLocale })
522
591
  ] });
523
592
  if (bare) {
524
- return /* @__PURE__ */ jsx6("div", { "data-testid": `filter-${column.id}`, children: panel });
593
+ return /* @__PURE__ */ jsx7("div", { "data-testid": `filter-${column.id}`, children: panel });
525
594
  }
526
595
  return /* @__PURE__ */ jsxs3(Popover, { children: [
527
- /* @__PURE__ */ jsx6(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs3(
596
+ /* @__PURE__ */ jsx7(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs3(
528
597
  Button,
529
598
  {
530
599
  variant: "outline",
531
600
  size: "sm",
532
601
  className: cn("gap-1", isFiltered ? "max-w-[220px] px-2" : "w-8 justify-center px-0"),
533
- "aria-label": `Filter ${column.header}`,
602
+ "aria-label": labels.filterAriaLabel(column.header),
534
603
  "data-testid": `filter-${column.id}`,
535
604
  children: [
536
- /* @__PURE__ */ jsx6(CalendarDaysIcon, { className: "h-3.5 w-3.5 shrink-0 opacity-70", "aria-hidden": true }),
537
- isFiltered && /* @__PURE__ */ jsx6("span", { className: "truncate", children: summary })
605
+ /* @__PURE__ */ jsx7(CalendarDaysIcon, { className: "h-3.5 w-3.5 shrink-0 opacity-70", "aria-hidden": true }),
606
+ isFiltered && /* @__PURE__ */ jsx7("span", { className: "truncate", children: summary })
538
607
  ]
539
608
  }
540
609
  ) }),
541
- /* @__PURE__ */ jsx6(PopoverContent, { className: "w-auto", children: panel })
610
+ /* @__PURE__ */ jsx7(PopoverContent, { className: "w-auto max-w-[var(--radix-popover-content-available-width)]", children: panel })
542
611
  ] });
543
612
  }
544
613
 
545
614
  // src/filter/EnumFilter.tsx
546
615
  import { FunnelIcon as FunnelIcon2 } from "@heroicons/react/24/outline";
547
- import { useMemo, useState } from "react";
616
+ import { useMemo as useMemo2, useState } from "react";
548
617
 
549
618
  // src/components/ui/checkbox.tsx
550
619
  import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
551
620
  import { Check as Check2, Minus } from "lucide-react";
552
621
  import { forwardRef as forwardRef4 } from "react";
553
- import { jsx as jsx7 } from "react/jsx-runtime";
554
- var Checkbox = forwardRef4(({ className, ...props }, ref) => /* @__PURE__ */ jsx7(
622
+ import { jsx as jsx8 } from "react/jsx-runtime";
623
+ var Checkbox = forwardRef4(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
555
624
  CheckboxPrimitive.Root,
556
625
  {
557
626
  ref,
@@ -564,16 +633,16 @@ var Checkbox = forwardRef4(({ className, ...props }, ref) => /* @__PURE__ */ jsx
564
633
  className
565
634
  ),
566
635
  ...props,
567
- children: /* @__PURE__ */ jsx7(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: props.checked === "indeterminate" ? /* @__PURE__ */ jsx7(Minus, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx7(Check2, { className: "h-3 w-3" }) })
636
+ children: /* @__PURE__ */ jsx8(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: props.checked === "indeterminate" ? /* @__PURE__ */ jsx8(Minus, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx8(Check2, { className: "h-3 w-3" }) })
568
637
  }
569
638
  ));
570
639
  Checkbox.displayName = "Checkbox";
571
640
 
572
641
  // src/components/ui/input.tsx
573
642
  import { forwardRef as forwardRef5 } from "react";
574
- import { jsx as jsx8 } from "react/jsx-runtime";
643
+ import { jsx as jsx9 } from "react/jsx-runtime";
575
644
  var Input = forwardRef5(({ className, type, ...props }, ref) => {
576
- return /* @__PURE__ */ jsx8(
645
+ return /* @__PURE__ */ jsx9(
577
646
  "input",
578
647
  {
579
648
  type,
@@ -589,7 +658,7 @@ var Input = forwardRef5(({ className, type, ...props }, ref) => {
589
658
  Input.displayName = "Input";
590
659
 
591
660
  // src/filter/EnumFilter.tsx
592
- import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
661
+ import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
593
662
  function selectedValuesOf(value) {
594
663
  if (!value || value.operator !== "in" || !Array.isArray(value.value)) return [];
595
664
  return value.value.filter((entry) => typeof entry === "string");
@@ -622,16 +691,18 @@ function EnumFilter({
622
691
  column,
623
692
  value,
624
693
  onChange,
625
- bare = false
694
+ bare = false,
695
+ labels: labelOverrides
626
696
  }) {
697
+ const labels = useFilterLabels(labelOverrides);
627
698
  const [search, setSearch] = useState("");
628
699
  const selected = selectedValuesOf(value);
629
- const visibleOptions = useMemo(() => {
700
+ const visibleOptions = useMemo2(() => {
630
701
  const term = search.trim().toLowerCase();
631
702
  if (!term) return column.options;
632
703
  return column.options.filter((option) => option.label.toLowerCase().includes(term));
633
704
  }, [column.options, search]);
634
- const renderChunks = useMemo(() => buildRenderChunks(visibleOptions), [visibleOptions]);
705
+ const renderChunks = useMemo2(() => buildRenderChunks(visibleOptions), [visibleOptions]);
635
706
  function emit(next) {
636
707
  onChange(next.length === 0 ? void 0 : { field: column.id, operator: "in", value: next });
637
708
  }
@@ -662,7 +733,7 @@ function EnumFilter({
662
733
  {
663
734
  className: "flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground",
664
735
  children: [
665
- /* @__PURE__ */ jsx9(
736
+ /* @__PURE__ */ jsx10(
666
737
  Checkbox,
667
738
  {
668
739
  checked: selected.includes(option.value),
@@ -676,29 +747,29 @@ function EnumFilter({
676
747
  );
677
748
  }
678
749
  const isFiltered = selected.length > 0;
679
- const summary = `${selected.length} selected`;
750
+ const summary = labels.selectedCount(selected.length);
680
751
  const panel = /* @__PURE__ */ jsxs4("div", { className: bare ? "flex w-full flex-col gap-2" : "flex w-64 flex-col gap-2 p-2", children: [
681
- /* @__PURE__ */ jsx9(
752
+ /* @__PURE__ */ jsx10(
682
753
  Input,
683
754
  {
684
- placeholder: `Search ${column.header.toLowerCase()}...`,
755
+ placeholder: labels.searchPlaceholder(column.header),
685
756
  value: search,
686
757
  onChange: (event) => setSearch(event.target.value)
687
758
  }
688
759
  ),
689
760
  /* @__PURE__ */ jsxs4("label", { className: "flex items-center gap-2 border-b px-1 pb-2 text-sm", children: [
690
- /* @__PURE__ */ jsx9(
761
+ /* @__PURE__ */ jsx10(
691
762
  Checkbox,
692
763
  {
693
764
  checked: someVisibleSelected ? "indeterminate" : allVisibleSelected,
694
765
  disabled: visibleValues.length === 0,
695
766
  onCheckedChange: toggleSelectAllVisible,
696
- "aria-label": "Select all"
767
+ "aria-label": labels.selectAll
697
768
  }
698
769
  ),
699
- "Select all"
770
+ labels.selectAll
700
771
  ] }),
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) => {
772
+ /* @__PURE__ */ jsx10("div", { className: "flex max-h-60 flex-col gap-0.5 overflow-y-auto", children: renderChunks.length === 0 ? /* @__PURE__ */ jsx10("p", { className: "py-2 text-center text-sm text-muted-foreground", children: labels.noMatches }) : renderChunks.map((chunk) => {
702
773
  if (chunk.kind === "single") return renderOption(chunk.row.option);
703
774
  const headerState = groupCheckState(visibleOptions, selected, chunk.group);
704
775
  return (
@@ -713,12 +784,12 @@ function EnumFilter({
713
784
  "data-group-header": true,
714
785
  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
786
  children: [
716
- /* @__PURE__ */ jsx9(
787
+ /* @__PURE__ */ jsx10(
717
788
  Checkbox,
718
789
  {
719
790
  checked: headerState === "indeterminate" ? "indeterminate" : headerState === "checked",
720
791
  onCheckedChange: () => toggleGroup(chunk.group),
721
- "aria-label": `Select all of ${chunk.group}`
792
+ "aria-label": labels.selectAllOfGroup(chunk.group)
722
793
  }
723
794
  ),
724
795
  chunk.group
@@ -731,30 +802,30 @@ function EnumFilter({
731
802
  }) })
732
803
  ] });
733
804
  if (bare) {
734
- return /* @__PURE__ */ jsx9("div", { "data-testid": `filter-${column.id}`, children: panel });
805
+ return /* @__PURE__ */ jsx10("div", { "data-testid": `filter-${column.id}`, children: panel });
735
806
  }
736
807
  return /* @__PURE__ */ jsxs4(Popover, { children: [
737
- /* @__PURE__ */ jsx9(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs4(
808
+ /* @__PURE__ */ jsx10(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs4(
738
809
  Button,
739
810
  {
740
811
  variant: "outline",
741
812
  size: "sm",
742
813
  className: cn("gap-1", isFiltered ? "max-w-[180px] px-2" : "w-8 justify-center px-0"),
743
- "aria-label": `Filter ${column.header}`,
814
+ "aria-label": labels.filterAriaLabel(column.header),
744
815
  "data-testid": `filter-${column.id}`,
745
816
  children: [
746
- /* @__PURE__ */ jsx9(
817
+ /* @__PURE__ */ jsx10(
747
818
  FunnelIcon2,
748
819
  {
749
820
  className: cn("h-3.5 w-3.5 shrink-0", isFiltered ? "opacity-100 text-primary" : "opacity-40"),
750
821
  "aria-hidden": true
751
822
  }
752
823
  ),
753
- isFiltered && /* @__PURE__ */ jsx9("span", { className: "truncate", children: summary })
824
+ isFiltered && /* @__PURE__ */ jsx10("span", { className: "truncate", children: summary })
754
825
  ]
755
826
  }
756
827
  ) }),
757
- /* @__PURE__ */ jsx9(PopoverContent, { className: "w-64 p-2", children: panel })
828
+ /* @__PURE__ */ jsx10(PopoverContent, { className: "w-64 p-2", children: panel })
758
829
  ] });
759
830
  }
760
831
 
@@ -897,15 +968,15 @@ function descriptorFor(field, range) {
897
968
  }
898
969
 
899
970
  // src/filter/NumberComparisonFilter.tsx
900
- import { Fragment, jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
971
+ import { Fragment, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
901
972
  var NUMBER_OPERATORS = [
902
- { value: "gt", label: "Greater than" },
903
- { value: "gte", label: "Greater than or equal to" },
904
- { value: "lt", label: "Less than" },
905
- { value: "lte", label: "Less than or equal to" },
906
- { value: "eq", label: "Equals" },
907
- { value: "neq", label: "Does not equal" },
908
- { value: "between", label: "Between" }
973
+ { value: "gt", labelKey: "numberGreaterThan" },
974
+ { value: "gte", labelKey: "numberGreaterThanOrEqual" },
975
+ { value: "lt", labelKey: "numberLessThan" },
976
+ { value: "lte", labelKey: "numberLessThanOrEqual" },
977
+ { value: "eq", labelKey: "numberEquals" },
978
+ { value: "neq", labelKey: "numberNotEquals" },
979
+ { value: "between", labelKey: "numberBetween" }
909
980
  ];
910
981
  var OPERATOR_SYMBOL = {
911
982
  gt: ">",
@@ -939,8 +1010,10 @@ function NumberComparisonFilter({
939
1010
  column,
940
1011
  value,
941
1012
  onChange,
942
- bare = true
1013
+ bare = true,
1014
+ labels: labelOverrides
943
1015
  }) {
1016
+ const labels = useFilterLabels(labelOverrides);
944
1017
  const initial = stateFromValue(value);
945
1018
  const [operator, setOperator] = useState2(initial.operator);
946
1019
  const [text, setText] = useState2(initial.text);
@@ -994,20 +1067,20 @@ function NumberComparisonFilter({
994
1067
  emit(nextOperator, text, text2);
995
1068
  },
996
1069
  children: [
997
- /* @__PURE__ */ jsx10(SelectTrigger, { id: operatorId, "aria-label": `${column.header} filter operator`, children: /* @__PURE__ */ jsx10(SelectValue, {}) }),
998
- /* @__PURE__ */ jsx10(SelectContent, { children: NUMBER_OPERATORS.map((option) => /* @__PURE__ */ jsx10(SelectItem, { value: option.value, children: option.label }, option.value)) })
1070
+ /* @__PURE__ */ jsx11(SelectTrigger, { id: operatorId, "aria-label": labels.operatorAriaLabel(column.header), children: /* @__PURE__ */ jsx11(SelectValue, {}) }),
1071
+ /* @__PURE__ */ jsx11(SelectContent, { children: NUMBER_OPERATORS.map((option) => /* @__PURE__ */ jsx11(SelectItem, { value: option.value, children: labels[option.labelKey] }, option.value)) })
999
1072
  ]
1000
1073
  }
1001
1074
  ),
1002
1075
  /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
1003
- /* @__PURE__ */ jsx10(
1076
+ /* @__PURE__ */ jsx11(
1004
1077
  Input,
1005
1078
  {
1006
1079
  id: valueId,
1007
1080
  type: "number",
1008
1081
  className: "min-w-0",
1009
- "aria-label": isBetween ? `${column.header} minimum` : column.header,
1010
- placeholder: isBetween ? "Min" : "Value",
1082
+ "aria-label": isBetween ? labels.minimumAriaLabel(column.header) : column.header,
1083
+ placeholder: isBetween ? labels.minPlaceholder : labels.valuePlaceholder,
1011
1084
  value: text,
1012
1085
  onChange: (event) => {
1013
1086
  setText(event.target.value);
@@ -1016,14 +1089,14 @@ function NumberComparisonFilter({
1016
1089
  }
1017
1090
  ),
1018
1091
  isBetween && /* @__PURE__ */ jsxs5(Fragment, { children: [
1019
- /* @__PURE__ */ jsx10("span", { className: "shrink-0 text-xs text-muted-foreground", children: "to" }),
1020
- /* @__PURE__ */ jsx10(
1092
+ /* @__PURE__ */ jsx11("span", { className: "shrink-0 text-xs text-muted-foreground", children: labels.rangeSeparator }),
1093
+ /* @__PURE__ */ jsx11(
1021
1094
  Input,
1022
1095
  {
1023
1096
  type: "number",
1024
1097
  className: "min-w-0",
1025
- "aria-label": `${column.header} maximum`,
1026
- placeholder: "Max",
1098
+ "aria-label": labels.maximumAriaLabel(column.header),
1099
+ placeholder: labels.maxPlaceholder,
1027
1100
  value: text2,
1028
1101
  onChange: (event) => {
1029
1102
  setText2(event.target.value);
@@ -1035,37 +1108,37 @@ function NumberComparisonFilter({
1035
1108
  ] })
1036
1109
  ] });
1037
1110
  if (bare) {
1038
- return /* @__PURE__ */ jsx10("div", { "data-testid": `filter-${column.id}`, children: panel });
1111
+ return /* @__PURE__ */ jsx11("div", { "data-testid": `filter-${column.id}`, children: panel });
1039
1112
  }
1040
1113
  return /* @__PURE__ */ jsxs5(Popover, { children: [
1041
- /* @__PURE__ */ jsx10(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs5(
1114
+ /* @__PURE__ */ jsx11(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs5(
1042
1115
  Button,
1043
1116
  {
1044
1117
  variant: "outline",
1045
1118
  size: "sm",
1046
1119
  className: cn("gap-1", isFiltered ? "max-w-[180px] px-2" : "w-8 justify-center px-0"),
1047
- "aria-label": `Filter ${column.header}`,
1120
+ "aria-label": labels.filterAriaLabel(column.header),
1048
1121
  "data-testid": `filter-${column.id}`,
1049
1122
  children: [
1050
- /* @__PURE__ */ jsx10(
1123
+ /* @__PURE__ */ jsx11(
1051
1124
  FunnelIcon3,
1052
1125
  {
1053
1126
  className: cn("h-3.5 w-3.5 shrink-0", isFiltered ? "opacity-100 text-primary" : "opacity-40"),
1054
1127
  "aria-hidden": true
1055
1128
  }
1056
1129
  ),
1057
- isFiltered && /* @__PURE__ */ jsx10("span", { className: "truncate", children: summary })
1130
+ isFiltered && /* @__PURE__ */ jsx11("span", { className: "truncate", children: summary })
1058
1131
  ]
1059
1132
  }
1060
1133
  ) }),
1061
- /* @__PURE__ */ jsx10(PopoverContent, { className: "w-auto p-3", children: panel })
1134
+ /* @__PURE__ */ jsx11(PopoverContent, { className: "w-auto p-3", children: panel })
1062
1135
  ] });
1063
1136
  }
1064
1137
 
1065
1138
  // src/filter/NumberRangeFilter.tsx
1066
1139
  import { FunnelIcon as FunnelIcon4 } from "@heroicons/react/24/outline";
1067
1140
  import { useEffect as useEffect3, useId as useId2, useRef as useRef3, useState as useState3 } from "react";
1068
- import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
1141
+ import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
1069
1142
  function parseNumber2(raw) {
1070
1143
  if (raw.trim() === "") return void 0;
1071
1144
  const parsed = Number(raw);
@@ -1075,8 +1148,10 @@ function NumberRangeFilter({
1075
1148
  column,
1076
1149
  value,
1077
1150
  onChange,
1078
- bare = false
1151
+ bare = false,
1152
+ labels: labelOverrides
1079
1153
  }) {
1154
+ const labels = useFilterLabels(labelOverrides);
1080
1155
  const initial = rangeOf2(value);
1081
1156
  const [minText, setMinText] = useState3(initial.min?.toString() ?? "");
1082
1157
  const [maxText, setMaxText] = useState3(initial.max?.toString() ?? "");
@@ -1102,13 +1177,13 @@ function NumberRangeFilter({
1102
1177
  const isFiltered = min !== void 0 || max !== void 0;
1103
1178
  const summary = min !== void 0 && max !== void 0 ? `${defaultFormat(column, min)} \u2013 ${defaultFormat(column, max)}` : min !== void 0 ? `\u2265 ${defaultFormat(column, min)}` : max !== void 0 ? `\u2264 ${defaultFormat(column, max)}` : "";
1104
1179
  const panel = /* @__PURE__ */ jsxs6("div", { className: "flex w-full max-w-[220px] items-center gap-2", children: [
1105
- /* @__PURE__ */ jsx11(
1180
+ /* @__PURE__ */ jsx12(
1106
1181
  Input,
1107
1182
  {
1108
1183
  id: minId,
1109
1184
  type: "number",
1110
- "aria-label": `${column.header} minimum`,
1111
- placeholder: "Min",
1185
+ "aria-label": labels.minimumAriaLabel(column.header),
1186
+ placeholder: labels.minPlaceholder,
1112
1187
  className: "min-w-0",
1113
1188
  value: minText,
1114
1189
  onChange: (event) => {
@@ -1117,14 +1192,14 @@ function NumberRangeFilter({
1117
1192
  }
1118
1193
  }
1119
1194
  ),
1120
- /* @__PURE__ */ jsx11("span", { className: "shrink-0 text-xs text-muted-foreground", children: "to" }),
1121
- /* @__PURE__ */ jsx11(
1195
+ /* @__PURE__ */ jsx12("span", { className: "shrink-0 text-xs text-muted-foreground", children: labels.rangeSeparator }),
1196
+ /* @__PURE__ */ jsx12(
1122
1197
  Input,
1123
1198
  {
1124
1199
  id: maxId,
1125
1200
  type: "number",
1126
- "aria-label": `${column.header} maximum`,
1127
- placeholder: "Max",
1201
+ "aria-label": labels.maximumAriaLabel(column.header),
1202
+ placeholder: labels.maxPlaceholder,
1128
1203
  className: "min-w-0",
1129
1204
  value: maxText,
1130
1205
  onChange: (event) => {
@@ -1135,37 +1210,37 @@ function NumberRangeFilter({
1135
1210
  )
1136
1211
  ] });
1137
1212
  if (bare) {
1138
- return /* @__PURE__ */ jsx11("div", { "data-testid": `filter-${column.id}`, children: panel });
1213
+ return /* @__PURE__ */ jsx12("div", { "data-testid": `filter-${column.id}`, children: panel });
1139
1214
  }
1140
1215
  return /* @__PURE__ */ jsxs6(Popover, { children: [
1141
- /* @__PURE__ */ jsx11(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
1216
+ /* @__PURE__ */ jsx12(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
1142
1217
  Button,
1143
1218
  {
1144
1219
  variant: "outline",
1145
1220
  size: "sm",
1146
1221
  className: cn("gap-1", isFiltered ? "max-w-[180px] px-2" : "w-8 justify-center px-0"),
1147
- "aria-label": `Filter ${column.header}`,
1222
+ "aria-label": labels.filterAriaLabel(column.header),
1148
1223
  "data-testid": `filter-${column.id}`,
1149
1224
  children: [
1150
- /* @__PURE__ */ jsx11(
1225
+ /* @__PURE__ */ jsx12(
1151
1226
  FunnelIcon4,
1152
1227
  {
1153
1228
  className: cn("h-3.5 w-3.5 shrink-0", isFiltered ? "opacity-100 text-primary" : "opacity-40"),
1154
1229
  "aria-hidden": true
1155
1230
  }
1156
1231
  ),
1157
- isFiltered && /* @__PURE__ */ jsx11("span", { className: "truncate", children: summary })
1232
+ isFiltered && /* @__PURE__ */ jsx12("span", { className: "truncate", children: summary })
1158
1233
  ]
1159
1234
  }
1160
1235
  ) }),
1161
- /* @__PURE__ */ jsx11(PopoverContent, { className: "w-auto p-3", children: panel })
1236
+ /* @__PURE__ */ jsx12(PopoverContent, { className: "w-auto p-3", children: panel })
1162
1237
  ] });
1163
1238
  }
1164
1239
 
1165
1240
  // src/filter/NumberHistogramFilter.tsx
1166
1241
  import { FunnelIcon as FunnelIcon5 } from "@heroicons/react/24/outline";
1167
- import { useCallback, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
1168
- import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
1242
+ import { useCallback, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef4, useState as useState4 } from "react";
1243
+ import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
1169
1244
  var BAR_HEIGHT_PX = 56;
1170
1245
  var DEFAULT_BUCKETS = 24;
1171
1246
  function tLog(v) {
@@ -1182,8 +1257,10 @@ function NumberHistogramFilter({
1182
1257
  loadValues,
1183
1258
  format: format2 = (v) => v.toLocaleString(),
1184
1259
  buckets = DEFAULT_BUCKETS,
1185
- bare = true
1260
+ bare = true,
1261
+ labels: labelOverrides
1186
1262
  }) {
1263
+ const labels = useFilterLabels(labelOverrides);
1187
1264
  const [openState, setOpen] = useState4(false);
1188
1265
  const open = bare || openState;
1189
1266
  const trackRef = useRef4(null);
@@ -1205,12 +1282,12 @@ function NumberHistogramFilter({
1205
1282
  };
1206
1283
  }, [open, loadValues]);
1207
1284
  const sourceValues = allValues ?? loadedValues;
1208
- const nums = useMemo2(
1285
+ const nums = useMemo3(
1209
1286
  () => open ? sourceValues.filter((v) => v != null) : [],
1210
1287
  [sourceValues, open]
1211
1288
  );
1212
- const dataMin = useMemo2(() => nums.reduce((a, b) => Math.min(a, b), Infinity), [nums]);
1213
- const dataMax = useMemo2(() => nums.reduce((a, b) => Math.max(a, b), -Infinity), [nums]);
1289
+ const dataMin = useMemo3(() => nums.reduce((a, b) => Math.min(a, b), Infinity), [nums]);
1290
+ const dataMax = useMemo3(() => nums.reduce((a, b) => Math.max(a, b), -Infinity), [nums]);
1214
1291
  const activeMin = min ?? dataMin;
1215
1292
  const activeMax = max ?? dataMax;
1216
1293
  const [minText, setMinText] = useState4("");
@@ -1227,7 +1304,7 @@ function NumberHistogramFilter({
1227
1304
  (v) => logDataMax === logDataMin ? 0 : (tLog(v) - logDataMin) / (logDataMax - logDataMin) * 100,
1228
1305
  [logDataMin, logDataMax]
1229
1306
  );
1230
- const histBars = useMemo2(() => {
1307
+ const histBars = useMemo3(() => {
1231
1308
  if (!nums.length || dataMin === dataMax || !Number.isFinite(dataMin) || !Number.isFinite(dataMax)) return [];
1232
1309
  const step = (logDataMax - logDataMin) / buckets;
1233
1310
  const counts = Array(buckets).fill(0);
@@ -1266,8 +1343,8 @@ function NumberHistogramFilter({
1266
1343
  const isFiltered = value !== void 0;
1267
1344
  const summary = isFiltered ? `${format2(activeMin)} \u2013 ${format2(activeMax)}` : "";
1268
1345
  const panel = /* @__PURE__ */ jsxs7("div", { className: bare ? "flex w-full flex-col gap-3" : "flex w-80 flex-col gap-3", children: [
1269
- loading && /* @__PURE__ */ jsx12("p", { className: "text-xs text-muted-foreground", "data-testid": `filter-${column.id}-loading`, children: "Loading\u2026" }),
1270
- /* @__PURE__ */ jsx12("div", { className: "flex items-end gap-px", style: { height: BAR_HEIGHT_PX }, "data-testid": `filter-${column.id}-histogram`, children: histBars.map((bar, i) => /* @__PURE__ */ jsx12(
1346
+ loading && /* @__PURE__ */ jsx13("p", { className: "text-xs text-muted-foreground", "data-testid": `filter-${column.id}-loading`, children: labels.loading }),
1347
+ /* @__PURE__ */ jsx13("div", { className: "flex items-end gap-px", style: { height: BAR_HEIGHT_PX }, "data-testid": `filter-${column.id}-histogram`, children: histBars.map((bar, i) => /* @__PURE__ */ jsx13(
1271
1348
  "div",
1272
1349
  {
1273
1350
  className: cn("flex-1 rounded-sm", bar.active ? "bg-primary/70" : "bg-muted-foreground/20"),
@@ -1276,11 +1353,11 @@ function NumberHistogramFilter({
1276
1353
  i
1277
1354
  )) }),
1278
1355
  /* @__PURE__ */ jsxs7("div", { ref: trackRef, className: "relative h-5", onMouseMove: handleTrackHover, children: [
1279
- /* @__PURE__ */ jsx12(
1356
+ /* @__PURE__ */ jsx13(
1280
1357
  "input",
1281
1358
  {
1282
1359
  type: "range",
1283
- "aria-label": `${column.header} minimum (slider)`,
1360
+ "aria-label": labels.minimumSliderAriaLabel(column.header),
1284
1361
  min: logDataMin,
1285
1362
  max: logDataMax,
1286
1363
  step: logStep,
@@ -1290,11 +1367,11 @@ function NumberHistogramFilter({
1290
1367
  style: { zIndex: minOnTop ? 5 : 3 }
1291
1368
  }
1292
1369
  ),
1293
- /* @__PURE__ */ jsx12(
1370
+ /* @__PURE__ */ jsx13(
1294
1371
  "input",
1295
1372
  {
1296
1373
  type: "range",
1297
- "aria-label": `${column.header} maximum (slider)`,
1374
+ "aria-label": labels.maximumSliderAriaLabel(column.header),
1298
1375
  min: logDataMin,
1299
1376
  max: logDataMax,
1300
1377
  step: logStep,
@@ -1304,14 +1381,14 @@ function NumberHistogramFilter({
1304
1381
  style: { zIndex: minOnTop ? 3 : 5 }
1305
1382
  }
1306
1383
  ),
1307
- /* @__PURE__ */ jsx12("div", { className: "pointer-events-none absolute top-1/2 h-1.5 w-full -translate-y-1/2 rounded-full bg-muted", children: /* @__PURE__ */ jsx12(
1384
+ /* @__PURE__ */ jsx13("div", { className: "pointer-events-none absolute top-1/2 h-1.5 w-full -translate-y-1/2 rounded-full bg-muted", children: /* @__PURE__ */ jsx13(
1308
1385
  "div",
1309
1386
  {
1310
1387
  className: "absolute h-full rounded-full bg-primary",
1311
1388
  style: { left: `${logPct(activeMin)}%`, right: `${100 - logPct(activeMax)}%` }
1312
1389
  }
1313
1390
  ) }),
1314
- [activeMin, activeMax].map((v, i) => /* @__PURE__ */ jsx12(
1391
+ [activeMin, activeMax].map((v, i) => /* @__PURE__ */ jsx13(
1315
1392
  "div",
1316
1393
  {
1317
1394
  className: "pointer-events-none absolute top-1/2 h-4 w-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-primary bg-background shadow",
@@ -1321,12 +1398,12 @@ function NumberHistogramFilter({
1321
1398
  ))
1322
1399
  ] }),
1323
1400
  /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
1324
- /* @__PURE__ */ jsx12(
1401
+ /* @__PURE__ */ jsx13(
1325
1402
  Input,
1326
1403
  {
1327
1404
  type: "text",
1328
1405
  inputMode: "numeric",
1329
- "aria-label": `${column.header} minimum`,
1406
+ "aria-label": labels.minimumAriaLabel(column.header),
1330
1407
  value: minText,
1331
1408
  onChange: (event) => {
1332
1409
  setMinText(event.target.value);
@@ -1335,13 +1412,13 @@ function NumberHistogramFilter({
1335
1412
  }
1336
1413
  }
1337
1414
  ),
1338
- /* @__PURE__ */ jsx12("span", { className: "shrink-0 text-xs text-muted-foreground", children: "to" }),
1339
- /* @__PURE__ */ jsx12(
1415
+ /* @__PURE__ */ jsx13("span", { className: "shrink-0 text-xs text-muted-foreground", children: labels.rangeSeparator }),
1416
+ /* @__PURE__ */ jsx13(
1340
1417
  Input,
1341
1418
  {
1342
1419
  type: "text",
1343
1420
  inputMode: "numeric",
1344
- "aria-label": `${column.header} maximum`,
1421
+ "aria-label": labels.maximumAriaLabel(column.header),
1345
1422
  value: maxText,
1346
1423
  onChange: (event) => {
1347
1424
  setMaxText(event.target.value);
@@ -1351,33 +1428,33 @@ function NumberHistogramFilter({
1351
1428
  }
1352
1429
  )
1353
1430
  ] }),
1354
- isFiltered && /* @__PURE__ */ jsx12(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onChange(void 0), children: "Clear" })
1431
+ isFiltered && /* @__PURE__ */ jsx13(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onChange(void 0), children: labels.clear })
1355
1432
  ] });
1356
1433
  if (bare) {
1357
- return /* @__PURE__ */ jsx12("div", { "data-testid": `filter-${column.id}`, children: panel });
1434
+ return /* @__PURE__ */ jsx13("div", { "data-testid": `filter-${column.id}`, children: panel });
1358
1435
  }
1359
1436
  return /* @__PURE__ */ jsxs7(Popover, { open, onOpenChange: setOpen, children: [
1360
- /* @__PURE__ */ jsx12(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs7(
1437
+ /* @__PURE__ */ jsx13(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs7(
1361
1438
  Button,
1362
1439
  {
1363
1440
  variant: "outline",
1364
1441
  size: "sm",
1365
1442
  className: cn("gap-1", isFiltered ? "max-w-[200px] px-2" : "w-8 justify-center px-0"),
1366
- "aria-label": `Filter ${column.header}`,
1443
+ "aria-label": labels.filterAriaLabel(column.header),
1367
1444
  "data-testid": `filter-${column.id}`,
1368
1445
  children: [
1369
- /* @__PURE__ */ jsx12(
1446
+ /* @__PURE__ */ jsx13(
1370
1447
  FunnelIcon5,
1371
1448
  {
1372
1449
  className: cn("h-3.5 w-3.5 shrink-0", isFiltered ? "opacity-100 text-primary" : "opacity-40"),
1373
1450
  "aria-hidden": true
1374
1451
  }
1375
1452
  ),
1376
- isFiltered && /* @__PURE__ */ jsx12("span", { className: "truncate", children: summary })
1453
+ isFiltered && /* @__PURE__ */ jsx13("span", { className: "truncate", children: summary })
1377
1454
  ]
1378
1455
  }
1379
1456
  ) }),
1380
- /* @__PURE__ */ jsx12(PopoverContent, { className: "w-80", children: panel })
1457
+ /* @__PURE__ */ jsx13(PopoverContent, { className: "w-80", children: panel })
1381
1458
  ] });
1382
1459
  }
1383
1460
 
@@ -1429,20 +1506,22 @@ function facetedNumberValues(data, column, filter) {
1429
1506
  // src/filter/StringFilter.tsx
1430
1507
  import { FunnelIcon as FunnelIcon6 } from "@heroicons/react/24/outline";
1431
1508
  import { useEffect as useEffect5, useId as useId3, useState as useState5 } from "react";
1432
- import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
1509
+ import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
1433
1510
  var STRING_OPERATORS = [
1434
- { value: "contains", label: "Contains" },
1435
- { value: "eq", label: "Is" },
1436
- { value: "startsWith", label: "Starts with" },
1437
- { value: "endsWith", label: "Ends with" }
1511
+ { value: "contains", labelKey: "stringContains" },
1512
+ { value: "eq", labelKey: "stringIs" },
1513
+ { value: "startsWith", labelKey: "stringStartsWith" },
1514
+ { value: "endsWith", labelKey: "stringEndsWith" }
1438
1515
  ];
1439
1516
  var DEFAULT_OPERATOR2 = "contains";
1440
1517
  function StringFilter({
1441
1518
  column,
1442
1519
  value,
1443
1520
  onChange,
1444
- bare = false
1521
+ bare = false,
1522
+ labels: labelOverrides
1445
1523
  }) {
1524
+ const labels = useFilterLabels(labelOverrides);
1446
1525
  const [operator, setOperator] = useState5(value?.operator ?? DEFAULT_OPERATOR2);
1447
1526
  const text = typeof value?.value === "string" ? value.value : "";
1448
1527
  const inputId = useId3();
@@ -1469,66 +1548,66 @@ function StringFilter({
1469
1548
  emit(nextOperator, text);
1470
1549
  },
1471
1550
  children: [
1472
- /* @__PURE__ */ jsx13(SelectTrigger, { "aria-label": `${column.header} filter operator`, children: /* @__PURE__ */ jsx13(SelectValue, {}) }),
1473
- /* @__PURE__ */ jsx13(SelectContent, { children: STRING_OPERATORS.map((option) => /* @__PURE__ */ jsx13(SelectItem, { value: option.value, children: option.label }, option.value)) })
1551
+ /* @__PURE__ */ jsx14(SelectTrigger, { "aria-label": labels.operatorAriaLabel(column.header), children: /* @__PURE__ */ jsx14(SelectValue, {}) }),
1552
+ /* @__PURE__ */ jsx14(SelectContent, { children: STRING_OPERATORS.map((option) => /* @__PURE__ */ jsx14(SelectItem, { value: option.value, children: labels[option.labelKey] }, option.value)) })
1474
1553
  ]
1475
1554
  }
1476
1555
  ),
1477
- /* @__PURE__ */ jsx13(
1556
+ /* @__PURE__ */ jsx14(
1478
1557
  Input,
1479
1558
  {
1480
1559
  id: inputId,
1481
1560
  value: text,
1482
- placeholder: `Filter ${column.header.toLowerCase()}...`,
1561
+ placeholder: labels.stringPlaceholder(column.header),
1483
1562
  onChange: (event) => emit(operator, event.target.value)
1484
1563
  }
1485
1564
  )
1486
1565
  ] });
1487
1566
  if (bare) {
1488
- return /* @__PURE__ */ jsx13("div", { "data-testid": `filter-${column.id}`, children: panel });
1567
+ return /* @__PURE__ */ jsx14("div", { "data-testid": `filter-${column.id}`, children: panel });
1489
1568
  }
1490
1569
  return /* @__PURE__ */ jsxs8(Popover, { children: [
1491
- /* @__PURE__ */ jsx13(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs8(
1570
+ /* @__PURE__ */ jsx14(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs8(
1492
1571
  Button,
1493
1572
  {
1494
1573
  variant: "outline",
1495
1574
  size: "sm",
1496
1575
  className: cn("gap-1", isFiltered ? "max-w-[160px] px-2" : "w-8 justify-center px-0"),
1497
- "aria-label": `Filter ${column.header}`,
1576
+ "aria-label": labels.filterAriaLabel(column.header),
1498
1577
  "data-testid": `filter-${column.id}`,
1499
1578
  children: [
1500
- /* @__PURE__ */ jsx13(
1579
+ /* @__PURE__ */ jsx14(
1501
1580
  FunnelIcon6,
1502
1581
  {
1503
1582
  className: cn("h-3.5 w-3.5 shrink-0", isFiltered ? "opacity-100 text-primary" : "opacity-40"),
1504
1583
  "aria-hidden": true
1505
1584
  }
1506
1585
  ),
1507
- isFiltered && /* @__PURE__ */ jsx13("span", { className: "truncate", children: text })
1586
+ isFiltered && /* @__PURE__ */ jsx14("span", { className: "truncate", children: text })
1508
1587
  ]
1509
1588
  }
1510
1589
  ) }),
1511
- /* @__PURE__ */ jsx13(PopoverContent, { className: "w-auto p-3", children: panel })
1590
+ /* @__PURE__ */ jsx14(PopoverContent, { className: "w-auto p-3", children: panel })
1512
1591
  ] });
1513
1592
  }
1514
1593
 
1515
1594
  // src/filter/registry.tsx
1516
- import { jsx as jsx14 } from "react/jsx-runtime";
1595
+ import { jsx as jsx15 } from "react/jsx-runtime";
1517
1596
  function renderDefaultFilterWidget(column, value, onChange) {
1518
1597
  const bare = column.filterDisplay !== "row";
1519
1598
  switch (column.type) {
1520
1599
  case "string":
1521
- return /* @__PURE__ */ jsx14(StringFilter, { column, value, onChange, bare });
1600
+ return /* @__PURE__ */ jsx15(StringFilter, { column, value, onChange, bare });
1522
1601
  case "enum":
1523
- return /* @__PURE__ */ jsx14(EnumFilter, { column, value, onChange, bare });
1602
+ return /* @__PURE__ */ jsx15(EnumFilter, { column, value, onChange, bare });
1524
1603
  case "boolean":
1525
- return /* @__PURE__ */ jsx14(BooleanFilter, { column, value, onChange, bare });
1604
+ return /* @__PURE__ */ jsx15(BooleanFilter, { column, value, onChange, bare });
1526
1605
  case "number":
1527
1606
  case "currency":
1528
- return /* @__PURE__ */ jsx14(NumberRangeFilter, { column, value, onChange, bare });
1607
+ return /* @__PURE__ */ jsx15(NumberRangeFilter, { column, value, onChange, bare });
1529
1608
  case "date":
1530
1609
  case "datetime":
1531
- return /* @__PURE__ */ jsx14(DateRangeFilter, { column, value, onChange, bare });
1610
+ return /* @__PURE__ */ jsx15(DateRangeFilter, { column, value, onChange, bare });
1532
1611
  }
1533
1612
  }
1534
1613
 
@@ -1538,13 +1617,13 @@ function editErrorId(rowId, columnId) {
1538
1617
  }
1539
1618
 
1540
1619
  // src/edit/EditFieldError.tsx
1541
- import { jsx as jsx15 } from "react/jsx-runtime";
1620
+ import { jsx as jsx16 } from "react/jsx-runtime";
1542
1621
  function EditFieldError({ id, message }) {
1543
- return /* @__PURE__ */ jsx15("span", { id, className: "mt-0.5 block text-xs text-destructive", children: message });
1622
+ return /* @__PURE__ */ jsx16("span", { id, className: "mt-0.5 block text-xs text-destructive", children: message });
1544
1623
  }
1545
1624
 
1546
1625
  // src/edit/BooleanEditor.tsx
1547
- import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
1626
+ import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
1548
1627
  function toBoolean(value) {
1549
1628
  if (typeof value === "boolean") return value;
1550
1629
  if (typeof value === "string") return value.trim().toLowerCase() === "true";
@@ -1565,7 +1644,7 @@ function BooleanEditor({
1565
1644
  // `mt-0.5` already provides the same spacing every other editor gets;
1566
1645
  // adding both would double it for this one editor only.
1567
1646
  /* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center", children: [
1568
- /* @__PURE__ */ jsx16(
1647
+ /* @__PURE__ */ jsx17(
1569
1648
  Checkbox,
1570
1649
  {
1571
1650
  "aria-label": `Edit ${column.header}`,
@@ -1577,14 +1656,14 @@ function BooleanEditor({
1577
1656
  onCheckedChange: (next) => onChange(next === true)
1578
1657
  }
1579
1658
  ),
1580
- error && /* @__PURE__ */ jsx16(EditFieldError, { id: errorId, message: error })
1659
+ error && /* @__PURE__ */ jsx17(EditFieldError, { id: errorId, message: error })
1581
1660
  ] })
1582
1661
  );
1583
1662
  }
1584
1663
 
1585
1664
  // src/edit/DateEditor.tsx
1586
1665
  import { format as formatDate, parseISO as parseISO4 } from "date-fns";
1587
- import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
1666
+ import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
1588
1667
  function inputValueOf(value, columnType) {
1589
1668
  const date = toDate(value);
1590
1669
  if (!date) return "";
@@ -1600,7 +1679,7 @@ function DateEditor({
1600
1679
  }) {
1601
1680
  const errorId = editErrorId(rowId, column.id);
1602
1681
  return /* @__PURE__ */ jsxs10("div", { children: [
1603
- /* @__PURE__ */ jsx17(
1682
+ /* @__PURE__ */ jsx18(
1604
1683
  Input,
1605
1684
  {
1606
1685
  type: column.type === "datetime" ? "datetime-local" : "date",
@@ -1615,12 +1694,12 @@ function DateEditor({
1615
1694
  onChange: (event) => onChange(event.target.value === "" ? null : parseISO4(event.target.value))
1616
1695
  }
1617
1696
  ),
1618
- error && /* @__PURE__ */ jsx17(EditFieldError, { id: errorId, message: error })
1697
+ error && /* @__PURE__ */ jsx18(EditFieldError, { id: errorId, message: error })
1619
1698
  ] });
1620
1699
  }
1621
1700
 
1622
1701
  // src/edit/EnumEditor.tsx
1623
- import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
1702
+ import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
1624
1703
  function EnumEditor({
1625
1704
  column,
1626
1705
  rowId,
@@ -1641,7 +1720,7 @@ function EnumEditor({
1641
1720
  open,
1642
1721
  onOpenChange,
1643
1722
  children: [
1644
- /* @__PURE__ */ jsx18(
1723
+ /* @__PURE__ */ jsx19(
1645
1724
  SelectTrigger,
1646
1725
  {
1647
1726
  className: "h-8",
@@ -1650,14 +1729,14 @@ function EnumEditor({
1650
1729
  "aria-describedby": error ? errorId : void 0,
1651
1730
  "data-testid": `edit-${rowId}-${column.id}`,
1652
1731
  autoFocus,
1653
- children: /* @__PURE__ */ jsx18(SelectValue, {})
1732
+ children: /* @__PURE__ */ jsx19(SelectValue, {})
1654
1733
  }
1655
1734
  ),
1656
- /* @__PURE__ */ jsx18(SelectContent, { children: column.options.map((option) => /* @__PURE__ */ jsx18(SelectItem, { value: option.value, children: option.label }, option.value)) })
1735
+ /* @__PURE__ */ jsx19(SelectContent, { children: column.options.map((option) => /* @__PURE__ */ jsx19(SelectItem, { value: option.value, children: option.label }, option.value)) })
1657
1736
  ]
1658
1737
  }
1659
1738
  ),
1660
- error && /* @__PURE__ */ jsx18(EditFieldError, { id: errorId, message: error })
1739
+ error && /* @__PURE__ */ jsx19(EditFieldError, { id: errorId, message: error })
1661
1740
  ] });
1662
1741
  }
1663
1742
 
@@ -1666,9 +1745,9 @@ import { useLayoutEffect, useRef as useRef5 } from "react";
1666
1745
 
1667
1746
  // src/components/ui/textarea.tsx
1668
1747
  import { forwardRef as forwardRef6 } from "react";
1669
- import { jsx as jsx19 } from "react/jsx-runtime";
1748
+ import { jsx as jsx20 } from "react/jsx-runtime";
1670
1749
  var Textarea = forwardRef6(({ className, ...props }, ref) => {
1671
- return /* @__PURE__ */ jsx19(
1750
+ return /* @__PURE__ */ jsx20(
1672
1751
  "textarea",
1673
1752
  {
1674
1753
  className: cn(
@@ -1683,7 +1762,7 @@ var Textarea = forwardRef6(({ className, ...props }, ref) => {
1683
1762
  Textarea.displayName = "Textarea";
1684
1763
 
1685
1764
  // src/edit/MultilineStringEditor.tsx
1686
- import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
1765
+ import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
1687
1766
  function MultilineStringEditor({
1688
1767
  column,
1689
1768
  rowId,
@@ -1707,7 +1786,7 @@ function MultilineStringEditor({
1707
1786
  }
1708
1787
  }, [text]);
1709
1788
  return /* @__PURE__ */ jsxs12("div", { children: [
1710
- /* @__PURE__ */ jsx20(
1789
+ /* @__PURE__ */ jsx21(
1711
1790
  Textarea,
1712
1791
  {
1713
1792
  ref: textareaRef,
@@ -1724,13 +1803,13 @@ function MultilineStringEditor({
1724
1803
  }
1725
1804
  }
1726
1805
  ),
1727
- error && /* @__PURE__ */ jsx20(EditFieldError, { id: errorId, message: error })
1806
+ error && /* @__PURE__ */ jsx21(EditFieldError, { id: errorId, message: error })
1728
1807
  ] });
1729
1808
  }
1730
1809
 
1731
1810
  // src/edit/NumberEditor.tsx
1732
1811
  import { useEffect as useEffect6, useRef as useRef6, useState as useState6 } from "react";
1733
- import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
1812
+ import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
1734
1813
  function textFromValue(value) {
1735
1814
  return value === null || value === void 0 ? "" : String(value);
1736
1815
  }
@@ -1751,7 +1830,7 @@ function NumberEditor({
1751
1830
  setText(textFromValue(value));
1752
1831
  }, [value]);
1753
1832
  return /* @__PURE__ */ jsxs13("div", { children: [
1754
- /* @__PURE__ */ jsx21(
1833
+ /* @__PURE__ */ jsx22(
1755
1834
  Input,
1756
1835
  {
1757
1836
  type: "number",
@@ -1770,12 +1849,12 @@ function NumberEditor({
1770
1849
  }
1771
1850
  }
1772
1851
  ),
1773
- error && /* @__PURE__ */ jsx21(EditFieldError, { id: errorId, message: error })
1852
+ error && /* @__PURE__ */ jsx22(EditFieldError, { id: errorId, message: error })
1774
1853
  ] });
1775
1854
  }
1776
1855
 
1777
1856
  // src/edit/StringEditor.tsx
1778
- import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
1857
+ import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
1779
1858
  function StringEditor({
1780
1859
  column,
1781
1860
  rowId,
@@ -1786,7 +1865,7 @@ function StringEditor({
1786
1865
  }) {
1787
1866
  const errorId = editErrorId(rowId, column.id);
1788
1867
  return /* @__PURE__ */ jsxs14("div", { children: [
1789
- /* @__PURE__ */ jsx22(
1868
+ /* @__PURE__ */ jsx23(
1790
1869
  Input,
1791
1870
  {
1792
1871
  className: "h-8",
@@ -1799,26 +1878,26 @@ function StringEditor({
1799
1878
  onChange: (event) => onChange(event.target.value)
1800
1879
  }
1801
1880
  ),
1802
- error && /* @__PURE__ */ jsx22(EditFieldError, { id: errorId, message: error })
1881
+ error && /* @__PURE__ */ jsx23(EditFieldError, { id: errorId, message: error })
1803
1882
  ] });
1804
1883
  }
1805
1884
 
1806
1885
  // src/edit/registry.tsx
1807
- import { jsx as jsx23 } from "react/jsx-runtime";
1886
+ import { jsx as jsx24 } from "react/jsx-runtime";
1808
1887
  function renderDefaultEditWidget(column, rowId, value, onChange, error, autoFocus) {
1809
1888
  switch (column.type) {
1810
1889
  case "string":
1811
- return column.multiline ? /* @__PURE__ */ jsx23(MultilineStringEditor, { column, rowId, value, onChange, error, autoFocus }) : /* @__PURE__ */ jsx23(StringEditor, { column, rowId, value, onChange, error, autoFocus });
1890
+ return column.multiline ? /* @__PURE__ */ jsx24(MultilineStringEditor, { column, rowId, value, onChange, error, autoFocus }) : /* @__PURE__ */ jsx24(StringEditor, { column, rowId, value, onChange, error, autoFocus });
1812
1891
  case "enum":
1813
- return /* @__PURE__ */ jsx23(EnumEditor, { column, rowId, value, onChange, error, autoFocus });
1892
+ return /* @__PURE__ */ jsx24(EnumEditor, { column, rowId, value, onChange, error, autoFocus });
1814
1893
  case "boolean":
1815
- return /* @__PURE__ */ jsx23(BooleanEditor, { column, rowId, value, onChange, error, autoFocus });
1894
+ return /* @__PURE__ */ jsx24(BooleanEditor, { column, rowId, value, onChange, error, autoFocus });
1816
1895
  case "number":
1817
1896
  case "currency":
1818
- return /* @__PURE__ */ jsx23(NumberEditor, { column, rowId, value, onChange, error, autoFocus });
1897
+ return /* @__PURE__ */ jsx24(NumberEditor, { column, rowId, value, onChange, error, autoFocus });
1819
1898
  case "date":
1820
1899
  case "datetime":
1821
- return /* @__PURE__ */ jsx23(DateEditor, { column, rowId, value, onChange, error, autoFocus });
1900
+ return /* @__PURE__ */ jsx24(DateEditor, { column, rowId, value, onChange, error, autoFocus });
1822
1901
  }
1823
1902
  }
1824
1903
 
@@ -1931,7 +2010,7 @@ function useEditingState(editing, getRowId) {
1931
2010
  }
1932
2011
 
1933
2012
  // src/edit/renderEditableCell.tsx
1934
- import { jsx as jsx24 } from "react/jsx-runtime";
2013
+ import { jsx as jsx25 } from "react/jsx-runtime";
1935
2014
  function renderEditableCell(column, row, rawValue, ctx) {
1936
2015
  const staticContent = (value2) => column.cell ? column.cell(value2, row) : defaultFormat(column, value2);
1937
2016
  if (!ctx || !isEditable(column, row)) return staticContent(rawValue);
@@ -1943,7 +2022,7 @@ function renderEditableCell(column, row, rawValue, ctx) {
1943
2022
  const autoFocus = ctx.autoFocusTarget?.rowId === rowId && ctx.autoFocusTarget.columnId === column.id;
1944
2023
  const onChange = (next) => ctx.onEdit(column, row, next);
1945
2024
  const editor = column.renderEditCell ? column.renderEditCell(value, row, onChange, error, autoFocus) : renderDefaultEditWidget(column, rowId, value, onChange, error, autoFocus);
1946
- return /* @__PURE__ */ jsx24(
2025
+ return /* @__PURE__ */ jsx25(
1947
2026
  "div",
1948
2027
  {
1949
2028
  onKeyDown: (event) => {
@@ -1956,7 +2035,7 @@ function renderEditableCell(column, row, rawValue, ctx) {
1956
2035
  }
1957
2036
  );
1958
2037
  }
1959
- return /* @__PURE__ */ jsx24(
2038
+ return /* @__PURE__ */ jsx25(
1960
2039
  "span",
1961
2040
  {
1962
2041
  role: "button",
@@ -1979,7 +2058,7 @@ function renderEditableCell(column, row, rawValue, ctx) {
1979
2058
  }
1980
2059
 
1981
2060
  // src/edit/EditingBar.tsx
1982
- import { jsx as jsx25, jsxs as jsxs15 } from "react/jsx-runtime";
2061
+ import { jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
1983
2062
  function resolveEditLabel(label, changedRowCount, fallback) {
1984
2063
  if (label === void 0) return fallback(changedRowCount);
1985
2064
  return typeof label === "function" ? label(changedRowCount) : label;
@@ -2017,7 +2096,7 @@ function EditingBar({
2017
2096
  ] })
2018
2097
  ] }),
2019
2098
  /* @__PURE__ */ jsxs15("div", { className: "flex gap-2", children: [
2020
- /* @__PURE__ */ jsx25(
2099
+ /* @__PURE__ */ jsx26(
2021
2100
  Button,
2022
2101
  {
2023
2102
  type: "button",
@@ -2029,7 +2108,7 @@ function EditingBar({
2029
2108
  children: resolveEditLabel(editing.discardLabel, pendingRowCount, () => "Discard")
2030
2109
  }
2031
2110
  ),
2032
- /* @__PURE__ */ jsx25(
2111
+ /* @__PURE__ */ jsx26(
2033
2112
  Button,
2034
2113
  {
2035
2114
  type: "button",
@@ -2131,15 +2210,15 @@ function extendRangeForFillToCellRange(base, target, rowIds, columnIds, rowIndex
2131
2210
  }
2132
2211
 
2133
2212
  // src/cell-editing/useCellSelection.ts
2134
- import { useCallback as useCallback2, useMemo as useMemo3, useRef as useRef8, useState as useState8 } from "react";
2213
+ import { useCallback as useCallback2, useMemo as useMemo4, useRef as useRef8, useState as useState8 } from "react";
2135
2214
  function useCellSelection({ rowIds, columnIds, onNavigateToRow }) {
2136
2215
  const [selection, setSelectionState] = useState8(void 0);
2137
2216
  const [isDragging, setIsDragging] = useState8(false);
2138
2217
  const [dragFocus, setDragFocus] = useState8(void 0);
2139
2218
  const draggingRef = useRef8(false);
2140
2219
  const dragFocusRef = useRef8(void 0);
2141
- const rowIndex = useMemo3(() => buildIndexMap(rowIds), [rowIds]);
2142
- const columnIndex = useMemo3(() => buildIndexMap(columnIds), [columnIds]);
2220
+ const rowIndex = useMemo4(() => buildIndexMap(rowIds), [rowIds]);
2221
+ const columnIndex = useMemo4(() => buildIndexMap(columnIds), [columnIds]);
2143
2222
  const startSelection = useCallback2((cell, options) => {
2144
2223
  setSelectionState((prev) => options?.extend && prev ? { anchor: prev.anchor, focus: cell } : { anchor: cell, focus: cell });
2145
2224
  draggingRef.current = true;
@@ -2193,7 +2272,7 @@ function useCellSelection({ rowIds, columnIds, onNavigateToRow }) {
2193
2272
  setDragFocus(void 0);
2194
2273
  setSelectionState(void 0);
2195
2274
  }, []);
2196
- const effectiveRange = useMemo3(() => {
2275
+ const effectiveRange = useMemo4(() => {
2197
2276
  if (!selection) return void 0;
2198
2277
  if (isDragging && dragFocus) return { anchor: selection.anchor, focus: dragFocus };
2199
2278
  return selection;
@@ -2229,7 +2308,7 @@ function useCellSelection({ rowIds, columnIds, onNavigateToRow }) {
2229
2308
  setSelectionState(finalRange);
2230
2309
  return { sourceRange, finalRange };
2231
2310
  }, [rowIds, columnIds, rowIndex, columnIndex]);
2232
- const fillPreviewRange = useMemo3(() => {
2311
+ const fillPreviewRange = useMemo4(() => {
2233
2312
  if (!isFillDragging || !selection || !fillTarget) return void 0;
2234
2313
  return extendRangeForFillToCellRange(selection, fillTarget, rowIds, columnIds, rowIndex, columnIndex);
2235
2314
  }, [isFillDragging, selection, fillTarget, rowIds, columnIds, rowIndex, columnIndex]);
@@ -2367,7 +2446,7 @@ function useCellEditingState(cellEditing, getRowId) {
2367
2446
  }
2368
2447
 
2369
2448
  // src/cell-editing/renderCellModeCell.tsx
2370
- import { jsx as jsx26 } from "react/jsx-runtime";
2449
+ import { jsx as jsx27 } from "react/jsx-runtime";
2371
2450
  function isAtomicEditorType(type) {
2372
2451
  return type === "enum" || type === "boolean" || type === "date" || type === "datetime";
2373
2452
  }
@@ -2378,7 +2457,7 @@ function renderCellModeCell(column, row, rawValue, ctx) {
2378
2457
  const value = ctx.resolveValue(rowId, column.id, rawValue);
2379
2458
  const isThisCellEditing = ctx.editingCell?.rowId === rowId && ctx.editingCell.columnId === column.id && isEditable(column, row);
2380
2459
  if (!isThisCellEditing) {
2381
- return /* @__PURE__ */ jsx26("span", { "data-testid": `cell-${rowId}-${column.id}`, className: "block w-full", children: staticContent(value) });
2460
+ return /* @__PURE__ */ jsx27("span", { "data-testid": `cell-${rowId}-${column.id}`, className: "block w-full", children: staticContent(value) });
2382
2461
  }
2383
2462
  const isAtomic = isAtomicEditorType(column.type);
2384
2463
  const error = ctx.getError(rowId, column.id);
@@ -2418,12 +2497,12 @@ function renderCellModeCell(column, row, rawValue, ctx) {
2418
2497
  if (validate(currentValue)) ctx.onCancelEdit();
2419
2498
  else ctx.onCommitEdit(row, value);
2420
2499
  }
2421
- return /* @__PURE__ */ jsx26("div", { onKeyDown: handleKeyDown, onBlur: handleBlur, children: editor });
2500
+ return /* @__PURE__ */ jsx27("div", { onKeyDown: handleKeyDown, onBlur: handleBlur, children: editor });
2422
2501
  }
2423
2502
 
2424
2503
  // src/cell-editing/SelectionOverlay.tsx
2425
2504
  import { useLayoutEffect as useLayoutEffect2, useRef as useRef10, useState as useState10 } from "react";
2426
- import { Fragment as Fragment2, jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
2505
+ import { Fragment as Fragment2, jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
2427
2506
  function cellSelector(rowId, columnId) {
2428
2507
  const escape = (value) => typeof CSS !== "undefined" && CSS.escape ? CSS.escape(value) : value.replace(/["\\]/g, "\\$&");
2429
2508
  return `[data-cell-row="${escape(rowId)}"][data-cell-col="${escape(columnId)}"]`;
@@ -2478,7 +2557,7 @@ function SelectionOverlay({
2478
2557
  }, [containerRef.current]);
2479
2558
  if (!rect) return null;
2480
2559
  return /* @__PURE__ */ jsxs16(Fragment2, { children: [
2481
- /* @__PURE__ */ jsx27(
2560
+ /* @__PURE__ */ jsx28(
2482
2561
  "div",
2483
2562
  {
2484
2563
  "data-testid": "cell-selection-overlay",
@@ -2487,7 +2566,7 @@ function SelectionOverlay({
2487
2566
  style: { top: rect.top, left: rect.left, width: rect.width, height: rect.height }
2488
2567
  }
2489
2568
  ),
2490
- previewRect && /* @__PURE__ */ jsx27(
2569
+ previewRect && /* @__PURE__ */ jsx28(
2491
2570
  "div",
2492
2571
  {
2493
2572
  "data-testid": "cell-fill-preview-overlay",
@@ -2496,7 +2575,7 @@ function SelectionOverlay({
2496
2575
  style: { top: previewRect.top, left: previewRect.left, width: previewRect.width, height: previewRect.height }
2497
2576
  }
2498
2577
  ),
2499
- onFillHandleMouseDown && /* @__PURE__ */ jsx27(
2578
+ onFillHandleMouseDown && /* @__PURE__ */ jsx28(
2500
2579
  "div",
2501
2580
  {
2502
2581
  "data-testid": "cell-fill-handle",
@@ -2708,10 +2787,10 @@ import { useEffect as useEffect8, useState as useState11 } from "react";
2708
2787
  import * as DialogPrimitive from "@radix-ui/react-dialog";
2709
2788
  import { X } from "lucide-react";
2710
2789
  import { forwardRef as forwardRef7 } from "react";
2711
- import { jsx as jsx28, jsxs as jsxs17 } from "react/jsx-runtime";
2790
+ import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
2712
2791
  var Dialog = DialogPrimitive.Root;
2713
2792
  var DialogTrigger = DialogPrimitive.Trigger;
2714
- var DialogOverlay = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */ jsx28(
2793
+ var DialogOverlay = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */ jsx29(
2715
2794
  DialogPrimitive.Overlay,
2716
2795
  {
2717
2796
  ref,
@@ -2721,7 +2800,7 @@ var DialogOverlay = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ *
2721
2800
  ));
2722
2801
  DialogOverlay.displayName = "DialogOverlay";
2723
2802
  var DialogContent = forwardRef7(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs17(DialogPrimitive.Portal, { children: [
2724
- /* @__PURE__ */ jsx28(DialogOverlay, {}),
2803
+ /* @__PURE__ */ jsx29(DialogOverlay, {}),
2725
2804
  /* @__PURE__ */ jsxs17(
2726
2805
  DialogPrimitive.Content,
2727
2806
  {
@@ -2734,8 +2813,8 @@ var DialogContent = forwardRef7(({ className, children, ...props }, ref) => /* @
2734
2813
  children: [
2735
2814
  children,
2736
2815
  /* @__PURE__ */ jsxs17(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100", children: [
2737
- /* @__PURE__ */ jsx28(X, { className: "h-4 w-4" }),
2738
- /* @__PURE__ */ jsx28("span", { className: "sr-only", children: "Close" })
2816
+ /* @__PURE__ */ jsx29(X, { className: "h-4 w-4" }),
2817
+ /* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Close" })
2739
2818
  ] })
2740
2819
  ]
2741
2820
  }
@@ -2745,10 +2824,10 @@ DialogContent.displayName = "DialogContent";
2745
2824
  var DialogHeader = ({
2746
2825
  className,
2747
2826
  ...props
2748
- }) => /* @__PURE__ */ jsx28("div", { className: cn("flex flex-col gap-1.5", className), ...props });
2749
- var DialogTitle = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */ jsx28(DialogPrimitive.Title, { ref, className: cn("text-lg font-semibold", className), ...props }));
2827
+ }) => /* @__PURE__ */ jsx29("div", { className: cn("flex flex-col gap-1.5", className), ...props });
2828
+ var DialogTitle = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */ jsx29(DialogPrimitive.Title, { ref, className: cn("text-lg font-semibold", className), ...props }));
2750
2829
  DialogTitle.displayName = "DialogTitle";
2751
- var DialogDescription = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */ jsx28(
2830
+ var DialogDescription = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */ jsx29(
2752
2831
  DialogPrimitive.Description,
2753
2832
  {
2754
2833
  ref,
@@ -2857,7 +2936,7 @@ function canHideGroup(columns, visibility, groupColumnIds) {
2857
2936
  }
2858
2937
 
2859
2938
  // src/column-selector/ColumnSelector.tsx
2860
- import { jsx as jsx29, jsxs as jsxs18 } from "react/jsx-runtime";
2939
+ import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
2861
2940
  function ColumnSelector({
2862
2941
  columns,
2863
2942
  visibility,
@@ -2903,11 +2982,11 @@ function ColumnSelector({
2903
2982
  if (persistKey) writePersistedColumnOrder(persistKey, next);
2904
2983
  }
2905
2984
  return /* @__PURE__ */ jsxs18(Dialog, { open, onOpenChange, children: [
2906
- /* @__PURE__ */ jsx29(DialogTrigger, { asChild: true, children: trigger ?? /* @__PURE__ */ jsx29(Button, { variant: "outline", size: "icon", "aria-label": "Choose columns", children: /* @__PURE__ */ jsx29(Columns3, { className: "h-4 w-4", "aria-hidden": true }) }) }),
2985
+ /* @__PURE__ */ jsx30(DialogTrigger, { asChild: true, children: trigger ?? /* @__PURE__ */ jsx30(Button, { variant: "outline", size: "icon", "aria-label": "Choose columns", children: /* @__PURE__ */ jsx30(Columns3, { className: "h-4 w-4", "aria-hidden": true }) }) }),
2907
2986
  /* @__PURE__ */ jsxs18(DialogContent, { className: "w-fit max-w-[calc(100vw-2rem)] sm:max-w-2xl", children: [
2908
- /* @__PURE__ */ jsx29(DialogHeader, { children: /* @__PURE__ */ jsx29(DialogTitle, { children: "Columns" }) }),
2909
- /* @__PURE__ */ jsx29("div", { className: "flex flex-wrap gap-x-8 gap-y-5", children: groups.map(({ group, columns: groupCols }) => /* @__PURE__ */ jsxs18("div", { className: "flex min-w-32 flex-col gap-1.5", children: [
2910
- group && /* @__PURE__ */ jsx29("span", { className: "border-b pb-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: group }),
2987
+ /* @__PURE__ */ jsx30(DialogHeader, { children: /* @__PURE__ */ jsx30(DialogTitle, { children: "Columns" }) }),
2988
+ /* @__PURE__ */ jsx30("div", { className: "flex flex-wrap gap-x-8 gap-y-5", children: groups.map(({ group, columns: groupCols }) => /* @__PURE__ */ jsxs18("div", { className: "flex min-w-32 flex-col gap-1.5", children: [
2989
+ group && /* @__PURE__ */ jsx30("span", { className: "border-b pb-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: group }),
2911
2990
  groupCols.map((column) => {
2912
2991
  const visible = isColumnVisible(visibility, column.id);
2913
2992
  return /* @__PURE__ */ jsxs18(
@@ -2937,14 +3016,14 @@ function ColumnSelector({
2937
3016
  overId === column.id && draggedId !== null && draggedId !== column.id && "outline -outline-offset-2 outline-2 outline-primary"
2938
3017
  ),
2939
3018
  children: [
2940
- canReorder && /* @__PURE__ */ jsx29(
3019
+ canReorder && /* @__PURE__ */ jsx30(
2941
3020
  GripVertical,
2942
3021
  {
2943
3022
  className: "h-3.5 w-3.5 shrink-0 text-muted-foreground/50",
2944
3023
  "aria-hidden": true
2945
3024
  }
2946
3025
  ),
2947
- /* @__PURE__ */ jsx29(
3026
+ /* @__PURE__ */ jsx30(
2948
3027
  Checkbox,
2949
3028
  {
2950
3029
  checked: visible,
@@ -2976,15 +3055,15 @@ function resolveMenuItems(items, ctx) {
2976
3055
 
2977
3056
  // src/menu/ActionsMenu.tsx
2978
3057
  import { MoreVertical } from "lucide-react";
2979
- import { useMemo as useMemo4 } from "react";
3058
+ import { useMemo as useMemo5 } from "react";
2980
3059
 
2981
3060
  // src/components/ui/dropdown-menu.tsx
2982
3061
  import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
2983
3062
  import { forwardRef as forwardRef8 } from "react";
2984
- import { jsx as jsx30 } from "react/jsx-runtime";
3063
+ import { jsx as jsx31 } from "react/jsx-runtime";
2985
3064
  var DropdownMenu = DropdownMenuPrimitive.Root;
2986
3065
  var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
2987
- var DropdownMenuContent = forwardRef8(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx30(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx30(
3066
+ var DropdownMenuContent = forwardRef8(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx31(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx31(
2988
3067
  DropdownMenuPrimitive.Content,
2989
3068
  {
2990
3069
  ref,
@@ -2997,7 +3076,7 @@ var DropdownMenuContent = forwardRef8(({ className, sideOffset = 4, ...props },
2997
3076
  }
2998
3077
  ) }));
2999
3078
  DropdownMenuContent.displayName = "DropdownMenuContent";
3000
- var DropdownMenuItem = forwardRef8(({ className, danger, ...props }, ref) => /* @__PURE__ */ jsx30(
3079
+ var DropdownMenuItem = forwardRef8(({ className, danger, ...props }, ref) => /* @__PURE__ */ jsx31(
3001
3080
  DropdownMenuPrimitive.Item,
3002
3081
  {
3003
3082
  ref,
@@ -3010,7 +3089,7 @@ var DropdownMenuItem = forwardRef8(({ className, danger, ...props }, ref) => /*
3010
3089
  }
3011
3090
  ));
3012
3091
  DropdownMenuItem.displayName = "DropdownMenuItem";
3013
- var DropdownMenuSeparator = forwardRef8(({ className, ...props }, ref) => /* @__PURE__ */ jsx30(
3092
+ var DropdownMenuSeparator = forwardRef8(({ className, ...props }, ref) => /* @__PURE__ */ jsx31(
3014
3093
  DropdownMenuPrimitive.Separator,
3015
3094
  {
3016
3095
  ref,
@@ -3019,7 +3098,7 @@ var DropdownMenuSeparator = forwardRef8(({ className, ...props }, ref) => /* @__
3019
3098
  }
3020
3099
  ));
3021
3100
  DropdownMenuSeparator.displayName = "DropdownMenuSeparator";
3022
- var DropdownMenuLabel = forwardRef8(({ className, ...props }, ref) => /* @__PURE__ */ jsx30(
3101
+ var DropdownMenuLabel = forwardRef8(({ className, ...props }, ref) => /* @__PURE__ */ jsx31(
3023
3102
  DropdownMenuPrimitive.Label,
3024
3103
  {
3025
3104
  ref,
@@ -3030,16 +3109,16 @@ var DropdownMenuLabel = forwardRef8(({ className, ...props }, ref) => /* @__PURE
3030
3109
  DropdownMenuLabel.displayName = "DropdownMenuLabel";
3031
3110
 
3032
3111
  // src/menu/ActionsMenu.tsx
3033
- import { jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
3112
+ import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
3034
3113
  function ActionsMenu({ items, ctx, triggerLabel }) {
3035
- const resolved = useMemo4(
3114
+ const resolved = useMemo5(
3036
3115
  () => resolveMenuItems(items, ctx),
3037
3116
  [items, ctx.row, ctx.selectedRows]
3038
3117
  );
3039
3118
  if (resolved.length === 0) return null;
3040
3119
  return /* @__PURE__ */ jsxs19(DropdownMenu, { children: [
3041
- /* @__PURE__ */ jsx31(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx31(Button, { variant: "ghost", size: "icon", "aria-label": triggerLabel, onClick: stopRowClick, children: /* @__PURE__ */ jsx31(MoreVertical, { className: "h-4 w-4", "aria-hidden": true }) }) }),
3042
- /* @__PURE__ */ jsx31(DropdownMenuContent, { align: "end", children: resolved.map((item) => /* @__PURE__ */ jsx31(
3120
+ /* @__PURE__ */ jsx32(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx32(Button, { variant: "ghost", size: "icon", "aria-label": triggerLabel, onClick: stopRowClick, children: /* @__PURE__ */ jsx32(MoreVertical, { className: "h-4 w-4", "aria-hidden": true }) }) }),
3121
+ /* @__PURE__ */ jsx32(DropdownMenuContent, { align: "end", children: resolved.map((item) => /* @__PURE__ */ jsx32(
3043
3122
  DropdownMenuItem,
3044
3123
  {
3045
3124
  danger: item.danger,
@@ -3057,14 +3136,14 @@ import { BarsArrowDownIcon, BarsArrowUpIcon, FunnelIcon as FunnelIcon7 } from "@
3057
3136
  import { columnResizingFeature, columnSizingFeature, flexRender, tableFeatures, useTable } from "@tanstack/react-table";
3058
3137
  import { useVirtualizer } from "@tanstack/react-virtual";
3059
3138
  import { ChevronRight, Loader2 } from "lucide-react";
3060
- import { Fragment as Fragment3, useEffect as useEffect12, useMemo as useMemo8, useRef as useRef13, useState as useState16 } from "react";
3139
+ import { Fragment as Fragment3, useEffect as useEffect12, useMemo as useMemo9, useRef as useRef13, useState as useState16 } from "react";
3061
3140
 
3062
3141
  // src/cell-editing/renderAlwaysEditCell.tsx
3063
3142
  import {
3064
3143
  useEffect as useEffect9,
3065
3144
  useState as useState12
3066
3145
  } from "react";
3067
- import { jsx as jsx32 } from "react/jsx-runtime";
3146
+ import { jsx as jsx33 } from "react/jsx-runtime";
3068
3147
  function AlwaysEditCell(props) {
3069
3148
  const { column, row, rawValue, ctx, atomicGesture } = props;
3070
3149
  const rowId = ctx.getRowId(row);
@@ -3077,7 +3156,7 @@ function AlwaysEditCell(props) {
3077
3156
  if (shouldOpenEnumNow) setEnumOpen(true);
3078
3157
  }, [shouldOpenEnumNow]);
3079
3158
  if (!isEditable(column, row)) {
3080
- return /* @__PURE__ */ jsx32("span", { "data-testid": `cell-${rowId}-${column.id}`, className: "block w-full", children: column.cell ? column.cell(resolvedValue, row) : defaultFormat(column, resolvedValue) });
3159
+ return /* @__PURE__ */ jsx33("span", { "data-testid": `cell-${rowId}-${column.id}`, className: "block w-full", children: column.cell ? column.cell(resolvedValue, row) : defaultFormat(column, resolvedValue) });
3081
3160
  }
3082
3161
  const isAtomic = isAtomicEditorType(column.type);
3083
3162
  const error = ctx.getError(rowId, column.id);
@@ -3144,7 +3223,7 @@ function AlwaysEditCell(props) {
3144
3223
  handleModifierCapture(event);
3145
3224
  handleEnumOpenCapture(event);
3146
3225
  }
3147
- return /* @__PURE__ */ jsx32(
3226
+ return /* @__PURE__ */ jsx33(
3148
3227
  "fieldset",
3149
3228
  {
3150
3229
  disabled: ctx.disabled,
@@ -3153,7 +3232,7 @@ function AlwaysEditCell(props) {
3153
3232
  onPointerDownCapture: handlePointerDownCapture,
3154
3233
  onClickCapture: handleClickCapture,
3155
3234
  className: "contents",
3156
- children: column.type === "enum" && !column.renderEditCell ? /* @__PURE__ */ jsx32(
3235
+ children: column.type === "enum" && !column.renderEditCell ? /* @__PURE__ */ jsx33(
3157
3236
  EnumEditor,
3158
3237
  {
3159
3238
  column,
@@ -3214,9 +3293,9 @@ function useStickyGroupHeaderTop(enabled) {
3214
3293
  }
3215
3294
 
3216
3295
  // src/hooks/useVisibleColumns.ts
3217
- import { useMemo as useMemo5 } from "react";
3296
+ import { useMemo as useMemo6 } from "react";
3218
3297
  function useVisibleColumns(columns, columnVisibility) {
3219
- return useMemo5(
3298
+ return useMemo6(
3220
3299
  () => columnVisibility ? columns.filter((column) => isColumnVisible(columnVisibility, column.id)) : columns,
3221
3300
  [columns, columnVisibility]
3222
3301
  );
@@ -3263,10 +3342,10 @@ function processClientData(data, state) {
3263
3342
  }
3264
3343
 
3265
3344
  // src/grid/useGridState.ts
3266
- import { useCallback as useCallback4, useEffect as useEffect11, useMemo as useMemo7, useState as useState15 } from "react";
3345
+ import { useCallback as useCallback4, useEffect as useEffect11, useMemo as useMemo8, useState as useState15 } from "react";
3267
3346
 
3268
3347
  // src/hooks/useDebouncedCallback.ts
3269
- import { useEffect as useEffect10, useMemo as useMemo6, useRef as useRef12 } from "react";
3348
+ import { useEffect as useEffect10, useMemo as useMemo7, useRef as useRef12 } from "react";
3270
3349
  function useDebouncedCallback(callback, delayMs) {
3271
3350
  const callbackRef = useRef12(callback);
3272
3351
  callbackRef.current = callback;
@@ -3276,7 +3355,7 @@ function useDebouncedCallback(callback, delayMs) {
3276
3355
  clearTimeout(timeoutRef.current);
3277
3356
  };
3278
3357
  }, []);
3279
- return useMemo6(() => {
3358
+ return useMemo7(() => {
3280
3359
  return {
3281
3360
  run: (...args) => {
3282
3361
  clearTimeout(timeoutRef.current);
@@ -3329,7 +3408,7 @@ function useGridState(dataSource, initialState, externalState, showPagination =
3329
3408
  cancelDebouncedNotify();
3330
3409
  setState(externalState);
3331
3410
  }, [externalState, cancelDebouncedNotify]);
3332
- const filtersByColumn = useMemo7(() => {
3411
+ const filtersByColumn = useMemo8(() => {
3333
3412
  const map = /* @__PURE__ */ new Map();
3334
3413
  for (const child of state.filter?.filters ?? []) {
3335
3414
  if ("operator" in child) map.set(fieldKey(child.field), child);
@@ -3393,7 +3472,7 @@ function useGridState(dataSource, initialState, externalState, showPagination =
3393
3472
  }
3394
3473
 
3395
3474
  // src/grid/DataGrid.tsx
3396
- import { Fragment as Fragment4, jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
3475
+ import { Fragment as Fragment4, jsx as jsx34, jsxs as jsxs20 } from "react/jsx-runtime";
3397
3476
  var gridTableFeatures = tableFeatures({ columnSizingFeature, columnResizingFeature });
3398
3477
  var DEFAULT_COLUMN_SIZE = 150;
3399
3478
  var MIN_COLUMN_SIZE = 40;
@@ -3444,7 +3523,7 @@ function toTanstackColumns(columns, editingCtxRef, cellEditingCtxRef, atomicGest
3444
3523
  cell: (info) => {
3445
3524
  const cellEditingCtx = cellEditingCtxRef.current;
3446
3525
  if (!cellEditingCtx) return renderEditableCell(column, info.row.original, info.getValue(), editingCtxRef.current);
3447
- return cellEditingCtx.alwaysEdit ? /* @__PURE__ */ jsx33(
3526
+ return cellEditingCtx.alwaysEdit ? /* @__PURE__ */ jsx34(
3448
3527
  AlwaysEditCell,
3449
3528
  {
3450
3529
  column,
@@ -3489,8 +3568,10 @@ function DataGrid({
3489
3568
  zebra = true,
3490
3569
  showTotals = false,
3491
3570
  editing,
3492
- cellEditing
3571
+ cellEditing,
3572
+ filterLabels
3493
3573
  }) {
3574
+ const resolvedFilterLabels = useFilterLabels(filterLabels);
3494
3575
  const hasCellEditing = Boolean(cellEditing) && !groupBy;
3495
3576
  const { state, filtersByColumn, setColumnFilter, toggleSort, setPage } = useGridState(
3496
3577
  dataSource,
@@ -3536,11 +3617,11 @@ function DataGrid({
3536
3617
  const atomicGestureRef = useRef13(void 0);
3537
3618
  const visibleColumns = useVisibleColumns(columns, columnVisibility);
3538
3619
  const serverRowCount = dataSource.mode === "server" ? dataSource.rowCount : void 0;
3539
- const { rows, rowCount } = useMemo8(() => {
3620
+ const { rows, rowCount } = useMemo9(() => {
3540
3621
  if (dataSource.mode === "client") return processClientData(dataSource.data, state);
3541
3622
  return { rows: dataSource.data, rowCount: serverRowCount ?? 0 };
3542
3623
  }, [dataSource.mode, dataSource.data, serverRowCount, state]);
3543
- const selectedRows = useMemo8(
3624
+ const selectedRows = useMemo9(
3544
3625
  () => rows.filter((row) => selectedIds.has(getRowId(row))),
3545
3626
  [rows, selectedIds, getRowId]
3546
3627
  );
@@ -3559,11 +3640,11 @@ function DataGrid({
3559
3640
  }
3560
3641
  updateSelectedIds(next);
3561
3642
  }
3562
- const tanstackColumns = useMemo8(
3643
+ const tanstackColumns = useMemo9(
3563
3644
  () => toTanstackColumns(visibleColumns, editingCtxRef, cellEditingCtxRef, atomicGestureRef),
3564
3645
  [visibleColumns]
3565
3646
  );
3566
- const columnById = useMemo8(() => {
3647
+ const columnById = useMemo9(() => {
3567
3648
  const map = /* @__PURE__ */ new Map();
3568
3649
  for (const column of visibleColumns) map.set(column.id, column);
3569
3650
  return map;
@@ -3591,7 +3672,7 @@ function DataGrid({
3591
3672
  const showDetailColumn = Boolean(renderDetail);
3592
3673
  const totalColumnCount = visibleColumns.length + (showDetailColumn ? 1 : 0) + (showSelectionColumn ? 1 : 0) + (showRowActionsColumn ? 1 : 0);
3593
3674
  const hasFilterRow = visibleColumns.some((column) => isFilterable(column) && column.filterDisplay === "row");
3594
- const headerRuns = useMemo8(() => computeHeaderRuns(visibleColumns), [visibleColumns]);
3675
+ const headerRuns = useMemo9(() => computeHeaderRuns(visibleColumns), [visibleColumns]);
3595
3676
  const hasHeaderGroups = visibleColumns.some((column) => column.headerGroup);
3596
3677
  const hasColumnSummary = visibleColumns.some((column) => column.summary);
3597
3678
  function renderFilterWidget(column) {
@@ -3602,21 +3683,22 @@ function DataGrid({
3602
3683
  const columnSize = (columnId) => table.getColumn(columnId)?.getSize() ?? DEFAULT_COLUMN_SIZE;
3603
3684
  const leadingStructuralWidth = (showDetailColumn ? DETAIL_COLUMN_WIDTH : 0) + (showSelectionColumn ? SELECTION_COLUMN_WIDTH : 0);
3604
3685
  const trailingStructuralWidth = showRowActionsColumn ? ROW_ACTIONS_COLUMN_WIDTH : 0;
3605
- const leftPinnedOffsets = useMemo8(
3686
+ const leftPinnedOffsets = useMemo9(
3606
3687
  () => pinnedOffsets(visibleColumns, "left", columnSize, leadingStructuralWidth),
3607
3688
  [visibleColumns, columnSizing, leadingStructuralWidth]
3608
3689
  );
3609
- const rightPinnedOffsets = useMemo8(
3690
+ const rightPinnedOffsets = useMemo9(
3610
3691
  () => pinnedOffsets(visibleColumns, "right", columnSize, trailingStructuralWidth),
3611
3692
  [visibleColumns, columnSizing, trailingStructuralWidth]
3612
3693
  );
3613
3694
  function pinnedCellProps(column, area = "body") {
3614
3695
  const bg = area === "header" ? "bg-muted" : "bg-background";
3696
+ const bgOdd = area === "header" ? "bg-muted" : STRUCTURAL_ZEBRA_BG_CLASS;
3615
3697
  if (column.pinned === "left") {
3616
- return { className: `sticky z-10 ${bg}`, style: { left: leftPinnedOffsets.get(column.id), width: columnSize(column.id), minWidth: columnSize(column.id) } };
3698
+ return { className: `sticky z-10 ${bg}`, classNameOdd: `sticky z-10 ${bgOdd}`, style: { left: leftPinnedOffsets.get(column.id), width: columnSize(column.id), minWidth: columnSize(column.id) } };
3617
3699
  }
3618
3700
  if (column.pinned === "right") {
3619
- return { className: `sticky z-10 ${bg}`, style: { right: rightPinnedOffsets.get(column.id), width: columnSize(column.id), minWidth: columnSize(column.id) } };
3701
+ return { className: `sticky z-10 ${bg}`, classNameOdd: `sticky z-10 ${bgOdd}`, style: { right: rightPinnedOffsets.get(column.id), width: columnSize(column.id), minWidth: columnSize(column.id) } };
3620
3702
  }
3621
3703
  if (enableColumnResizing) return { style: { width: columnSize(column.id) } };
3622
3704
  return { style: column.width ? { width: column.width } : void 0 };
@@ -3651,10 +3733,11 @@ function DataGrid({
3651
3733
  const pinnedProps = column.pinned || enableColumnResizing ? pinnedCellProps(column) : void 0;
3652
3734
  return {
3653
3735
  className: pinnedProps?.className ? `${BODY_TD_BASE_CLASS} ${pinnedProps.className}` : BODY_TD_BASE_CLASS,
3736
+ classNameOdd: pinnedProps?.classNameOdd ? `${BODY_TD_BASE_CLASS} ${pinnedProps.classNameOdd}` : BODY_TD_BASE_CLASS,
3654
3737
  style: pinnedProps?.style
3655
3738
  };
3656
3739
  }
3657
- const bodyCellPropsByColumn = useMemo8(() => {
3740
+ const bodyCellPropsByColumn = useMemo9(() => {
3658
3741
  const map = /* @__PURE__ */ new Map();
3659
3742
  for (const column of visibleColumns) map.set(column.id, bodyCellClassAndStyle(column));
3660
3743
  return map;
@@ -3670,7 +3753,7 @@ function DataGrid({
3670
3753
  );
3671
3754
  return { className, style: pinnedProps.style };
3672
3755
  }
3673
- const leafHeaderCellPropsByColumn = useMemo8(() => {
3756
+ const leafHeaderCellPropsByColumn = useMemo9(() => {
3674
3757
  const map = /* @__PURE__ */ new Map();
3675
3758
  for (const column of visibleColumns) {
3676
3759
  map.set(
@@ -3680,7 +3763,7 @@ function DataGrid({
3680
3763
  }
3681
3764
  return map;
3682
3765
  }, [visibleColumns, enableColumnResizing, leftPinnedOffsets, rightPinnedOffsets, columnSizing]);
3683
- const filterHeaderCellPropsByColumn = useMemo8(() => {
3766
+ const filterHeaderCellPropsByColumn = useMemo9(() => {
3684
3767
  const map = /* @__PURE__ */ new Map();
3685
3768
  for (const column of visibleColumns) {
3686
3769
  map.set(column.id, headerCellClassAndStyle(column, "border-b border-border p-2 align-top font-normal"));
@@ -3700,13 +3783,13 @@ function DataGrid({
3700
3783
  `[DataGrid] showPagination={false} but only ${tableRows.length} of ${rowCount} row(s) are rendered, with no pagination UI to reach the rest. Pass an explicit pageSize (via initialState or gridState) that covers every row you want visible, or a dataSource that returns all of them.`
3701
3784
  );
3702
3785
  }, [showPagination, gridState, initialState?.pageSize, tableRows.length, rowCount]);
3703
- const groupedBuckets = useMemo8(
3786
+ const groupedBuckets = useMemo9(
3704
3787
  () => groupBy ? groupRows(tableRows, (row) => groupBy(row.original)) : void 0,
3705
3788
  [tableRows, groupBy]
3706
3789
  );
3707
3790
  const { theadRef, groupHeaderTop } = useStickyGroupHeaderTop(Boolean(groupBy));
3708
3791
  const shouldVirtualize = Boolean(virtualize) && tableRows.length > (virtualize?.threshold ?? 100);
3709
- const flatItems = useMemo8(() => {
3792
+ const flatItems = useMemo9(() => {
3710
3793
  if (!shouldVirtualize) return [];
3711
3794
  if (!groupedBuckets) return tableRows.map((row) => ({ kind: "row", row }));
3712
3795
  const items = [];
@@ -3743,15 +3826,15 @@ function DataGrid({
3743
3826
  notifiedForLengthRef.current = tableRows.length;
3744
3827
  virtualize.onEndReached();
3745
3828
  }, [lastVisibleIndex, flatItems.length, tableRows.length, virtualize]);
3746
- const cellEditingRowIds = useMemo8(
3829
+ const cellEditingRowIds = useMemo9(
3747
3830
  () => hasCellEditing ? tableRows.map((row) => row.id) : EMPTY_ID_ARRAY,
3748
3831
  [hasCellEditing, tableRows]
3749
3832
  );
3750
- const cellEditingColumnIds = useMemo8(
3833
+ const cellEditingColumnIds = useMemo9(
3751
3834
  () => hasCellEditing ? visibleColumns.map((column) => column.id) : EMPTY_ID_ARRAY,
3752
3835
  [hasCellEditing, visibleColumns]
3753
3836
  );
3754
- const cellEditingRowIndex = useMemo8(() => buildIndexMap(cellEditingRowIds), [cellEditingRowIds]);
3837
+ const cellEditingRowIndex = useMemo9(() => buildIndexMap(cellEditingRowIds), [cellEditingRowIds]);
3755
3838
  const cellSelection = useCellSelection({
3756
3839
  rowIds: cellEditingRowIds,
3757
3840
  columnIds: cellEditingColumnIds,
@@ -3998,12 +4081,12 @@ function DataGrid({
3998
4081
  "data-testid": rowTestId,
3999
4082
  className: rowProps?.className ? cn("divide-x divide-border", rowProps.className, isOddRow && "bg-foreground/5") : `divide-x divide-border${isOddRow ? " bg-foreground/5" : ""}`,
4000
4083
  children: [
4001
- showDetailColumn && /* @__PURE__ */ jsx33(
4084
+ showDetailColumn && /* @__PURE__ */ jsx34(
4002
4085
  "td",
4003
4086
  {
4004
4087
  className: isOddRow ? detailCellProps.classNameOdd : detailCellProps.className,
4005
4088
  style: detailCellProps.style,
4006
- children: /* @__PURE__ */ jsx33(
4089
+ children: /* @__PURE__ */ jsx34(
4007
4090
  Button,
4008
4091
  {
4009
4092
  type: "button",
@@ -4015,7 +4098,7 @@ function DataGrid({
4015
4098
  stopRowClick(event);
4016
4099
  toggleRowExpanded(row.id);
4017
4100
  },
4018
- children: /* @__PURE__ */ jsx33(
4101
+ children: /* @__PURE__ */ jsx34(
4019
4102
  ChevronRight,
4020
4103
  {
4021
4104
  className: `h-4 w-4 transition-transform${isExpanded ? " rotate-90" : ""}`,
@@ -4026,12 +4109,12 @@ function DataGrid({
4026
4109
  )
4027
4110
  }
4028
4111
  ),
4029
- showSelectionColumn && /* @__PURE__ */ jsx33(
4112
+ showSelectionColumn && /* @__PURE__ */ jsx34(
4030
4113
  "td",
4031
4114
  {
4032
4115
  className: isOddRow ? selectionCellProps.classNameOdd : selectionCellProps.className,
4033
4116
  style: selectionCellProps.style,
4034
- children: /* @__PURE__ */ jsx33(
4117
+ children: /* @__PURE__ */ jsx34(
4035
4118
  "input",
4036
4119
  {
4037
4120
  type: "checkbox",
@@ -4045,11 +4128,11 @@ function DataGrid({
4045
4128
  ),
4046
4129
  row.getAllCells().map((cell) => {
4047
4130
  const cellProps = bodyCellPropsByColumn.get(cell.column.id);
4048
- return /* @__PURE__ */ jsx33(
4131
+ return /* @__PURE__ */ jsx34(
4049
4132
  "td",
4050
4133
  {
4051
4134
  style: cellProps?.style,
4052
- className: cellProps?.className ?? BODY_TD_BASE_CLASS,
4135
+ className: (isOddRow ? cellProps?.classNameOdd : cellProps?.className) ?? BODY_TD_BASE_CLASS,
4053
4136
  "data-cell-row": hasCellEditing ? row.id : void 0,
4054
4137
  "data-cell-col": hasCellEditing ? cell.column.id : void 0,
4055
4138
  children: flexRender(cell.column.columnDef.cell, cell.getContext())
@@ -4057,24 +4140,24 @@ function DataGrid({
4057
4140
  cell.id
4058
4141
  );
4059
4142
  }),
4060
- showRowActionsColumn && rowActions && /* @__PURE__ */ jsx33(
4143
+ showRowActionsColumn && rowActions && /* @__PURE__ */ jsx34(
4061
4144
  "td",
4062
4145
  {
4063
4146
  className: isOddRow ? rowActionsCellProps.classNameOdd : rowActionsCellProps.className,
4064
4147
  style: rowActionsCellProps.style,
4065
- children: /* @__PURE__ */ jsx33(ActionsMenu, { items: rowActions, ctx: { row: row.original }, triggerLabel: `Row actions for ${row.id}` })
4148
+ children: /* @__PURE__ */ jsx34(ActionsMenu, { items: rowActions, ctx: { row: row.original }, triggerLabel: `Row actions for ${row.id}` })
4066
4149
  }
4067
4150
  )
4068
4151
  ]
4069
4152
  }
4070
4153
  ),
4071
- showDetailColumn && isExpanded && renderDetail && /* @__PURE__ */ jsx33("tr", { "data-testid": `${rowTestId}-detail`, children: /* @__PURE__ */ jsx33("td", { colSpan: totalColumnCount, className: "border-b border-border p-2", children: renderDetail(row.original) }) })
4154
+ showDetailColumn && isExpanded && renderDetail && /* @__PURE__ */ jsx34("tr", { "data-testid": `${rowTestId}-detail`, children: /* @__PURE__ */ jsx34("td", { colSpan: totalColumnCount, className: "border-b border-border p-2", children: renderDetail(row.original) }) })
4072
4155
  ] }, row.id);
4073
4156
  }
4074
4157
  function renderGroupSummaryCells(rows2, bgClassName) {
4075
4158
  return visibleColumns.map((column) => {
4076
4159
  const cellProps = bodyCellPropsByColumn.get(column.id);
4077
- return /* @__PURE__ */ jsx33(
4160
+ return /* @__PURE__ */ jsx34(
4078
4161
  "td",
4079
4162
  {
4080
4163
  className: cn(cellProps?.className, bgClassName, "font-medium", alignClassName(column)),
@@ -4093,9 +4176,9 @@ function DataGrid({
4093
4176
  const bgClassName = zebra ? "bg-muted" : "bg-background";
4094
4177
  const fillerClass = cn("border-b border-border p-2", bgClassName);
4095
4178
  return /* @__PURE__ */ jsxs20("tr", { "data-testid": "group-summary-row", className: "divide-x divide-border", children: [
4096
- leadingSpan > 0 && /* @__PURE__ */ jsx33("td", { colSpan: leadingSpan, className: fillerClass }),
4179
+ leadingSpan > 0 && /* @__PURE__ */ jsx34("td", { colSpan: leadingSpan, className: fillerClass }),
4097
4180
  renderGroupSummaryCells(rows2, bgClassName),
4098
- showRowActionsColumn && /* @__PURE__ */ jsx33("td", { className: fillerClass, "aria-hidden": true })
4181
+ showRowActionsColumn && /* @__PURE__ */ jsx34("td", { className: fillerClass, "aria-hidden": true })
4099
4182
  ] });
4100
4183
  }
4101
4184
  function renderTotalsFooter() {
@@ -4103,11 +4186,11 @@ function DataGrid({
4103
4186
  const summaryRows = tableRows.map((row) => row.original);
4104
4187
  const leadingSpan = summaryLeadingCellSpan();
4105
4188
  const fillerClass = "sticky bottom-0 z-20 border-t border-border bg-muted p-2";
4106
- return /* @__PURE__ */ jsx33("tfoot", { children: /* @__PURE__ */ jsxs20("tr", { "data-testid": "totals-row", className: "divide-x divide-border", children: [
4107
- leadingSpan > 0 && /* @__PURE__ */ jsx33("td", { colSpan: leadingSpan, className: fillerClass }),
4189
+ return /* @__PURE__ */ jsx34("tfoot", { children: /* @__PURE__ */ jsxs20("tr", { "data-testid": "totals-row", className: "divide-x divide-border", children: [
4190
+ leadingSpan > 0 && /* @__PURE__ */ jsx34("td", { colSpan: leadingSpan, className: fillerClass }),
4108
4191
  visibleColumns.map((column) => {
4109
4192
  const pinnedProps = pinnedCellProps(column, "header");
4110
- return /* @__PURE__ */ jsx33(
4193
+ return /* @__PURE__ */ jsx34(
4111
4194
  "td",
4112
4195
  {
4113
4196
  className: cn(
@@ -4122,13 +4205,13 @@ function DataGrid({
4122
4205
  column.id
4123
4206
  );
4124
4207
  }),
4125
- showRowActionsColumn && /* @__PURE__ */ jsx33("td", { className: fillerClass, "aria-hidden": true })
4208
+ showRowActionsColumn && /* @__PURE__ */ jsx34("td", { className: fillerClass, "aria-hidden": true })
4126
4209
  ] }) });
4127
4210
  }
4128
4211
  function renderGroupHeaderTbody(key, rows2, measureRef, dataIndex) {
4129
4212
  const expanded = isGroupExpanded(key);
4130
4213
  return /* @__PURE__ */ jsxs20("tbody", { ref: measureRef, "data-index": dataIndex, children: [
4131
- /* @__PURE__ */ jsx33("tr", { "data-testid": `group-header-${key}`, children: /* @__PURE__ */ jsx33(
4214
+ /* @__PURE__ */ jsx34("tr", { "data-testid": `group-header-${key}`, children: /* @__PURE__ */ jsx34(
4132
4215
  "td",
4133
4216
  {
4134
4217
  colSpan: totalColumnCount,
@@ -4142,7 +4225,7 @@ function DataGrid({
4142
4225
  onClick: () => toggleGroupExpanded(key),
4143
4226
  "aria-expanded": expanded,
4144
4227
  children: [
4145
- /* @__PURE__ */ jsx33(
4228
+ /* @__PURE__ */ jsx34(
4146
4229
  ChevronRight,
4147
4230
  {
4148
4231
  className: `h-4 w-4 shrink-0 transition-transform${expanded ? " rotate-90" : ""}`,
@@ -4170,7 +4253,7 @@ function DataGrid({
4170
4253
  if (item.kind === "header") return renderGroupHeaderTbody(item.key, item.rows, measureRef, index);
4171
4254
  return renderRow(item.row, measureRef, index);
4172
4255
  }
4173
- return (
4256
+ const grid = (
4174
4257
  // `h-full`/`min-h-0` here and on the two wrappers below are no-ops unless
4175
4258
  // a consumer itself gives <DataGrid> a bounded height (e.g. wraps it in
4176
4259
  // its own `flex-1 min-h-0` container) -- percentage heights fall back to
@@ -4184,7 +4267,7 @@ function DataGrid({
4184
4267
  // `overflow-x-auto` div scrolling horizontally) fighting over which one
4185
4268
  // a sticky header/pinned column is actually stuck relative to.
4186
4269
  /* @__PURE__ */ jsxs20("div", { className: "flex h-full min-h-0 flex-col gap-2", "data-testid": "datagrid", children: [
4187
- editing && pendingEdits.size > 0 && /* @__PURE__ */ jsx33(
4270
+ editing && pendingEdits.size > 0 && /* @__PURE__ */ jsx34(
4188
4271
  EditingBar,
4189
4272
  {
4190
4273
  editing,
@@ -4199,15 +4282,15 @@ function DataGrid({
4199
4282
  selectedRows.length,
4200
4283
  " selected"
4201
4284
  ] }),
4202
- /* @__PURE__ */ jsx33(ActionsMenu, { items: headerActions, ctx: { selectedRows }, triggerLabel: "Bulk actions" })
4285
+ /* @__PURE__ */ jsx34(ActionsMenu, { items: headerActions, ctx: { selectedRows }, triggerLabel: "Bulk actions" })
4203
4286
  ] }),
4204
4287
  /* @__PURE__ */ jsxs20("div", { className: "relative min-h-0 flex-1", children: [
4205
- loading && /* @__PURE__ */ jsx33(
4288
+ loading && /* @__PURE__ */ jsx34(
4206
4289
  "div",
4207
4290
  {
4208
4291
  "data-testid": "datagrid-loading-overlay",
4209
4292
  className: "absolute inset-0 z-30 flex items-center justify-center bg-background/60",
4210
- children: /* @__PURE__ */ jsx33(Loader2, { className: "h-6 w-6 animate-spin text-muted-foreground", "aria-hidden": true })
4293
+ children: /* @__PURE__ */ jsx34(Loader2, { className: "h-6 w-6 animate-spin text-muted-foreground", "aria-hidden": true })
4211
4294
  }
4212
4295
  ),
4213
4296
  /* @__PURE__ */ jsxs20(
@@ -4257,8 +4340,8 @@ function DataGrid({
4257
4340
  onClick: (event) => toggleSort(column.id, enableMultiSort && event.shiftKey, column.sortDescFirst === true),
4258
4341
  children: [
4259
4342
  headerContent,
4260
- sortEntry?.dir === "asc" && /* @__PURE__ */ jsx33(BarsArrowUpIcon, { className: "h-3 w-3", "aria-hidden": true }),
4261
- sortEntry?.dir === "desc" && /* @__PURE__ */ jsx33(BarsArrowDownIcon, { className: "h-3 w-3", "aria-hidden": true })
4343
+ sortEntry?.dir === "asc" && /* @__PURE__ */ jsx34(BarsArrowUpIcon, { className: "h-3 w-3", "aria-hidden": true }),
4344
+ sortEntry?.dir === "desc" && /* @__PURE__ */ jsx34(BarsArrowDownIcon, { className: "h-3 w-3", "aria-hidden": true })
4262
4345
  ]
4263
4346
  }
4264
4347
  ) : (
@@ -4267,17 +4350,17 @@ function DataGrid({
4267
4350
  // silently breaking any interactive content a column's own `renderHeader`
4268
4351
  // embeds directly (bare filter inputs, "select/reject all" buttons) —
4269
4352
  // clicks never reach them at all, even though nothing looks wrong visually.
4270
- /* @__PURE__ */ jsx33("div", { id: headerLabelId, className: "flex items-center gap-1 px-1", children: headerContent })
4353
+ /* @__PURE__ */ jsx34("div", { id: headerLabelId, className: "flex items-center gap-1 px-1", children: headerContent })
4271
4354
  ),
4272
4355
  filterable && /* @__PURE__ */ jsxs20(Popover, { children: [
4273
- /* @__PURE__ */ jsx33(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx33(
4356
+ /* @__PURE__ */ jsx34(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx34(
4274
4357
  Button,
4275
4358
  {
4276
4359
  variant: "ghost",
4277
4360
  size: "icon",
4278
4361
  "data-testid": `filter-trigger-${column.id}`,
4279
- "aria-label": `Filter ${column.header}`,
4280
- children: /* @__PURE__ */ jsx33(
4362
+ "aria-label": resolvedFilterLabels.filterAriaLabel(column.header),
4363
+ children: /* @__PURE__ */ jsx34(
4281
4364
  FunnelIcon7,
4282
4365
  {
4283
4366
  className: cn(
@@ -4289,10 +4372,10 @@ function DataGrid({
4289
4372
  )
4290
4373
  }
4291
4374
  ) }),
4292
- /* @__PURE__ */ jsx33(PopoverContent, { className: "w-auto", children: renderFilterWidget(column) })
4375
+ /* @__PURE__ */ jsx34(PopoverContent, { className: "w-auto max-w-[var(--radix-popover-content-available-width)]", children: renderFilterWidget(column) })
4293
4376
  ] })
4294
4377
  ] }),
4295
- enableColumnResizing && /* @__PURE__ */ jsx33(
4378
+ enableColumnResizing && /* @__PURE__ */ jsx34(
4296
4379
  "div",
4297
4380
  {
4298
4381
  "data-testid": `resize-handle-${column.id}`,
@@ -4319,7 +4402,7 @@ function DataGrid({
4319
4402
  }
4320
4403
  return /* @__PURE__ */ jsxs20(Fragment3, { children: [
4321
4404
  hasHeaderGroups && /* @__PURE__ */ jsxs20("tr", { "data-testid": "header-group-row", className: "divide-x divide-border", children: [
4322
- showDetailColumn && /* @__PURE__ */ jsx33(
4405
+ showDetailColumn && /* @__PURE__ */ jsx34(
4323
4406
  "th",
4324
4407
  {
4325
4408
  rowSpan: 2,
@@ -4328,13 +4411,13 @@ function DataGrid({
4328
4411
  "aria-hidden": true
4329
4412
  }
4330
4413
  ),
4331
- showSelectionColumn && /* @__PURE__ */ jsx33(
4414
+ showSelectionColumn && /* @__PURE__ */ jsx34(
4332
4415
  "th",
4333
4416
  {
4334
4417
  rowSpan: 2,
4335
4418
  className: selectionHeaderCellProps.className,
4336
4419
  style: selectionHeaderCellProps.style,
4337
- children: /* @__PURE__ */ jsx33(
4420
+ children: /* @__PURE__ */ jsx34(
4338
4421
  "input",
4339
4422
  {
4340
4423
  type: "checkbox",
@@ -4346,7 +4429,7 @@ function DataGrid({
4346
4429
  }
4347
4430
  ),
4348
4431
  headerRuns.map(
4349
- (run) => run.kind === "single" ? renderLeafHeaderCell(run.column, 2) : /* @__PURE__ */ jsx33(
4432
+ (run) => run.kind === "single" ? renderLeafHeaderCell(run.column, 2) : /* @__PURE__ */ jsx34(
4350
4433
  "th",
4351
4434
  {
4352
4435
  colSpan: run.columns.length,
@@ -4356,7 +4439,7 @@ function DataGrid({
4356
4439
  `group-${run.label}-${run.columns[0].id}`
4357
4440
  )
4358
4441
  ),
4359
- showRowActionsColumn && /* @__PURE__ */ jsx33(
4442
+ showRowActionsColumn && /* @__PURE__ */ jsx34(
4360
4443
  "th",
4361
4444
  {
4362
4445
  rowSpan: 2,
@@ -4367,7 +4450,7 @@ function DataGrid({
4367
4450
  )
4368
4451
  ] }, `${headerGroup.id}-groups`),
4369
4452
  /* @__PURE__ */ jsxs20("tr", { className: "divide-x divide-border", children: [
4370
- !hasHeaderGroups && showDetailColumn && /* @__PURE__ */ jsx33(
4453
+ !hasHeaderGroups && showDetailColumn && /* @__PURE__ */ jsx34(
4371
4454
  "th",
4372
4455
  {
4373
4456
  className: detailHeaderCellProps.className,
@@ -4375,12 +4458,12 @@ function DataGrid({
4375
4458
  "aria-hidden": true
4376
4459
  }
4377
4460
  ),
4378
- !hasHeaderGroups && showSelectionColumn && /* @__PURE__ */ jsx33(
4461
+ !hasHeaderGroups && showSelectionColumn && /* @__PURE__ */ jsx34(
4379
4462
  "th",
4380
4463
  {
4381
4464
  className: selectionHeaderCellProps.className,
4382
4465
  style: selectionHeaderCellProps.style,
4383
- children: /* @__PURE__ */ jsx33(
4466
+ children: /* @__PURE__ */ jsx34(
4384
4467
  "input",
4385
4468
  {
4386
4469
  type: "checkbox",
@@ -4396,7 +4479,7 @@ function DataGrid({
4396
4479
  if (!column || hasHeaderGroups && !column.headerGroup) return null;
4397
4480
  return renderLeafHeaderCell(column);
4398
4481
  }),
4399
- !hasHeaderGroups && showRowActionsColumn && /* @__PURE__ */ jsx33(
4482
+ !hasHeaderGroups && showRowActionsColumn && /* @__PURE__ */ jsx34(
4400
4483
  "th",
4401
4484
  {
4402
4485
  className: rowActionsHeaderCellProps.className,
@@ -4408,8 +4491,8 @@ function DataGrid({
4408
4491
  ] }, headerGroup.id);
4409
4492
  }),
4410
4493
  hasFilterRow && /* @__PURE__ */ jsxs20("tr", { "data-testid": "filter-row", className: "divide-x divide-border", children: [
4411
- showDetailColumn && /* @__PURE__ */ jsx33("th", { className: detailHeaderCellProps.className, style: detailHeaderCellProps.style }),
4412
- showSelectionColumn && /* @__PURE__ */ jsx33(
4494
+ showDetailColumn && /* @__PURE__ */ jsx34("th", { className: detailHeaderCellProps.className, style: detailHeaderCellProps.style }),
4495
+ showSelectionColumn && /* @__PURE__ */ jsx34(
4413
4496
  "th",
4414
4497
  {
4415
4498
  className: selectionHeaderCellProps.className,
@@ -4418,9 +4501,9 @@ function DataGrid({
4418
4501
  ),
4419
4502
  visibleColumns.map((column) => {
4420
4503
  const cellProps = filterHeaderCellPropsByColumn.get(column.id);
4421
- return /* @__PURE__ */ jsx33("th", { style: cellProps?.style, className: cellProps?.className, children: isFilterable(column) && column.filterDisplay === "row" ? renderFilterWidget(column) : null }, column.id);
4504
+ return /* @__PURE__ */ jsx34("th", { style: cellProps?.style, className: cellProps?.className, children: isFilterable(column) && column.filterDisplay === "row" ? renderFilterWidget(column) : null }, column.id);
4422
4505
  }),
4423
- showRowActionsColumn && /* @__PURE__ */ jsx33(
4506
+ showRowActionsColumn && /* @__PURE__ */ jsx34(
4424
4507
  "th",
4425
4508
  {
4426
4509
  className: rowActionsHeaderCellProps.className,
@@ -4429,8 +4512,8 @@ function DataGrid({
4429
4512
  )
4430
4513
  ] })
4431
4514
  ] }),
4432
- rows.length === 0 ? /* @__PURE__ */ jsx33("tbody", { children: /* @__PURE__ */ jsx33("tr", { children: /* @__PURE__ */ jsx33("td", { colSpan: totalColumnCount, className: "p-4 text-center text-muted-foreground", children: loading ? "Loading..." : "No results." }) }) }) : shouldVirtualize ? /* @__PURE__ */ jsxs20(Fragment4, { children: [
4433
- paddingTop > 0 && /* @__PURE__ */ jsx33("tbody", { children: /* @__PURE__ */ jsx33("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx33("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingTop } }) }) }),
4515
+ rows.length === 0 ? /* @__PURE__ */ jsx34("tbody", { children: /* @__PURE__ */ jsx34("tr", { children: /* @__PURE__ */ jsx34("td", { colSpan: totalColumnCount, className: "p-4 text-center text-muted-foreground", children: loading ? "Loading..." : "No results." }) }) }) : shouldVirtualize ? /* @__PURE__ */ jsxs20(Fragment4, { children: [
4516
+ paddingTop > 0 && /* @__PURE__ */ jsx34("tbody", { children: /* @__PURE__ */ jsx34("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx34("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingTop } }) }) }),
4434
4517
  virtualItems.map(
4435
4518
  (virtualItem) => renderFlatItem(
4436
4519
  flatItems[virtualItem.index],
@@ -4438,11 +4521,11 @@ function DataGrid({
4438
4521
  (el) => virtualizer.measureElement(el)
4439
4522
  )
4440
4523
  ),
4441
- paddingBottom > 0 && /* @__PURE__ */ jsx33("tbody", { children: /* @__PURE__ */ jsx33("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx33("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingBottom } }) }) })
4524
+ paddingBottom > 0 && /* @__PURE__ */ jsx34("tbody", { children: /* @__PURE__ */ jsx34("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx34("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingBottom } }) }) })
4442
4525
  ] }) : groupedBuckets ? groupedBuckets.map((bucket) => renderGroupedBucket(bucket)) : tableRows.map((row) => renderRow(row)),
4443
4526
  renderTotalsFooter()
4444
4527
  ] }),
4445
- hasCellEditing && /* @__PURE__ */ jsx33(
4528
+ hasCellEditing && /* @__PURE__ */ jsx34(
4446
4529
  SelectionOverlay,
4447
4530
  {
4448
4531
  containerRef: scrollRef,
@@ -4468,7 +4551,7 @@ function DataGrid({
4468
4551
  ")"
4469
4552
  ] }),
4470
4553
  /* @__PURE__ */ jsxs20("div", { className: "flex gap-2", children: [
4471
- /* @__PURE__ */ jsx33(
4554
+ /* @__PURE__ */ jsx34(
4472
4555
  Button,
4473
4556
  {
4474
4557
  variant: "outline",
@@ -4478,7 +4561,7 @@ function DataGrid({
4478
4561
  children: "Previous"
4479
4562
  }
4480
4563
  ),
4481
- /* @__PURE__ */ jsx33(
4564
+ /* @__PURE__ */ jsx34(
4482
4565
  Button,
4483
4566
  {
4484
4567
  variant: "outline",
@@ -4492,12 +4575,13 @@ function DataGrid({
4492
4575
  ] })
4493
4576
  ] })
4494
4577
  );
4578
+ return /* @__PURE__ */ jsx34(FilterLabelsProvider, { labels: filterLabels, children: grid });
4495
4579
  }
4496
4580
 
4497
4581
  // src/tree/TreeDataGrid.tsx
4498
4582
  import { useVirtualizer as useVirtualizer2 } from "@tanstack/react-virtual";
4499
4583
  import { AlertCircle, ChevronDown as ChevronDown2, ChevronRight as ChevronRight2, Loader2 as Loader22 } from "lucide-react";
4500
- import { Fragment as Fragment5, useEffect as useEffect13, useMemo as useMemo10, useRef as useRef14 } from "react";
4584
+ import { Fragment as Fragment5, useEffect as useEffect13, useMemo as useMemo11, useRef as useRef14 } from "react";
4501
4585
 
4502
4586
  // src/tree/flattenTree.ts
4503
4587
  function flattenTree(roots, accessors, expanded, childrenOverride) {
@@ -4542,7 +4626,7 @@ function computeSelectionStates(roots, accessors, childrenOverride, selectedIds)
4542
4626
  }
4543
4627
 
4544
4628
  // src/tree/useTreeState.ts
4545
- import { useCallback as useCallback5, useMemo as useMemo9, useState as useState17 } from "react";
4629
+ import { useCallback as useCallback5, useMemo as useMemo10, useState as useState17 } from "react";
4546
4630
  function useTreeState({
4547
4631
  data,
4548
4632
  getRowId,
@@ -4580,7 +4664,7 @@ function useTreeState({
4580
4664
  );
4581
4665
  const [loadingIds, setLoadingIds] = useState17(/* @__PURE__ */ new Set());
4582
4666
  const [errorIds, setErrorIds] = useState17(/* @__PURE__ */ new Map());
4583
- const resolveHasChildren = useMemo9(
4667
+ const resolveHasChildren = useMemo10(
4584
4668
  () => hasChildren ?? ((row) => (getChildren(row)?.length ?? 0) > 0),
4585
4669
  [hasChildren, getChildren]
4586
4670
  );
@@ -4659,7 +4743,7 @@ function useTreeState({
4659
4743
  }
4660
4744
 
4661
4745
  // src/tree/TreeDataGrid.tsx
4662
- import { Fragment as Fragment6, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
4746
+ import { Fragment as Fragment6, jsx as jsx35, jsxs as jsxs21 } from "react/jsx-runtime";
4663
4747
  var EMPTY_SELECTED_IDS = /* @__PURE__ */ new Set();
4664
4748
  var UNCHECKED_STATE = { checked: false, indeterminate: false };
4665
4749
  function renderCell(column, row, editingCtx) {
@@ -4676,7 +4760,7 @@ function TreeCell({
4676
4760
  editingCtx
4677
4761
  }) {
4678
4762
  return /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-1", style: { paddingLeft: flatRow.depth * indentSize }, children: [
4679
- flatRow.hasChildren ? /* @__PURE__ */ jsx34(
4763
+ flatRow.hasChildren ? /* @__PURE__ */ jsx35(
4680
4764
  "button",
4681
4765
  {
4682
4766
  type: "button",
@@ -4688,14 +4772,14 @@ function TreeCell({
4688
4772
  "aria-label": flatRow.isExpanded ? "Collapse" : "Expand",
4689
4773
  "aria-expanded": flatRow.isExpanded,
4690
4774
  className: "flex h-4 w-4 shrink-0 items-center justify-center text-muted-foreground hover:text-foreground disabled:opacity-50",
4691
- children: isLoading ? /* @__PURE__ */ jsx34(Loader22, { className: "h-3.5 w-3.5 animate-spin", "aria-hidden": "true" }) : flatRow.isExpanded ? /* @__PURE__ */ jsx34(ChevronDown2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }) : /* @__PURE__ */ jsx34(ChevronRight2, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
4775
+ children: isLoading ? /* @__PURE__ */ jsx35(Loader22, { className: "h-3.5 w-3.5 animate-spin", "aria-hidden": "true" }) : flatRow.isExpanded ? /* @__PURE__ */ jsx35(ChevronDown2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }) : /* @__PURE__ */ jsx35(ChevronRight2, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
4692
4776
  }
4693
- ) : /* @__PURE__ */ jsx34("span", { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
4694
- /* @__PURE__ */ jsx34("span", { className: "min-w-0 flex-1 truncate", children: renderCell(column, flatRow.row, editingCtx) }),
4777
+ ) : /* @__PURE__ */ jsx35("span", { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
4778
+ /* @__PURE__ */ jsx35("span", { className: "min-w-0 flex-1 truncate", children: renderCell(column, flatRow.row, editingCtx) }),
4695
4779
  flatRow.isExpanded && error ? /* @__PURE__ */ jsxs21("span", { className: "ml-1 flex shrink-0 items-center gap-1 text-xs text-destructive", children: [
4696
- /* @__PURE__ */ jsx34(AlertCircle, { className: "h-3 w-3", "aria-hidden": "true" }),
4780
+ /* @__PURE__ */ jsx35(AlertCircle, { className: "h-3 w-3", "aria-hidden": "true" }),
4697
4781
  "Failed to load.",
4698
- /* @__PURE__ */ jsx34("button", { type: "button", className: "underline underline-offset-2", onClick: onRetry, children: "Retry" })
4782
+ /* @__PURE__ */ jsx35("button", { type: "button", className: "underline underline-offset-2", onClick: onRetry, children: "Retry" })
4699
4783
  ] }) : null
4700
4784
  ] });
4701
4785
  }
@@ -4735,7 +4819,7 @@ function TreeDataGrid({
4735
4819
  showTotals = false,
4736
4820
  editing
4737
4821
  }) {
4738
- const accessors = useMemo10(
4822
+ const accessors = useMemo11(
4739
4823
  () => ({ getRowId, getChildren, hasChildren }),
4740
4824
  [getRowId, getChildren, hasChildren]
4741
4825
  );
@@ -4763,11 +4847,11 @@ function TreeDataGrid({
4763
4847
  controlledExpandedGroups,
4764
4848
  onExpandedGroupsChange
4765
4849
  );
4766
- const flatRows = useMemo10(
4850
+ const flatRows = useMemo11(
4767
4851
  () => groupBy ? [] : flattenTree(data, accessors, expanded, childrenMap),
4768
4852
  [groupBy, data, accessors, expanded, childrenMap]
4769
4853
  );
4770
- const groupedBuckets = useMemo10(
4854
+ const groupedBuckets = useMemo11(
4771
4855
  () => groupBy ? groupRows(data, groupBy).map((bucket) => ({
4772
4856
  key: bucket.key,
4773
4857
  roots: bucket.items,
@@ -4775,7 +4859,7 @@ function TreeDataGrid({
4775
4859
  })) : void 0,
4776
4860
  [groupBy, data, accessors, expanded, childrenMap]
4777
4861
  );
4778
- const groupedRender = useMemo10(() => {
4862
+ const groupedRender = useMemo11(() => {
4779
4863
  if (!groupedBuckets) return void 0;
4780
4864
  const startIndexByBucket = /* @__PURE__ */ new Map();
4781
4865
  const rows = [];
@@ -4792,7 +4876,7 @@ function TreeDataGrid({
4792
4876
  const showSelectionColumn = controlledSelectedIds !== void 0;
4793
4877
  const totalColumnCount = visibleColumns.length + (showRowActionsColumn ? 1 : 0) + (showSelectionColumn ? 1 : 0);
4794
4878
  const { theadRef, groupHeaderTop } = useStickyGroupHeaderTop(Boolean(groupBy));
4795
- const selectionStates = useMemo10(
4879
+ const selectionStates = useMemo11(
4796
4880
  () => showSelectionColumn ? computeSelectionStates(data, accessors, childrenMap, controlledSelectedIds ?? EMPTY_SELECTED_IDS) : void 0,
4797
4881
  [showSelectionColumn, data, accessors, childrenMap, controlledSelectedIds]
4798
4882
  );
@@ -4808,7 +4892,7 @@ function TreeDataGrid({
4808
4892
  else next.add(id);
4809
4893
  onSelectedIdsChange?.(next);
4810
4894
  }
4811
- const selectableFlatRows = useMemo10(
4895
+ const selectableFlatRows = useMemo11(
4812
4896
  () => allFlatRows.filter((flatRow) => !(isRowSelectionDisabled?.(flatRow.row) ?? false)),
4813
4897
  [allFlatRows, isRowSelectionDisabled]
4814
4898
  );
@@ -4822,14 +4906,14 @@ function TreeDataGrid({
4822
4906
  }
4823
4907
  onSelectedIdsChange?.(next);
4824
4908
  }
4825
- const bodyTdClassByColumn = useMemo10(() => {
4909
+ const bodyTdClassByColumn = useMemo11(() => {
4826
4910
  const map = /* @__PURE__ */ new Map();
4827
4911
  for (const column of visibleColumns) map.set(column.id, `p-2 ${alignClassName(column)}`);
4828
4912
  return map;
4829
4913
  }, [visibleColumns]);
4830
4914
  const hasColumnSummary = visibleColumns.some((column) => column.summary);
4831
4915
  function renderGroupSummaryCells(rows) {
4832
- return visibleColumns.map((column) => /* @__PURE__ */ jsx34("td", { className: cn(bodyTdClassByColumn.get(column.id), "font-medium"), children: column.summary?.(rows) }, column.id));
4916
+ return visibleColumns.map((column) => /* @__PURE__ */ jsx35("td", { className: cn(bodyTdClassByColumn.get(column.id), "font-medium"), children: column.summary?.(rows) }, column.id));
4833
4917
  }
4834
4918
  const scrollRef = useRef14(null);
4835
4919
  const shouldVirtualize = !groupBy && flatRows.length > virtualizeThreshold;
@@ -4857,9 +4941,9 @@ function TreeDataGrid({
4857
4941
  isOddRow && "bg-foreground/5"
4858
4942
  ) : `border-b border-border divide-x divide-border${isOddRow ? " bg-foreground/5" : ""}`,
4859
4943
  children: [
4860
- showSelectionColumn && /* @__PURE__ */ jsx34("td", { className: "p-1", style: { width: SELECTION_COLUMN_WIDTH }, children: (() => {
4944
+ showSelectionColumn && /* @__PURE__ */ jsx35("td", { className: "p-1", style: { width: SELECTION_COLUMN_WIDTH }, children: (() => {
4861
4945
  const state = resolveSelectionState(flatRow.row, flatRow.id);
4862
- return /* @__PURE__ */ jsx34(
4946
+ return /* @__PURE__ */ jsx35(
4863
4947
  Checkbox,
4864
4948
  {
4865
4949
  "aria-label": `Select row ${flatRow.id}`,
@@ -4870,7 +4954,7 @@ function TreeDataGrid({
4870
4954
  }
4871
4955
  );
4872
4956
  })() }),
4873
- visibleColumns.map((column) => /* @__PURE__ */ jsx34("td", { className: bodyTdClassByColumn.get(column.id), children: column.id === treeColId ? /* @__PURE__ */ jsx34(
4957
+ visibleColumns.map((column) => /* @__PURE__ */ jsx35("td", { className: bodyTdClassByColumn.get(column.id), children: column.id === treeColId ? /* @__PURE__ */ jsx35(
4874
4958
  TreeCell,
4875
4959
  {
4876
4960
  flatRow,
@@ -4883,7 +4967,7 @@ function TreeDataGrid({
4883
4967
  editingCtx: editingState.ctx
4884
4968
  }
4885
4969
  ) : renderCell(column, flatRow.row, editingState.ctx) }, column.id)),
4886
- showRowActionsColumn && rowActions && /* @__PURE__ */ jsx34("td", { className: "p-2", children: /* @__PURE__ */ jsx34(
4970
+ showRowActionsColumn && rowActions && /* @__PURE__ */ jsx35("td", { className: "p-2", children: /* @__PURE__ */ jsx35(
4887
4971
  ActionsMenu,
4888
4972
  {
4889
4973
  items: rowActions,
@@ -4900,7 +4984,7 @@ function TreeDataGrid({
4900
4984
  const paddingTop = virtualItems.length > 0 ? virtualItems[0].start : 0;
4901
4985
  const paddingBottom = virtualItems.length > 0 ? virtualizer.getTotalSize() - virtualItems[virtualItems.length - 1].end : 0;
4902
4986
  return /* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-2", "data-testid": "tree-datagrid", children: [
4903
- editing && editingState.pendingEdits.size > 0 && /* @__PURE__ */ jsx34(
4987
+ editing && editingState.pendingEdits.size > 0 && /* @__PURE__ */ jsx35(
4904
4988
  EditingBar,
4905
4989
  {
4906
4990
  editing,
@@ -4911,7 +4995,7 @@ function TreeDataGrid({
4911
4995
  testIdPrefix: "tree-datagrid"
4912
4996
  }
4913
4997
  ),
4914
- /* @__PURE__ */ jsx34(
4998
+ /* @__PURE__ */ jsx35(
4915
4999
  "div",
4916
5000
  {
4917
5001
  ref: scrollRef,
@@ -4919,13 +5003,13 @@ function TreeDataGrid({
4919
5003
  className: "overflow-y-auto",
4920
5004
  style: { maxHeight: maxBodyHeight },
4921
5005
  children: /* @__PURE__ */ jsxs21("table", { className: "w-full border-collapse text-sm", children: [
4922
- /* @__PURE__ */ jsx34("thead", { ref: theadRef, children: /* @__PURE__ */ jsxs21("tr", { className: "divide-x divide-border", children: [
4923
- showSelectionColumn && /* @__PURE__ */ jsx34(
5006
+ /* @__PURE__ */ jsx35("thead", { ref: theadRef, children: /* @__PURE__ */ jsxs21("tr", { className: "divide-x divide-border", children: [
5007
+ showSelectionColumn && /* @__PURE__ */ jsx35(
4924
5008
  "th",
4925
5009
  {
4926
5010
  className: "sticky top-0 z-20 border-b border-border bg-muted p-1",
4927
5011
  style: { width: SELECTION_COLUMN_WIDTH },
4928
- children: /* @__PURE__ */ jsx34(
5012
+ children: /* @__PURE__ */ jsx35(
4929
5013
  Checkbox,
4930
5014
  {
4931
5015
  "aria-label": "Select all visible rows",
@@ -4935,7 +5019,7 @@ function TreeDataGrid({
4935
5019
  )
4936
5020
  }
4937
5021
  ),
4938
- visibleColumns.map((column) => /* @__PURE__ */ jsx34(
5022
+ visibleColumns.map((column) => /* @__PURE__ */ jsx35(
4939
5023
  "th",
4940
5024
  {
4941
5025
  style: column.width ? { width: column.width } : void 0,
@@ -4947,15 +5031,15 @@ function TreeDataGrid({
4947
5031
  },
4948
5032
  column.id
4949
5033
  )),
4950
- showRowActionsColumn && /* @__PURE__ */ jsx34("th", { className: "sticky top-0 z-20 border-b border-border bg-muted p-2", "aria-label": "Row actions" })
5034
+ showRowActionsColumn && /* @__PURE__ */ jsx35("th", { className: "sticky top-0 z-20 border-b border-border bg-muted p-2", "aria-label": "Row actions" })
4951
5035
  ] }) }),
4952
- /* @__PURE__ */ jsx34("tbody", { children: data.length === 0 ? /* @__PURE__ */ jsx34("tr", { children: /* @__PURE__ */ jsx34("td", { colSpan: totalColumnCount, className: "p-4 text-center text-muted-foreground", children: loading ? /* @__PURE__ */ jsxs21("span", { className: "inline-flex items-center gap-2", children: [
4953
- /* @__PURE__ */ jsx34(Loader22, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" }),
5036
+ /* @__PURE__ */ jsx35("tbody", { children: data.length === 0 ? /* @__PURE__ */ jsx35("tr", { children: /* @__PURE__ */ jsx35("td", { colSpan: totalColumnCount, className: "p-4 text-center text-muted-foreground", children: loading ? /* @__PURE__ */ jsxs21("span", { className: "inline-flex items-center gap-2", children: [
5037
+ /* @__PURE__ */ jsx35(Loader22, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" }),
4954
5038
  "Loading..."
4955
5039
  ] }) : "No results." }) }) : groupedBuckets ? groupedBuckets.map((bucket) => {
4956
5040
  const groupExpanded = isGroupExpanded(bucket.key);
4957
5041
  return /* @__PURE__ */ jsxs21(Fragment5, { children: [
4958
- /* @__PURE__ */ jsx34("tr", { "data-testid": `group-header-${bucket.key}`, children: /* @__PURE__ */ jsx34(
5042
+ /* @__PURE__ */ jsx35("tr", { "data-testid": `group-header-${bucket.key}`, children: /* @__PURE__ */ jsx35(
4959
5043
  "td",
4960
5044
  {
4961
5045
  colSpan: totalColumnCount,
@@ -4972,7 +5056,7 @@ function TreeDataGrid({
4972
5056
  onClick: () => toggleGroupExpanded(bucket.key),
4973
5057
  "aria-expanded": groupExpanded,
4974
5058
  children: [
4975
- /* @__PURE__ */ jsx34(
5059
+ /* @__PURE__ */ jsx35(
4976
5060
  ChevronRight2,
4977
5061
  {
4978
5062
  className: `h-4 w-4 shrink-0 transition-transform${groupExpanded ? " rotate-90" : ""}`,
@@ -4991,7 +5075,7 @@ function TreeDataGrid({
4991
5075
  "data-testid": `group-summary-${bucket.key}`,
4992
5076
  className: "border-b border-border divide-x divide-border",
4993
5077
  children: [
4994
- showSelectionColumn && /* @__PURE__ */ jsx34(
5078
+ showSelectionColumn && /* @__PURE__ */ jsx35(
4995
5079
  "td",
4996
5080
  {
4997
5081
  className: cn("p-2", zebra ? "bg-muted" : "bg-background"),
@@ -4999,7 +5083,7 @@ function TreeDataGrid({
4999
5083
  }
5000
5084
  ),
5001
5085
  renderGroupSummaryCells(bucket.roots),
5002
- showRowActionsColumn && /* @__PURE__ */ jsx34("td", { className: cn("p-2", zebra ? "bg-muted" : "bg-background"), "aria-hidden": true })
5086
+ showRowActionsColumn && /* @__PURE__ */ jsx35("td", { className: cn("p-2", zebra ? "bg-muted" : "bg-background"), "aria-hidden": true })
5003
5087
  ]
5004
5088
  }
5005
5089
  ),
@@ -5009,11 +5093,11 @@ function TreeDataGrid({
5009
5093
  })()
5010
5094
  ] }, `group-${bucket.key}`);
5011
5095
  }) : shouldVirtualize ? /* @__PURE__ */ jsxs21(Fragment6, { children: [
5012
- paddingTop > 0 && /* @__PURE__ */ jsx34("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx34("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingTop } }) }),
5096
+ paddingTop > 0 && /* @__PURE__ */ jsx35("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx35("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingTop } }) }),
5013
5097
  virtualItems.map(
5014
5098
  (virtualItem) => renderRow(flatRows[virtualItem.index], virtualItem.index, (el) => virtualizer.measureElement(el))
5015
5099
  ),
5016
- paddingBottom > 0 && /* @__PURE__ */ jsx34("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx34(
5100
+ paddingBottom > 0 && /* @__PURE__ */ jsx35("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx35(
5017
5101
  "td",
5018
5102
  {
5019
5103
  colSpan: totalColumnCount,
@@ -5028,15 +5112,15 @@ function TreeDataGrid({
5028
5112
  // "roots only" scope `groupBy` itself uses, and for the same
5029
5113
  // reason (a child's value is usually already folded into its
5030
5114
  // parent's).
5031
- /* @__PURE__ */ jsx34("tfoot", { children: /* @__PURE__ */ jsxs21("tr", { "data-testid": "totals-row", className: "divide-x divide-border", children: [
5032
- showSelectionColumn && /* @__PURE__ */ jsx34(
5115
+ /* @__PURE__ */ jsx35("tfoot", { children: /* @__PURE__ */ jsxs21("tr", { "data-testid": "totals-row", className: "divide-x divide-border", children: [
5116
+ showSelectionColumn && /* @__PURE__ */ jsx35(
5033
5117
  "td",
5034
5118
  {
5035
5119
  className: "sticky bottom-0 z-20 border-t border-border bg-muted p-2",
5036
5120
  style: { width: SELECTION_COLUMN_WIDTH }
5037
5121
  }
5038
5122
  ),
5039
- visibleColumns.map((column) => /* @__PURE__ */ jsx34(
5123
+ visibleColumns.map((column) => /* @__PURE__ */ jsx35(
5040
5124
  "td",
5041
5125
  {
5042
5126
  style: column.width ? { width: column.width } : void 0,
@@ -5048,7 +5132,7 @@ function TreeDataGrid({
5048
5132
  },
5049
5133
  column.id
5050
5134
  )),
5051
- showRowActionsColumn && /* @__PURE__ */ jsx34("td", { className: "sticky bottom-0 z-20 border-t border-border bg-muted p-2", "aria-hidden": true })
5135
+ showRowActionsColumn && /* @__PURE__ */ jsx35("td", { className: "sticky bottom-0 z-20 border-t border-border bg-muted p-2", "aria-hidden": true })
5052
5136
  ] }) })
5053
5137
  ] })
5054
5138
  }
@@ -5067,6 +5151,7 @@ export {
5067
5151
  EditingBar,
5068
5152
  EnumEditor,
5069
5153
  EnumFilter,
5154
+ FilterLabelsProvider,
5070
5155
  MultilineStringEditor,
5071
5156
  NumberComparisonFilter,
5072
5157
  NumberEditor,
@@ -5087,6 +5172,7 @@ export {
5087
5172
  computeFillChanges,
5088
5173
  countVisible,
5089
5174
  defaultAlign,
5175
+ defaultFilterLabels,
5090
5176
  defaultFormat,
5091
5177
  editErrorId,
5092
5178
  evaluateFilter,
@@ -5103,6 +5189,7 @@ export {
5103
5189
  isFilterDescriptor,
5104
5190
  isFilterable,
5105
5191
  isSortable,
5192
+ mergeFilterLabels,
5106
5193
  moveColumnBefore,
5107
5194
  normalizeRange,
5108
5195
  orderStorageKeyFor,
@@ -5120,6 +5207,7 @@ export {
5120
5207
  useCellSelection,
5121
5208
  useDebouncedCallback,
5122
5209
  useEditingState,
5210
+ useFilterLabels,
5123
5211
  useGridState,
5124
5212
  useGroupExpansion,
5125
5213
  useStickyGroupHeaderTop,