@bmsuisse/datagrid 0.38.0 → 0.40.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
@@ -184,6 +184,8 @@ var defaultFilterLabels = {
184
184
  numberBetween: "Between",
185
185
  clear: "Clear",
186
186
  loading: "Loading\u2026",
187
+ loadFailed: "Couldn't load values.",
188
+ retry: "Retry",
187
189
  dateToday: "Today",
188
190
  dateLast7Days: "Last 7 days",
189
191
  dateThisMonth: "This month",
@@ -286,7 +288,7 @@ PopoverContent.displayName = "PopoverContent";
286
288
 
287
289
  // src/components/ui/select.tsx
288
290
  import * as SelectPrimitive from "@radix-ui/react-select";
289
- import { Check, ChevronDown } from "lucide-react";
291
+ import { CheckIcon, ChevronDownIcon } from "@heroicons/react/24/outline";
290
292
  import { forwardRef as forwardRef3 } from "react";
291
293
  import { jsx as jsx4, jsxs } from "react/jsx-runtime";
292
294
  var Select = SelectPrimitive.Root;
@@ -302,7 +304,7 @@ var SelectTrigger = forwardRef3(({ className, children, ...props }, ref) => /* @
302
304
  ...props,
303
305
  children: [
304
306
  children,
305
- /* @__PURE__ */ jsx4(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx4(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
307
+ /* @__PURE__ */ jsx4(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx4(ChevronDownIcon, { className: "h-4 w-4 opacity-50" }) })
306
308
  ]
307
309
  }
308
310
  ));
@@ -332,7 +334,7 @@ var SelectItem = forwardRef3(({ className, children, ...props }, ref) => /* @__P
332
334
  ),
333
335
  ...props,
334
336
  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" }) }) }),
337
+ /* @__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(CheckIcon, { className: "h-4 w-4" }) }) }),
336
338
  /* @__PURE__ */ jsx4(SelectPrimitive.ItemText, { children })
337
339
  ]
338
340
  }
@@ -425,7 +427,12 @@ import { CalendarDaysIcon } from "@heroicons/react/24/outline";
425
427
  import { endOfDay, endOfMonth, format, parseISO as parseISO2, startOfDay, startOfMonth, subDays } from "date-fns";
426
428
 
427
429
  // src/components/ui/calendar.tsx
428
- import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon } from "lucide-react";
430
+ import {
431
+ ChevronDownIcon as ChevronDownIcon2,
432
+ ChevronLeftIcon,
433
+ ChevronRightIcon,
434
+ ChevronUpIcon
435
+ } from "@heroicons/react/24/outline";
429
436
  import { useEffect, useRef } from "react";
430
437
  import { DayPicker, getDefaultClassNames } from "react-day-picker";
431
438
  import { jsx as jsx6 } from "react/jsx-runtime";
@@ -481,7 +488,7 @@ function Calendar({ className, classNames, ...props }) {
481
488
  },
482
489
  components: {
483
490
  Chevron: ({ className: chevronClassName, orientation }) => {
484
- const Icon2 = orientation === "up" ? ChevronUpIcon : orientation === "down" ? ChevronDownIcon : orientation === "right" ? ChevronRightIcon : ChevronLeftIcon;
491
+ const Icon2 = orientation === "up" ? ChevronUpIcon : orientation === "down" ? ChevronDownIcon2 : orientation === "right" ? ChevronRightIcon : ChevronLeftIcon;
485
492
  return /* @__PURE__ */ jsx6(Icon2, { className: cn("h-4 w-4", chevronClassName), "aria-hidden": true });
486
493
  },
487
494
  DayButton: ({ className: dayClassName, day: _day, modifiers, ...dayProps }) => {
@@ -617,7 +624,7 @@ import { useMemo as useMemo2, useState } from "react";
617
624
 
618
625
  // src/components/ui/checkbox.tsx
619
626
  import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
620
- import { Check as Check2, Minus } from "lucide-react";
627
+ import { CheckIcon as CheckIcon2, MinusIcon } from "@heroicons/react/24/outline";
621
628
  import { forwardRef as forwardRef4 } from "react";
622
629
  import { jsx as jsx8 } from "react/jsx-runtime";
623
630
  var Checkbox = forwardRef4(({ className, ...props }, ref) => /* @__PURE__ */ jsx8(
@@ -633,7 +640,7 @@ var Checkbox = forwardRef4(({ className, ...props }, ref) => /* @__PURE__ */ jsx
633
640
  className
634
641
  ),
635
642
  ...props,
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" }) })
643
+ children: /* @__PURE__ */ jsx8(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: props.checked === "indeterminate" ? /* @__PURE__ */ jsx8(MinusIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx8(CheckIcon2, { className: "h-3 w-3" }) })
637
644
  }
638
645
  ));
639
646
  Checkbox.displayName = "Checkbox";
@@ -1238,7 +1245,7 @@ function NumberRangeFilter({
1238
1245
  }
1239
1246
 
1240
1247
  // src/filter/NumberHistogramFilter.tsx
1241
- import { FunnelIcon as FunnelIcon5 } from "@heroicons/react/24/outline";
1248
+ import { ExclamationTriangleIcon, FunnelIcon as FunnelIcon5 } from "@heroicons/react/24/outline";
1242
1249
  import { useCallback, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef4, useState as useState4 } from "react";
1243
1250
  import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
1244
1251
  var BAR_HEIGHT_PX = 56;
@@ -1267,20 +1274,25 @@ function NumberHistogramFilter({
1267
1274
  const [minOnTop, setMinOnTop] = useState4(false);
1268
1275
  const [loadedValues, setLoadedValues] = useState4([]);
1269
1276
  const [loading, setLoading] = useState4(false);
1277
+ const [loadError, setLoadError] = useState4(void 0);
1278
+ const [retryKey, setRetryKey] = useState4(0);
1270
1279
  const { min, max } = rangeOf2(value);
1271
1280
  useEffect4(() => {
1272
1281
  if (!open || !loadValues) return;
1273
1282
  let cancelled = false;
1274
1283
  setLoading(true);
1284
+ setLoadError(void 0);
1275
1285
  loadValues().then((values) => {
1276
1286
  if (!cancelled) setLoadedValues(values);
1287
+ }).catch((err) => {
1288
+ if (!cancelled) setLoadError(err instanceof Error ? err.message : String(err));
1277
1289
  }).finally(() => {
1278
1290
  if (!cancelled) setLoading(false);
1279
1291
  });
1280
1292
  return () => {
1281
1293
  cancelled = true;
1282
1294
  };
1283
- }, [open, loadValues]);
1295
+ }, [open, loadValues, retryKey]);
1284
1296
  const sourceValues = allValues ?? loadedValues;
1285
1297
  const nums = useMemo3(
1286
1298
  () => open ? sourceValues.filter((v) => v != null) : [],
@@ -1344,6 +1356,20 @@ function NumberHistogramFilter({
1344
1356
  const summary = isFiltered ? `${format2(activeMin)} \u2013 ${format2(activeMax)}` : "";
1345
1357
  const panel = /* @__PURE__ */ jsxs7("div", { className: bare ? "flex w-full flex-col gap-3" : "flex w-80 flex-col gap-3", children: [
1346
1358
  loading && /* @__PURE__ */ jsx13("p", { className: "text-xs text-muted-foreground", "data-testid": `filter-${column.id}-loading`, children: labels.loading }),
1359
+ loadError !== void 0 && !loading && /* @__PURE__ */ jsxs7(
1360
+ "span",
1361
+ {
1362
+ role: "alert",
1363
+ title: loadError,
1364
+ className: "flex items-center gap-1.5 text-xs text-destructive",
1365
+ "data-testid": `filter-${column.id}-error`,
1366
+ children: [
1367
+ /* @__PURE__ */ jsx13(ExclamationTriangleIcon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }),
1368
+ labels.loadFailed,
1369
+ /* @__PURE__ */ jsx13("button", { type: "button", className: "underline underline-offset-2", onClick: () => setRetryKey((k) => k + 1), children: labels.retry })
1370
+ ]
1371
+ }
1372
+ ),
1347
1373
  /* @__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(
1348
1374
  "div",
1349
1375
  {
@@ -2780,12 +2806,12 @@ function computeFillChanges(sourceRange, finalRange, rowIds, columnIds, columns,
2780
2806
  }
2781
2807
 
2782
2808
  // src/column-selector/ColumnSelector.tsx
2783
- import { Columns3, GripVertical } from "lucide-react";
2809
+ import { Bars2Icon, ViewColumnsIcon } from "@heroicons/react/24/outline";
2784
2810
  import { useEffect as useEffect8, useState as useState11 } from "react";
2785
2811
 
2786
2812
  // src/components/ui/dialog.tsx
2787
2813
  import * as DialogPrimitive from "@radix-ui/react-dialog";
2788
- import { X } from "lucide-react";
2814
+ import { XMarkIcon } from "@heroicons/react/24/outline";
2789
2815
  import { forwardRef as forwardRef7 } from "react";
2790
2816
  import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
2791
2817
  var Dialog = DialogPrimitive.Root;
@@ -2813,7 +2839,7 @@ var DialogContent = forwardRef7(({ className, children, ...props }, ref) => /* @
2813
2839
  children: [
2814
2840
  children,
2815
2841
  /* @__PURE__ */ jsxs17(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100", children: [
2816
- /* @__PURE__ */ jsx29(X, { className: "h-4 w-4" }),
2842
+ /* @__PURE__ */ jsx29(XMarkIcon, { className: "h-4 w-4" }),
2817
2843
  /* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Close" })
2818
2844
  ] })
2819
2845
  ]
@@ -2982,7 +3008,7 @@ function ColumnSelector({
2982
3008
  if (persistKey) writePersistedColumnOrder(persistKey, next);
2983
3009
  }
2984
3010
  return /* @__PURE__ */ jsxs18(Dialog, { open, onOpenChange, children: [
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 }) }) }),
3011
+ /* @__PURE__ */ jsx30(DialogTrigger, { asChild: true, children: trigger ?? /* @__PURE__ */ jsx30(Button, { variant: "outline", size: "icon", "aria-label": "Choose columns", children: /* @__PURE__ */ jsx30(ViewColumnsIcon, { className: "h-4 w-4", "aria-hidden": true }) }) }),
2986
3012
  /* @__PURE__ */ jsxs18(DialogContent, { className: "w-fit max-w-[calc(100vw-2rem)] sm:max-w-2xl", children: [
2987
3013
  /* @__PURE__ */ jsx30(DialogHeader, { children: /* @__PURE__ */ jsx30(DialogTitle, { children: "Columns" }) }),
2988
3014
  /* @__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: [
@@ -3017,9 +3043,9 @@ function ColumnSelector({
3017
3043
  ),
3018
3044
  children: [
3019
3045
  canReorder && /* @__PURE__ */ jsx30(
3020
- GripVertical,
3046
+ Bars2Icon,
3021
3047
  {
3022
- className: "h-3.5 w-3.5 shrink-0 text-muted-foreground/50",
3048
+ className: "h-3.5 w-3.5 shrink-0 rotate-90 text-muted-foreground/50",
3023
3049
  "aria-hidden": true
3024
3050
  }
3025
3051
  ),
@@ -3054,7 +3080,7 @@ function resolveMenuItems(items, ctx) {
3054
3080
  }
3055
3081
 
3056
3082
  // src/menu/ActionsMenu.tsx
3057
- import { MoreVertical } from "lucide-react";
3083
+ import { EllipsisVerticalIcon } from "@heroicons/react/24/outline";
3058
3084
  import { useMemo as useMemo5 } from "react";
3059
3085
 
3060
3086
  // src/components/ui/dropdown-menu.tsx
@@ -3117,7 +3143,7 @@ function ActionsMenu({ items, ctx, triggerLabel }) {
3117
3143
  );
3118
3144
  if (resolved.length === 0) return null;
3119
3145
  return /* @__PURE__ */ jsxs19(DropdownMenu, { children: [
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 }) }) }),
3146
+ /* @__PURE__ */ jsx32(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx32(Button, { variant: "ghost", size: "icon", "aria-label": triggerLabel, onClick: stopRowClick, children: /* @__PURE__ */ jsx32(EllipsisVerticalIcon, { className: "h-4 w-4", "aria-hidden": true }) }) }),
3121
3147
  /* @__PURE__ */ jsx32(DropdownMenuContent, { align: "end", children: resolved.map((item) => /* @__PURE__ */ jsx32(
3122
3148
  DropdownMenuItem,
3123
3149
  {
@@ -3132,10 +3158,115 @@ function ActionsMenu({ items, ctx, triggerLabel }) {
3132
3158
  }
3133
3159
 
3134
3160
  // src/grid/DataGrid.tsx
3135
- import { BarsArrowDownIcon, BarsArrowUpIcon, FunnelIcon as FunnelIcon7 } from "@heroicons/react/24/outline";
3161
+ import {
3162
+ BarsArrowDownIcon,
3163
+ BarsArrowUpIcon,
3164
+ ChevronRightIcon as ChevronRightIcon2,
3165
+ FunnelIcon as FunnelIcon7
3166
+ } from "@heroicons/react/24/outline";
3136
3167
  import { columnResizingFeature, columnSizingFeature, flexRender, tableFeatures, useTable } from "@tanstack/react-table";
3137
3168
  import { useVirtualizer } from "@tanstack/react-virtual";
3138
- import { ChevronRight, Loader2 } from "lucide-react";
3169
+
3170
+ // src/components/status.tsx
3171
+ import { ArrowPathIcon, ExclamationTriangleIcon as ExclamationTriangleIcon2 } from "@heroicons/react/24/outline";
3172
+ import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
3173
+ function toErrorInfo(error) {
3174
+ if (error == null || error === false || error === "") return void 0;
3175
+ if (typeof error === "string") return { message: error };
3176
+ if (error instanceof Error) return { message: error.message || void 0, details: error.stack };
3177
+ if (typeof error === "object") {
3178
+ const { title, message, details } = error;
3179
+ if (title !== void 0 || message !== void 0 || details !== void 0) return { title, message, details };
3180
+ }
3181
+ try {
3182
+ return { message: typeof error === "object" ? "Unknown error" : String(error) };
3183
+ } catch {
3184
+ return { message: "Unknown error" };
3185
+ }
3186
+ }
3187
+ var defaultGridStatusLabels = {
3188
+ loading: "Loading...",
3189
+ noResults: "No results.",
3190
+ errorTitle: "Couldn't load data",
3191
+ retry: "Retry",
3192
+ showDetails: "Show details",
3193
+ nodeLoadFailed: "Failed to load."
3194
+ };
3195
+ function resolveStatusLabels(overrides) {
3196
+ return overrides ? { ...defaultGridStatusLabels, ...overrides } : defaultGridStatusLabels;
3197
+ }
3198
+ function LoadingRows({ label, rows = 4 }) {
3199
+ return /* @__PURE__ */ jsxs20("div", { role: "status", "aria-busy": "true", "data-testid": "grid-loading-rows", className: "flex flex-col gap-2 p-1", children: [
3200
+ /* @__PURE__ */ jsx33("span", { className: "sr-only", children: label }),
3201
+ Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx33("div", { className: "h-4 animate-pulse rounded-md bg-muted", style: { width: i === rows - 1 ? "60%" : "100%" } }, i))
3202
+ ] });
3203
+ }
3204
+ function RefreshBar(props) {
3205
+ return /* @__PURE__ */ jsx33(
3206
+ "div",
3207
+ {
3208
+ role: "progressbar",
3209
+ "aria-label": "Refreshing",
3210
+ className: "pointer-events-none absolute inset-x-0 top-0 z-30 h-0.5 overflow-hidden bg-muted",
3211
+ ...props,
3212
+ children: /* @__PURE__ */ jsx33("div", { className: "h-full w-1/3 animate-pulse bg-primary motion-reduce:animate-none" })
3213
+ }
3214
+ );
3215
+ }
3216
+ function GridErrorState({
3217
+ error,
3218
+ onRetry,
3219
+ labels
3220
+ }) {
3221
+ const info = toErrorInfo(error);
3222
+ if (!info) return null;
3223
+ return /* @__PURE__ */ jsxs20(
3224
+ "div",
3225
+ {
3226
+ role: "alert",
3227
+ "data-testid": "grid-error-state",
3228
+ className: "flex min-h-24 w-full flex-col items-center justify-center gap-1 p-4 text-center text-sm",
3229
+ children: [
3230
+ /* @__PURE__ */ jsx33(ExclamationTriangleIcon2, { className: "h-8 w-8 text-destructive", "aria-hidden": "true" }),
3231
+ /* @__PURE__ */ jsx33("p", { className: "font-semibold", children: info.title ?? labels.errorTitle }),
3232
+ info.message ? /* @__PURE__ */ jsx33("p", { className: "text-muted-foreground", children: info.message }) : null,
3233
+ info.details ? /* @__PURE__ */ jsxs20("details", { className: "w-full max-w-lg text-left text-xs", children: [
3234
+ /* @__PURE__ */ jsx33("summary", { className: "cursor-pointer select-none underline underline-offset-2", children: labels.showDetails }),
3235
+ /* @__PURE__ */ jsx33("pre", { className: "mt-1 max-h-40 overflow-auto whitespace-pre-wrap break-words rounded bg-muted p-2 text-muted-foreground", children: info.details })
3236
+ ] }) : null,
3237
+ onRetry ? /* @__PURE__ */ jsxs20(Button, { type: "button", variant: "outline", size: "sm", className: "mt-2", onClick: onRetry, children: [
3238
+ /* @__PURE__ */ jsx33(ArrowPathIcon, { className: "h-4 w-4", "aria-hidden": "true" }),
3239
+ labels.retry
3240
+ ] }) : null
3241
+ ]
3242
+ }
3243
+ );
3244
+ }
3245
+ function GridInlineError({
3246
+ error,
3247
+ onRetry,
3248
+ labels,
3249
+ className
3250
+ }) {
3251
+ const info = toErrorInfo(error);
3252
+ if (!info) return null;
3253
+ return /* @__PURE__ */ jsxs20(
3254
+ "span",
3255
+ {
3256
+ role: "alert",
3257
+ "data-testid": "grid-inline-error",
3258
+ title: info.details,
3259
+ className: cn("inline-flex min-w-0 items-center gap-1.5 text-xs text-red-700 dark:text-red-300", className),
3260
+ children: [
3261
+ /* @__PURE__ */ jsx33(ExclamationTriangleIcon2, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }),
3262
+ /* @__PURE__ */ jsx33("span", { className: "truncate", children: info.message ?? info.title ?? labels.errorTitle }),
3263
+ onRetry ? /* @__PURE__ */ jsx33("button", { type: "button", className: "shrink-0 underline underline-offset-2", onClick: onRetry, children: labels.retry }) : null
3264
+ ]
3265
+ }
3266
+ );
3267
+ }
3268
+
3269
+ // src/grid/DataGrid.tsx
3139
3270
  import { Fragment as Fragment3, useEffect as useEffect12, useMemo as useMemo9, useRef as useRef13, useState as useState16 } from "react";
3140
3271
 
3141
3272
  // src/cell-editing/renderAlwaysEditCell.tsx
@@ -3143,7 +3274,7 @@ import {
3143
3274
  useEffect as useEffect9,
3144
3275
  useState as useState12
3145
3276
  } from "react";
3146
- import { jsx as jsx33 } from "react/jsx-runtime";
3277
+ import { jsx as jsx34 } from "react/jsx-runtime";
3147
3278
  function AlwaysEditCell(props) {
3148
3279
  const { column, row, rawValue, ctx, atomicGesture } = props;
3149
3280
  const rowId = ctx.getRowId(row);
@@ -3156,7 +3287,7 @@ function AlwaysEditCell(props) {
3156
3287
  if (shouldOpenEnumNow) setEnumOpen(true);
3157
3288
  }, [shouldOpenEnumNow]);
3158
3289
  if (!isEditable(column, row)) {
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) });
3290
+ return /* @__PURE__ */ jsx34("span", { "data-testid": `cell-${rowId}-${column.id}`, className: "block w-full", children: column.cell ? column.cell(resolvedValue, row) : defaultFormat(column, resolvedValue) });
3160
3291
  }
3161
3292
  const isAtomic = isAtomicEditorType(column.type);
3162
3293
  const error = ctx.getError(rowId, column.id);
@@ -3223,7 +3354,7 @@ function AlwaysEditCell(props) {
3223
3354
  handleModifierCapture(event);
3224
3355
  handleEnumOpenCapture(event);
3225
3356
  }
3226
- return /* @__PURE__ */ jsx33(
3357
+ return /* @__PURE__ */ jsx34(
3227
3358
  "fieldset",
3228
3359
  {
3229
3360
  disabled: ctx.disabled,
@@ -3232,7 +3363,7 @@ function AlwaysEditCell(props) {
3232
3363
  onPointerDownCapture: handlePointerDownCapture,
3233
3364
  onClickCapture: handleClickCapture,
3234
3365
  className: "contents",
3235
- children: column.type === "enum" && !column.renderEditCell ? /* @__PURE__ */ jsx33(
3366
+ children: column.type === "enum" && !column.renderEditCell ? /* @__PURE__ */ jsx34(
3236
3367
  EnumEditor,
3237
3368
  {
3238
3369
  column,
@@ -3472,7 +3603,7 @@ function useGridState(dataSource, initialState, externalState, showPagination =
3472
3603
  }
3473
3604
 
3474
3605
  // src/grid/DataGrid.tsx
3475
- import { Fragment as Fragment4, jsx as jsx34, jsxs as jsxs20 } from "react/jsx-runtime";
3606
+ import { Fragment as Fragment4, jsx as jsx35, jsxs as jsxs21 } from "react/jsx-runtime";
3476
3607
  var gridTableFeatures = tableFeatures({ columnSizingFeature, columnResizingFeature });
3477
3608
  var DEFAULT_COLUMN_SIZE = 150;
3478
3609
  var MIN_COLUMN_SIZE = 40;
@@ -3523,7 +3654,7 @@ function toTanstackColumns(columns, editingCtxRef, cellEditingCtxRef, atomicGest
3523
3654
  cell: (info) => {
3524
3655
  const cellEditingCtx = cellEditingCtxRef.current;
3525
3656
  if (!cellEditingCtx) return renderEditableCell(column, info.row.original, info.getValue(), editingCtxRef.current);
3526
- return cellEditingCtx.alwaysEdit ? /* @__PURE__ */ jsx34(
3657
+ return cellEditingCtx.alwaysEdit ? /* @__PURE__ */ jsx35(
3527
3658
  AlwaysEditCell,
3528
3659
  {
3529
3660
  column,
@@ -3560,6 +3691,9 @@ function DataGrid({
3560
3691
  onSelectedIdsChange,
3561
3692
  testId,
3562
3693
  loading: loadingProp = false,
3694
+ error,
3695
+ onRetry,
3696
+ statusLabels,
3563
3697
  groupBy,
3564
3698
  renderGroupHeader,
3565
3699
  defaultGroupsExpanded = true,
@@ -3666,6 +3800,8 @@ function DataGrid({
3666
3800
  return table.getRowModel().rowsById[rowId]?.original;
3667
3801
  }
3668
3802
  const pageCount = Math.max(1, Math.ceil(rowCount / state.pageSize));
3803
+ const labels = resolveStatusLabels(statusLabels);
3804
+ const hasError = toErrorInfo(error) !== void 0;
3669
3805
  const loading = loadingProp || (dataSource.mode === "server" ? Boolean(dataSource.loading) : false);
3670
3806
  const showSelectionColumn = Boolean(headerActions?.length) || controlledSelectedIds !== void 0;
3671
3807
  const showRowActionsColumn = Boolean(rowActions?.length);
@@ -4073,20 +4209,20 @@ function DataGrid({
4073
4209
  const rowProps = getRowProps?.(row.original);
4074
4210
  const rowTestId = getRowTestId?.(row.original) ?? `row-${row.id}`;
4075
4211
  const isOddRow = zebra && row.index % 2 === 1;
4076
- return /* @__PURE__ */ jsxs20("tbody", { ref: measureRef, "data-index": dataIndex, children: [
4077
- /* @__PURE__ */ jsxs20(
4212
+ return /* @__PURE__ */ jsxs21("tbody", { ref: measureRef, "data-index": dataIndex, children: [
4213
+ /* @__PURE__ */ jsxs21(
4078
4214
  "tr",
4079
4215
  {
4080
4216
  ...rowProps,
4081
4217
  "data-testid": rowTestId,
4082
4218
  className: rowProps?.className ? cn("divide-x divide-border", rowProps.className, isOddRow && "bg-foreground/5") : `divide-x divide-border${isOddRow ? " bg-foreground/5" : ""}`,
4083
4219
  children: [
4084
- showDetailColumn && /* @__PURE__ */ jsx34(
4220
+ showDetailColumn && /* @__PURE__ */ jsx35(
4085
4221
  "td",
4086
4222
  {
4087
4223
  className: isOddRow ? detailCellProps.classNameOdd : detailCellProps.className,
4088
4224
  style: detailCellProps.style,
4089
- children: /* @__PURE__ */ jsx34(
4225
+ children: /* @__PURE__ */ jsx35(
4090
4226
  Button,
4091
4227
  {
4092
4228
  type: "button",
@@ -4098,8 +4234,8 @@ function DataGrid({
4098
4234
  stopRowClick(event);
4099
4235
  toggleRowExpanded(row.id);
4100
4236
  },
4101
- children: /* @__PURE__ */ jsx34(
4102
- ChevronRight,
4237
+ children: /* @__PURE__ */ jsx35(
4238
+ ChevronRightIcon2,
4103
4239
  {
4104
4240
  className: `h-4 w-4 transition-transform${isExpanded ? " rotate-90" : ""}`,
4105
4241
  "aria-hidden": true
@@ -4109,12 +4245,12 @@ function DataGrid({
4109
4245
  )
4110
4246
  }
4111
4247
  ),
4112
- showSelectionColumn && /* @__PURE__ */ jsx34(
4248
+ showSelectionColumn && /* @__PURE__ */ jsx35(
4113
4249
  "td",
4114
4250
  {
4115
4251
  className: isOddRow ? selectionCellProps.classNameOdd : selectionCellProps.className,
4116
4252
  style: selectionCellProps.style,
4117
- children: /* @__PURE__ */ jsx34(
4253
+ children: /* @__PURE__ */ jsx35(
4118
4254
  "input",
4119
4255
  {
4120
4256
  type: "checkbox",
@@ -4128,7 +4264,7 @@ function DataGrid({
4128
4264
  ),
4129
4265
  row.getAllCells().map((cell) => {
4130
4266
  const cellProps = bodyCellPropsByColumn.get(cell.column.id);
4131
- return /* @__PURE__ */ jsx34(
4267
+ return /* @__PURE__ */ jsx35(
4132
4268
  "td",
4133
4269
  {
4134
4270
  style: cellProps?.style,
@@ -4140,24 +4276,24 @@ function DataGrid({
4140
4276
  cell.id
4141
4277
  );
4142
4278
  }),
4143
- showRowActionsColumn && rowActions && /* @__PURE__ */ jsx34(
4279
+ showRowActionsColumn && rowActions && /* @__PURE__ */ jsx35(
4144
4280
  "td",
4145
4281
  {
4146
4282
  className: isOddRow ? rowActionsCellProps.classNameOdd : rowActionsCellProps.className,
4147
4283
  style: rowActionsCellProps.style,
4148
- children: /* @__PURE__ */ jsx34(ActionsMenu, { items: rowActions, ctx: { row: row.original }, triggerLabel: `Row actions for ${row.id}` })
4284
+ children: /* @__PURE__ */ jsx35(ActionsMenu, { items: rowActions, ctx: { row: row.original }, triggerLabel: `Row actions for ${row.id}` })
4149
4285
  }
4150
4286
  )
4151
4287
  ]
4152
4288
  }
4153
4289
  ),
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) }) })
4290
+ showDetailColumn && isExpanded && renderDetail && /* @__PURE__ */ jsx35("tr", { "data-testid": `${rowTestId}-detail`, children: /* @__PURE__ */ jsx35("td", { colSpan: totalColumnCount, className: "border-b border-border p-2", children: renderDetail(row.original) }) })
4155
4291
  ] }, row.id);
4156
4292
  }
4157
4293
  function renderGroupSummaryCells(rows2, bgClassName) {
4158
4294
  return visibleColumns.map((column) => {
4159
4295
  const cellProps = bodyCellPropsByColumn.get(column.id);
4160
- return /* @__PURE__ */ jsx34(
4296
+ return /* @__PURE__ */ jsx35(
4161
4297
  "td",
4162
4298
  {
4163
4299
  className: cn(cellProps?.className, bgClassName, "font-medium", alignClassName(column)),
@@ -4175,10 +4311,10 @@ function DataGrid({
4175
4311
  const leadingSpan = summaryLeadingCellSpan();
4176
4312
  const bgClassName = zebra ? "bg-muted" : "bg-background";
4177
4313
  const fillerClass = cn("border-b border-border p-2", bgClassName);
4178
- return /* @__PURE__ */ jsxs20("tr", { "data-testid": "group-summary-row", className: "divide-x divide-border", children: [
4179
- leadingSpan > 0 && /* @__PURE__ */ jsx34("td", { colSpan: leadingSpan, className: fillerClass }),
4314
+ return /* @__PURE__ */ jsxs21("tr", { "data-testid": "group-summary-row", className: "divide-x divide-border", children: [
4315
+ leadingSpan > 0 && /* @__PURE__ */ jsx35("td", { colSpan: leadingSpan, className: fillerClass }),
4180
4316
  renderGroupSummaryCells(rows2, bgClassName),
4181
- showRowActionsColumn && /* @__PURE__ */ jsx34("td", { className: fillerClass, "aria-hidden": true })
4317
+ showRowActionsColumn && /* @__PURE__ */ jsx35("td", { className: fillerClass, "aria-hidden": true })
4182
4318
  ] });
4183
4319
  }
4184
4320
  function renderTotalsFooter() {
@@ -4186,11 +4322,11 @@ function DataGrid({
4186
4322
  const summaryRows = tableRows.map((row) => row.original);
4187
4323
  const leadingSpan = summaryLeadingCellSpan();
4188
4324
  const fillerClass = "sticky bottom-0 z-20 border-t border-border bg-muted p-2";
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 }),
4325
+ return /* @__PURE__ */ jsx35("tfoot", { children: /* @__PURE__ */ jsxs21("tr", { "data-testid": "totals-row", className: "divide-x divide-border", children: [
4326
+ leadingSpan > 0 && /* @__PURE__ */ jsx35("td", { colSpan: leadingSpan, className: fillerClass }),
4191
4327
  visibleColumns.map((column) => {
4192
4328
  const pinnedProps = pinnedCellProps(column, "header");
4193
- return /* @__PURE__ */ jsx34(
4329
+ return /* @__PURE__ */ jsx35(
4194
4330
  "td",
4195
4331
  {
4196
4332
  className: cn(
@@ -4205,19 +4341,19 @@ function DataGrid({
4205
4341
  column.id
4206
4342
  );
4207
4343
  }),
4208
- showRowActionsColumn && /* @__PURE__ */ jsx34("td", { className: fillerClass, "aria-hidden": true })
4344
+ showRowActionsColumn && /* @__PURE__ */ jsx35("td", { className: fillerClass, "aria-hidden": true })
4209
4345
  ] }) });
4210
4346
  }
4211
4347
  function renderGroupHeaderTbody(key, rows2, measureRef, dataIndex) {
4212
4348
  const expanded = isGroupExpanded(key);
4213
- return /* @__PURE__ */ jsxs20("tbody", { ref: measureRef, "data-index": dataIndex, children: [
4214
- /* @__PURE__ */ jsx34("tr", { "data-testid": `group-header-${key}`, children: /* @__PURE__ */ jsx34(
4349
+ return /* @__PURE__ */ jsxs21("tbody", { ref: measureRef, "data-index": dataIndex, children: [
4350
+ /* @__PURE__ */ jsx35("tr", { "data-testid": `group-header-${key}`, children: /* @__PURE__ */ jsx35(
4215
4351
  "td",
4216
4352
  {
4217
4353
  colSpan: totalColumnCount,
4218
4354
  className: cn("sticky z-20 border-b p-2 font-medium", zebra ? "bg-muted" : "bg-background"),
4219
4355
  style: { top: groupHeaderTop },
4220
- children: /* @__PURE__ */ jsxs20(
4356
+ children: /* @__PURE__ */ jsxs21(
4221
4357
  "button",
4222
4358
  {
4223
4359
  type: "button",
@@ -4225,8 +4361,8 @@ function DataGrid({
4225
4361
  onClick: () => toggleGroupExpanded(key),
4226
4362
  "aria-expanded": expanded,
4227
4363
  children: [
4228
- /* @__PURE__ */ jsx34(
4229
- ChevronRight,
4364
+ /* @__PURE__ */ jsx35(
4365
+ ChevronRightIcon2,
4230
4366
  {
4231
4367
  className: `h-4 w-4 shrink-0 transition-transform${expanded ? " rotate-90" : ""}`,
4232
4368
  "aria-hidden": true
@@ -4244,7 +4380,7 @@ function DataGrid({
4244
4380
  function renderGroupedBucket(bucket) {
4245
4381
  const expanded = isGroupExpanded(bucket.key);
4246
4382
  const originalRows = bucket.items.map((row) => row.original);
4247
- return /* @__PURE__ */ jsxs20(Fragment3, { children: [
4383
+ return /* @__PURE__ */ jsxs21(Fragment3, { children: [
4248
4384
  renderGroupHeaderTbody(bucket.key, originalRows),
4249
4385
  expanded && bucket.items.map((row) => renderRow(row))
4250
4386
  ] }, `group-${bucket.key}`);
@@ -4266,8 +4402,8 @@ function DataGrid({
4266
4402
  // containers (that one scrolling vertically, this component's own
4267
4403
  // `overflow-x-auto` div scrolling horizontally) fighting over which one
4268
4404
  // a sticky header/pinned column is actually stuck relative to.
4269
- /* @__PURE__ */ jsxs20("div", { className: "flex h-full min-h-0 flex-col gap-2", "data-testid": "datagrid", children: [
4270
- editing && pendingEdits.size > 0 && /* @__PURE__ */ jsx34(
4405
+ /* @__PURE__ */ jsxs21("div", { className: "flex h-full min-h-0 flex-col gap-2", "data-testid": "datagrid", children: [
4406
+ editing && pendingEdits.size > 0 && /* @__PURE__ */ jsx35(
4271
4407
  EditingBar,
4272
4408
  {
4273
4409
  editing,
@@ -4277,28 +4413,25 @@ function DataGrid({
4277
4413
  onDiscard: handleDiscardEdits
4278
4414
  }
4279
4415
  ),
4280
- showSelectionColumn && headerActions && /* @__PURE__ */ jsxs20("div", { className: "flex shrink-0 items-center justify-between text-sm", children: [
4281
- /* @__PURE__ */ jsxs20("span", { children: [
4416
+ showSelectionColumn && headerActions && /* @__PURE__ */ jsxs21("div", { className: "flex shrink-0 items-center justify-between text-sm", children: [
4417
+ /* @__PURE__ */ jsxs21("span", { children: [
4282
4418
  selectedRows.length,
4283
4419
  " selected"
4284
4420
  ] }),
4285
- /* @__PURE__ */ jsx34(ActionsMenu, { items: headerActions, ctx: { selectedRows }, triggerLabel: "Bulk actions" })
4421
+ /* @__PURE__ */ jsx35(ActionsMenu, { items: headerActions, ctx: { selectedRows }, triggerLabel: "Bulk actions" })
4286
4422
  ] }),
4287
- /* @__PURE__ */ jsxs20("div", { className: "relative min-h-0 flex-1", children: [
4288
- loading && /* @__PURE__ */ jsx34(
4289
- "div",
4290
- {
4291
- "data-testid": "datagrid-loading-overlay",
4292
- className: "absolute inset-0 z-30 flex items-center justify-center bg-background/60",
4293
- children: /* @__PURE__ */ jsx34(Loader2, { className: "h-6 w-6 animate-spin text-muted-foreground", "aria-hidden": true })
4294
- }
4295
- ),
4296
- /* @__PURE__ */ jsxs20(
4423
+ hasError && rows.length > 0 && /* @__PURE__ */ jsx35("div", { className: "flex shrink-0 items-center rounded-md border border-destructive/40 bg-destructive/10 px-2 py-1", children: /* @__PURE__ */ jsx35(GridInlineError, { error, onRetry, labels }) }),
4424
+ /* @__PURE__ */ jsxs21("div", { className: "relative min-h-0 flex-1", children: [
4425
+ loading && rows.length > 0 && /* @__PURE__ */ jsx35(RefreshBar, { "data-testid": "datagrid-loading-overlay" }),
4426
+ /* @__PURE__ */ jsxs21(
4297
4427
  "div",
4298
4428
  {
4299
4429
  ref: scrollRef,
4300
4430
  "data-testid": testId,
4301
- className: cn("h-full overflow-auto rounded-md border", hasCellEditing && "relative"),
4431
+ className: cn(
4432
+ "h-full overflow-auto rounded-md border",
4433
+ hasCellEditing && "relative"
4434
+ ),
4302
4435
  style: shouldVirtualize ? { maxHeight: virtualize?.maxBodyHeight ?? 480 } : void 0,
4303
4436
  tabIndex: hasCellEditing ? 0 : void 0,
4304
4437
  onMouseDown: hasCellEditing ? handleCellMouseDown : void 0,
@@ -4307,8 +4440,8 @@ function DataGrid({
4307
4440
  onCopy: hasCellEditing ? handleCopy : void 0,
4308
4441
  onPaste: hasCellEditing ? handlePaste : void 0,
4309
4442
  children: [
4310
- /* @__PURE__ */ jsxs20("table", { className: cn("w-full border-collapse text-sm", enableColumnResizing && "table-fixed"), children: [
4311
- /* @__PURE__ */ jsxs20("thead", { ref: theadRef, className: "bg-muted", children: [
4443
+ /* @__PURE__ */ jsxs21("table", { className: cn("w-full border-collapse text-sm", enableColumnResizing && "table-fixed"), children: [
4444
+ /* @__PURE__ */ jsxs21("thead", { ref: theadRef, className: "bg-muted", children: [
4312
4445
  table.getHeaderGroups().map((headerGroup) => {
4313
4446
  const headerById = new Map(headerGroup.headers.map((header) => [header.id, header]));
4314
4447
  function renderLeafHeaderCell(column, rowSpan) {
@@ -4320,7 +4453,7 @@ function DataGrid({
4320
4453
  const cellProps = leafHeaderCellPropsByColumn.get(column.id);
4321
4454
  const headerContent = column.renderHeader ? column.renderHeader(column) : column.header;
4322
4455
  const headerLabelId = `${header.id}-label`;
4323
- return /* @__PURE__ */ jsxs20(
4456
+ return /* @__PURE__ */ jsxs21(
4324
4457
  "th",
4325
4458
  {
4326
4459
  rowSpan,
@@ -4329,8 +4462,8 @@ function DataGrid({
4329
4462
  "aria-sort": sortable ? sortDirToAriaSort(sortEntry?.dir) : void 0,
4330
4463
  "aria-labelledby": headerLabelId,
4331
4464
  children: [
4332
- /* @__PURE__ */ jsxs20("div", { className: "flex items-center gap-1", children: [
4333
- sortable ? /* @__PURE__ */ jsxs20(
4465
+ /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-1", children: [
4466
+ sortable ? /* @__PURE__ */ jsxs21(
4334
4467
  "button",
4335
4468
  {
4336
4469
  type: "button",
@@ -4340,8 +4473,8 @@ function DataGrid({
4340
4473
  onClick: (event) => toggleSort(column.id, enableMultiSort && event.shiftKey, column.sortDescFirst === true),
4341
4474
  children: [
4342
4475
  headerContent,
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 })
4476
+ sortEntry?.dir === "asc" && /* @__PURE__ */ jsx35(BarsArrowUpIcon, { className: "h-3 w-3", "aria-hidden": true }),
4477
+ sortEntry?.dir === "desc" && /* @__PURE__ */ jsx35(BarsArrowDownIcon, { className: "h-3 w-3", "aria-hidden": true })
4345
4478
  ]
4346
4479
  }
4347
4480
  ) : (
@@ -4350,17 +4483,17 @@ function DataGrid({
4350
4483
  // silently breaking any interactive content a column's own `renderHeader`
4351
4484
  // embeds directly (bare filter inputs, "select/reject all" buttons) —
4352
4485
  // clicks never reach them at all, even though nothing looks wrong visually.
4353
- /* @__PURE__ */ jsx34("div", { id: headerLabelId, className: "flex items-center gap-1 px-1", children: headerContent })
4486
+ /* @__PURE__ */ jsx35("div", { id: headerLabelId, className: "flex items-center gap-1 px-1", children: headerContent })
4354
4487
  ),
4355
- filterable && /* @__PURE__ */ jsxs20(Popover, { children: [
4356
- /* @__PURE__ */ jsx34(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx34(
4488
+ filterable && /* @__PURE__ */ jsxs21(Popover, { children: [
4489
+ /* @__PURE__ */ jsx35(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx35(
4357
4490
  Button,
4358
4491
  {
4359
4492
  variant: "ghost",
4360
4493
  size: "icon",
4361
4494
  "data-testid": `filter-trigger-${column.id}`,
4362
4495
  "aria-label": resolvedFilterLabels.filterAriaLabel(column.header),
4363
- children: /* @__PURE__ */ jsx34(
4496
+ children: /* @__PURE__ */ jsx35(
4364
4497
  FunnelIcon7,
4365
4498
  {
4366
4499
  className: cn(
@@ -4372,10 +4505,10 @@ function DataGrid({
4372
4505
  )
4373
4506
  }
4374
4507
  ) }),
4375
- /* @__PURE__ */ jsx34(PopoverContent, { className: "w-auto max-w-[var(--radix-popover-content-available-width)]", children: renderFilterWidget(column) })
4508
+ /* @__PURE__ */ jsx35(PopoverContent, { className: "w-auto max-w-[var(--radix-popover-content-available-width)]", children: renderFilterWidget(column) })
4376
4509
  ] })
4377
4510
  ] }),
4378
- enableColumnResizing && /* @__PURE__ */ jsx34(
4511
+ enableColumnResizing && /* @__PURE__ */ jsx35(
4379
4512
  "div",
4380
4513
  {
4381
4514
  "data-testid": `resize-handle-${column.id}`,
@@ -4400,9 +4533,9 @@ function DataGrid({
4400
4533
  header.id
4401
4534
  );
4402
4535
  }
4403
- return /* @__PURE__ */ jsxs20(Fragment3, { children: [
4404
- hasHeaderGroups && /* @__PURE__ */ jsxs20("tr", { "data-testid": "header-group-row", className: "divide-x divide-border", children: [
4405
- showDetailColumn && /* @__PURE__ */ jsx34(
4536
+ return /* @__PURE__ */ jsxs21(Fragment3, { children: [
4537
+ hasHeaderGroups && /* @__PURE__ */ jsxs21("tr", { "data-testid": "header-group-row", className: "divide-x divide-border", children: [
4538
+ showDetailColumn && /* @__PURE__ */ jsx35(
4406
4539
  "th",
4407
4540
  {
4408
4541
  rowSpan: 2,
@@ -4411,13 +4544,13 @@ function DataGrid({
4411
4544
  "aria-hidden": true
4412
4545
  }
4413
4546
  ),
4414
- showSelectionColumn && /* @__PURE__ */ jsx34(
4547
+ showSelectionColumn && /* @__PURE__ */ jsx35(
4415
4548
  "th",
4416
4549
  {
4417
4550
  rowSpan: 2,
4418
4551
  className: selectionHeaderCellProps.className,
4419
4552
  style: selectionHeaderCellProps.style,
4420
- children: /* @__PURE__ */ jsx34(
4553
+ children: /* @__PURE__ */ jsx35(
4421
4554
  "input",
4422
4555
  {
4423
4556
  type: "checkbox",
@@ -4429,7 +4562,7 @@ function DataGrid({
4429
4562
  }
4430
4563
  ),
4431
4564
  headerRuns.map(
4432
- (run) => run.kind === "single" ? renderLeafHeaderCell(run.column, 2) : /* @__PURE__ */ jsx34(
4565
+ (run) => run.kind === "single" ? renderLeafHeaderCell(run.column, 2) : /* @__PURE__ */ jsx35(
4433
4566
  "th",
4434
4567
  {
4435
4568
  colSpan: run.columns.length,
@@ -4439,7 +4572,7 @@ function DataGrid({
4439
4572
  `group-${run.label}-${run.columns[0].id}`
4440
4573
  )
4441
4574
  ),
4442
- showRowActionsColumn && /* @__PURE__ */ jsx34(
4575
+ showRowActionsColumn && /* @__PURE__ */ jsx35(
4443
4576
  "th",
4444
4577
  {
4445
4578
  rowSpan: 2,
@@ -4449,8 +4582,8 @@ function DataGrid({
4449
4582
  }
4450
4583
  )
4451
4584
  ] }, `${headerGroup.id}-groups`),
4452
- /* @__PURE__ */ jsxs20("tr", { className: "divide-x divide-border", children: [
4453
- !hasHeaderGroups && showDetailColumn && /* @__PURE__ */ jsx34(
4585
+ /* @__PURE__ */ jsxs21("tr", { className: "divide-x divide-border", children: [
4586
+ !hasHeaderGroups && showDetailColumn && /* @__PURE__ */ jsx35(
4454
4587
  "th",
4455
4588
  {
4456
4589
  className: detailHeaderCellProps.className,
@@ -4458,12 +4591,12 @@ function DataGrid({
4458
4591
  "aria-hidden": true
4459
4592
  }
4460
4593
  ),
4461
- !hasHeaderGroups && showSelectionColumn && /* @__PURE__ */ jsx34(
4594
+ !hasHeaderGroups && showSelectionColumn && /* @__PURE__ */ jsx35(
4462
4595
  "th",
4463
4596
  {
4464
4597
  className: selectionHeaderCellProps.className,
4465
4598
  style: selectionHeaderCellProps.style,
4466
- children: /* @__PURE__ */ jsx34(
4599
+ children: /* @__PURE__ */ jsx35(
4467
4600
  "input",
4468
4601
  {
4469
4602
  type: "checkbox",
@@ -4479,7 +4612,7 @@ function DataGrid({
4479
4612
  if (!column || hasHeaderGroups && !column.headerGroup) return null;
4480
4613
  return renderLeafHeaderCell(column);
4481
4614
  }),
4482
- !hasHeaderGroups && showRowActionsColumn && /* @__PURE__ */ jsx34(
4615
+ !hasHeaderGroups && showRowActionsColumn && /* @__PURE__ */ jsx35(
4483
4616
  "th",
4484
4617
  {
4485
4618
  className: rowActionsHeaderCellProps.className,
@@ -4490,9 +4623,9 @@ function DataGrid({
4490
4623
  ] }, headerGroup.id)
4491
4624
  ] }, headerGroup.id);
4492
4625
  }),
4493
- hasFilterRow && /* @__PURE__ */ jsxs20("tr", { "data-testid": "filter-row", className: "divide-x divide-border", children: [
4494
- showDetailColumn && /* @__PURE__ */ jsx34("th", { className: detailHeaderCellProps.className, style: detailHeaderCellProps.style }),
4495
- showSelectionColumn && /* @__PURE__ */ jsx34(
4626
+ hasFilterRow && /* @__PURE__ */ jsxs21("tr", { "data-testid": "filter-row", className: "divide-x divide-border", children: [
4627
+ showDetailColumn && /* @__PURE__ */ jsx35("th", { className: detailHeaderCellProps.className, style: detailHeaderCellProps.style }),
4628
+ showSelectionColumn && /* @__PURE__ */ jsx35(
4496
4629
  "th",
4497
4630
  {
4498
4631
  className: selectionHeaderCellProps.className,
@@ -4501,9 +4634,9 @@ function DataGrid({
4501
4634
  ),
4502
4635
  visibleColumns.map((column) => {
4503
4636
  const cellProps = filterHeaderCellPropsByColumn.get(column.id);
4504
- return /* @__PURE__ */ jsx34("th", { style: cellProps?.style, className: cellProps?.className, children: isFilterable(column) && column.filterDisplay === "row" ? renderFilterWidget(column) : null }, column.id);
4637
+ return /* @__PURE__ */ jsx35("th", { style: cellProps?.style, className: cellProps?.className, children: isFilterable(column) && column.filterDisplay === "row" ? renderFilterWidget(column) : null }, column.id);
4505
4638
  }),
4506
- showRowActionsColumn && /* @__PURE__ */ jsx34(
4639
+ showRowActionsColumn && /* @__PURE__ */ jsx35(
4507
4640
  "th",
4508
4641
  {
4509
4642
  className: rowActionsHeaderCellProps.className,
@@ -4512,8 +4645,8 @@ function DataGrid({
4512
4645
  )
4513
4646
  ] })
4514
4647
  ] }),
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 } }) }) }),
4648
+ rows.length === 0 ? /* @__PURE__ */ jsx35("tbody", { children: /* @__PURE__ */ jsx35("tr", { children: /* @__PURE__ */ jsx35("td", { colSpan: totalColumnCount, className: "p-4 text-center text-muted-foreground", children: loading ? /* @__PURE__ */ jsx35(LoadingRows, { label: labels.loading }) : hasError ? /* @__PURE__ */ jsx35(GridErrorState, { error, onRetry, labels }) : labels.noResults }) }) }) : shouldVirtualize ? /* @__PURE__ */ jsxs21(Fragment4, { children: [
4649
+ paddingTop > 0 && /* @__PURE__ */ jsx35("tbody", { children: /* @__PURE__ */ jsx35("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx35("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingTop } }) }) }),
4517
4650
  virtualItems.map(
4518
4651
  (virtualItem) => renderFlatItem(
4519
4652
  flatItems[virtualItem.index],
@@ -4521,11 +4654,11 @@ function DataGrid({
4521
4654
  (el) => virtualizer.measureElement(el)
4522
4655
  )
4523
4656
  ),
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 } }) }) })
4657
+ paddingBottom > 0 && /* @__PURE__ */ jsx35("tbody", { children: /* @__PURE__ */ jsx35("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx35("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingBottom } }) }) })
4525
4658
  ] }) : groupedBuckets ? groupedBuckets.map((bucket) => renderGroupedBucket(bucket)) : tableRows.map((row) => renderRow(row)),
4526
4659
  renderTotalsFooter()
4527
4660
  ] }),
4528
- hasCellEditing && /* @__PURE__ */ jsx34(
4661
+ hasCellEditing && /* @__PURE__ */ jsx35(
4529
4662
  SelectionOverlay,
4530
4663
  {
4531
4664
  containerRef: scrollRef,
@@ -4538,8 +4671,8 @@ function DataGrid({
4538
4671
  }
4539
4672
  )
4540
4673
  ] }),
4541
- showPagination && /* @__PURE__ */ jsxs20("div", { className: "flex shrink-0 items-center justify-between text-sm", children: [
4542
- /* @__PURE__ */ jsxs20("span", { children: [
4674
+ showPagination && /* @__PURE__ */ jsxs21("div", { className: "flex shrink-0 items-center justify-between text-sm", children: [
4675
+ /* @__PURE__ */ jsxs21("span", { children: [
4543
4676
  "Page ",
4544
4677
  state.page + 1,
4545
4678
  " of ",
@@ -4550,8 +4683,8 @@ function DataGrid({
4550
4683
  rowCount === 1 ? "" : "s",
4551
4684
  ")"
4552
4685
  ] }),
4553
- /* @__PURE__ */ jsxs20("div", { className: "flex gap-2", children: [
4554
- /* @__PURE__ */ jsx34(
4686
+ /* @__PURE__ */ jsxs21("div", { className: "flex gap-2", children: [
4687
+ /* @__PURE__ */ jsx35(
4555
4688
  Button,
4556
4689
  {
4557
4690
  variant: "outline",
@@ -4561,7 +4694,7 @@ function DataGrid({
4561
4694
  children: "Previous"
4562
4695
  }
4563
4696
  ),
4564
- /* @__PURE__ */ jsx34(
4697
+ /* @__PURE__ */ jsx35(
4565
4698
  Button,
4566
4699
  {
4567
4700
  variant: "outline",
@@ -4575,13 +4708,83 @@ function DataGrid({
4575
4708
  ] })
4576
4709
  ] })
4577
4710
  );
4578
- return /* @__PURE__ */ jsx34(FilterLabelsProvider, { labels: filterLabels, children: grid });
4711
+ return /* @__PURE__ */ jsx35(FilterLabelsProvider, { labels: filterLabels, children: grid });
4579
4712
  }
4580
4713
 
4581
4714
  // src/tree/TreeDataGrid.tsx
4582
4715
  import { useVirtualizer as useVirtualizer2 } from "@tanstack/react-virtual";
4583
- import { AlertCircle, ChevronDown as ChevronDown2, ChevronRight as ChevronRight2, Loader2 as Loader22 } from "lucide-react";
4584
- import { Fragment as Fragment5, useEffect as useEffect13, useMemo as useMemo11, useRef as useRef14 } from "react";
4716
+ import {
4717
+ ArrowPathIcon as ArrowPathIcon2,
4718
+ ChevronDownIcon as ChevronDownIcon3,
4719
+ ChevronRightIcon as ChevronRightIcon3
4720
+ } from "@heroicons/react/24/outline";
4721
+ import { Fragment as Fragment5, useEffect as useEffect13, useMemo as useMemo11, useRef as useRef15 } from "react";
4722
+
4723
+ // src/hooks/useColumnSizing.ts
4724
+ import { useCallback as useCallback5, useState as useState17 } from "react";
4725
+ var MIN_COLUMN_SIZE2 = 40;
4726
+ var KEYBOARD_RESIZE_STEP = 10;
4727
+ function useColumnSizing(controlled, onChange) {
4728
+ const [internal, setInternal] = useState17({});
4729
+ const columnSizing = controlled ?? internal;
4730
+ const setColumnSize = useCallback5(
4731
+ (columnId, width) => {
4732
+ const next = { ...columnSizing, [columnId]: Math.max(MIN_COLUMN_SIZE2, Math.round(width)) };
4733
+ setInternal(next);
4734
+ onChange?.(next);
4735
+ },
4736
+ [columnSizing, onChange]
4737
+ );
4738
+ return { columnSizing, setColumnSize };
4739
+ }
4740
+
4741
+ // src/tree/ColumnResizeHandle.tsx
4742
+ import { useRef as useRef14 } from "react";
4743
+ import { jsx as jsx36 } from "react/jsx-runtime";
4744
+ function ColumnResizeHandle({ columnId, label, width, onResize }) {
4745
+ const drag = useRef14(null);
4746
+ const cellWidth = (handle) => handle.parentElement?.getBoundingClientRect().width ?? 0;
4747
+ const onPointerDown = (event) => {
4748
+ event.preventDefault();
4749
+ event.stopPropagation();
4750
+ event.currentTarget.setPointerCapture(event.pointerId);
4751
+ drag.current = { startX: event.clientX, startWidth: cellWidth(event.currentTarget) };
4752
+ };
4753
+ const onPointerMove = (event) => {
4754
+ if (!drag.current) return;
4755
+ onResize(columnId, drag.current.startWidth + event.clientX - drag.current.startX);
4756
+ };
4757
+ const endDrag = (event) => {
4758
+ if (!drag.current) return;
4759
+ drag.current = null;
4760
+ event.currentTarget.releasePointerCapture(event.pointerId);
4761
+ };
4762
+ const onKeyDown = (event) => {
4763
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
4764
+ event.preventDefault();
4765
+ const delta = event.key === "ArrowRight" ? KEYBOARD_RESIZE_STEP : -KEYBOARD_RESIZE_STEP;
4766
+ onResize(columnId, cellWidth(event.currentTarget) + delta);
4767
+ };
4768
+ return /* @__PURE__ */ jsx36(
4769
+ "div",
4770
+ {
4771
+ "data-testid": `resize-handle-${columnId}`,
4772
+ role: "separator",
4773
+ "aria-orientation": "vertical",
4774
+ "aria-label": `Resize ${label} column`,
4775
+ "aria-valuenow": width,
4776
+ "aria-valuemin": MIN_COLUMN_SIZE2,
4777
+ "aria-valuetext": width === void 0 ? void 0 : `${width} pixels`,
4778
+ tabIndex: 0,
4779
+ onPointerDown,
4780
+ onPointerMove,
4781
+ onPointerUp: endDrag,
4782
+ onPointerCancel: endDrag,
4783
+ onKeyDown,
4784
+ className: "absolute right-0 top-0 h-full w-1 cursor-col-resize touch-none select-none hover:bg-accent focus-visible:bg-accent focus-visible:outline-none"
4785
+ }
4786
+ );
4787
+ }
4585
4788
 
4586
4789
  // src/tree/flattenTree.ts
4587
4790
  function flattenTree(roots, accessors, expanded, childrenOverride) {
@@ -4626,7 +4829,7 @@ function computeSelectionStates(roots, accessors, childrenOverride, selectedIds)
4626
4829
  }
4627
4830
 
4628
4831
  // src/tree/useTreeState.ts
4629
- import { useCallback as useCallback5, useMemo as useMemo10, useState as useState17 } from "react";
4832
+ import { useCallback as useCallback6, useMemo as useMemo10, useState as useState18 } from "react";
4630
4833
  function useTreeState({
4631
4834
  data,
4632
4835
  getRowId,
@@ -4638,9 +4841,9 @@ function useTreeState({
4638
4841
  childrenMap: controlledChildrenMap,
4639
4842
  onChildrenMapChange
4640
4843
  }) {
4641
- const [internalExpanded, setInternalExpanded] = useState17({});
4844
+ const [internalExpanded, setInternalExpanded] = useState18({});
4642
4845
  const expanded = controlledExpanded ?? internalExpanded;
4643
- const setExpanded = useCallback5(
4846
+ const setExpanded = useCallback6(
4644
4847
  (updater) => {
4645
4848
  if (controlledExpanded) {
4646
4849
  onExpandedChange?.(updater(controlledExpanded));
@@ -4650,9 +4853,9 @@ function useTreeState({
4650
4853
  },
4651
4854
  [controlledExpanded, onExpandedChange]
4652
4855
  );
4653
- const [internalChildrenMap, setInternalChildrenMap] = useState17(/* @__PURE__ */ new Map());
4856
+ const [internalChildrenMap, setInternalChildrenMap] = useState18(/* @__PURE__ */ new Map());
4654
4857
  const childrenMap = controlledChildrenMap ?? internalChildrenMap;
4655
- const setChildrenMap = useCallback5(
4858
+ const setChildrenMap = useCallback6(
4656
4859
  (updater) => {
4657
4860
  if (controlledChildrenMap) {
4658
4861
  onChildrenMapChange?.(updater(controlledChildrenMap));
@@ -4662,13 +4865,13 @@ function useTreeState({
4662
4865
  },
4663
4866
  [controlledChildrenMap, onChildrenMapChange]
4664
4867
  );
4665
- const [loadingIds, setLoadingIds] = useState17(/* @__PURE__ */ new Set());
4666
- const [errorIds, setErrorIds] = useState17(/* @__PURE__ */ new Map());
4868
+ const [loadingIds, setLoadingIds] = useState18(/* @__PURE__ */ new Set());
4869
+ const [errorIds, setErrorIds] = useState18(/* @__PURE__ */ new Map());
4667
4870
  const resolveHasChildren = useMemo10(
4668
4871
  () => hasChildren ?? ((row) => (getChildren(row)?.length ?? 0) > 0),
4669
4872
  [hasChildren, getChildren]
4670
4873
  );
4671
- const loadChildrenFor = useCallback5(
4874
+ const loadChildrenFor = useCallback6(
4672
4875
  async (row) => {
4673
4876
  const id = getRowId(row);
4674
4877
  const cached = childrenMap.get(id);
@@ -4701,7 +4904,7 @@ function useTreeState({
4701
4904
  },
4702
4905
  [childrenMap, getChildren, getRowId, onLoadChildren, setChildrenMap]
4703
4906
  );
4704
- const toggleExpand = useCallback5(
4907
+ const toggleExpand = useCallback6(
4705
4908
  (row) => {
4706
4909
  const id = getRowId(row);
4707
4910
  const willExpand = !expanded[id];
@@ -4713,14 +4916,14 @@ function useTreeState({
4713
4916
  },
4714
4917
  [expanded, getRowId, loadChildrenFor, resolveHasChildren, setExpanded]
4715
4918
  );
4716
- const retry = useCallback5(
4919
+ const retry = useCallback6(
4717
4920
  (row) => {
4718
4921
  loadChildrenFor(row).catch(() => {
4719
4922
  });
4720
4923
  },
4721
4924
  [loadChildrenFor]
4722
4925
  );
4723
- const expandToLevel = useCallback5(
4926
+ const expandToLevel = useCallback6(
4724
4927
  async (level) => {
4725
4928
  const nextExpanded = { ...expanded };
4726
4929
  async function visit(row, depth) {
@@ -4743,7 +4946,7 @@ function useTreeState({
4743
4946
  }
4744
4947
 
4745
4948
  // src/tree/TreeDataGrid.tsx
4746
- import { Fragment as Fragment6, jsx as jsx35, jsxs as jsxs21 } from "react/jsx-runtime";
4949
+ import { Fragment as Fragment6, jsx as jsx37, jsxs as jsxs22 } from "react/jsx-runtime";
4747
4950
  var EMPTY_SELECTED_IDS = /* @__PURE__ */ new Set();
4748
4951
  var UNCHECKED_STATE = { checked: false, indeterminate: false };
4749
4952
  function renderCell(column, row, editingCtx) {
@@ -4755,12 +4958,13 @@ function TreeCell({
4755
4958
  indentSize,
4756
4959
  isLoading,
4757
4960
  error,
4961
+ labels,
4758
4962
  onToggle,
4759
4963
  onRetry,
4760
4964
  editingCtx
4761
4965
  }) {
4762
- return /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-1", style: { paddingLeft: flatRow.depth * indentSize }, children: [
4763
- flatRow.hasChildren ? /* @__PURE__ */ jsx35(
4966
+ return /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-1", style: { paddingLeft: flatRow.depth * indentSize }, children: [
4967
+ flatRow.hasChildren ? /* @__PURE__ */ jsx37(
4764
4968
  "button",
4765
4969
  {
4766
4970
  type: "button",
@@ -4772,21 +4976,28 @@ function TreeCell({
4772
4976
  "aria-label": flatRow.isExpanded ? "Collapse" : "Expand",
4773
4977
  "aria-expanded": flatRow.isExpanded,
4774
4978
  className: "flex h-4 w-4 shrink-0 items-center justify-center text-muted-foreground hover:text-foreground disabled:opacity-50",
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" })
4979
+ children: isLoading ? /* @__PURE__ */ jsx37(ArrowPathIcon2, { className: "h-3.5 w-3.5 animate-spin", "aria-hidden": "true" }) : flatRow.isExpanded ? /* @__PURE__ */ jsx37(ChevronDownIcon3, { className: "h-3.5 w-3.5", "aria-hidden": "true" }) : /* @__PURE__ */ jsx37(ChevronRightIcon3, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
4776
4980
  }
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) }),
4779
- flatRow.isExpanded && error ? /* @__PURE__ */ jsxs21("span", { className: "ml-1 flex shrink-0 items-center gap-1 text-xs text-destructive", children: [
4780
- /* @__PURE__ */ jsx35(AlertCircle, { className: "h-3 w-3", "aria-hidden": "true" }),
4781
- "Failed to load.",
4782
- /* @__PURE__ */ jsx35("button", { type: "button", className: "underline underline-offset-2", onClick: onRetry, children: "Retry" })
4783
- ] }) : null
4981
+ ) : /* @__PURE__ */ jsx37("span", { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
4982
+ /* @__PURE__ */ jsx37("span", { className: "min-w-0 flex-1 truncate", children: renderCell(column, flatRow.row, editingCtx) }),
4983
+ flatRow.isExpanded && error ? /* @__PURE__ */ jsx37(
4984
+ GridInlineError,
4985
+ {
4986
+ error: { message: labels.nodeLoadFailed, details: error },
4987
+ onRetry,
4988
+ labels,
4989
+ className: "ml-1 shrink-0"
4990
+ }
4991
+ ) : null
4784
4992
  ] });
4785
4993
  }
4786
4994
  function TreeDataGrid({
4787
4995
  columns,
4788
4996
  data,
4789
4997
  loading = false,
4998
+ error,
4999
+ onRetry,
5000
+ statusLabels,
4790
5001
  treeColumnId,
4791
5002
  columnVisibility,
4792
5003
  getRowId,
@@ -4817,8 +5028,13 @@ function TreeDataGrid({
4817
5028
  onExpandedGroupsChange,
4818
5029
  zebra = true,
4819
5030
  showTotals = false,
4820
- editing
5031
+ editing,
5032
+ enableColumnResizing = false,
5033
+ columnSizing: controlledColumnSizing,
5034
+ onColumnSizingChange
4821
5035
  }) {
5036
+ const labels = resolveStatusLabels(statusLabels);
5037
+ const hasError = toErrorInfo(error) !== void 0;
4822
5038
  const accessors = useMemo11(
4823
5039
  () => ({ getRowId, getChildren, hasChildren }),
4824
5040
  [getRowId, getChildren, hasChildren]
@@ -4835,7 +5051,7 @@ function TreeDataGrid({
4835
5051
  childrenMap: controlledChildrenMap,
4836
5052
  onChildrenMapChange
4837
5053
  });
4838
- const didAutoExpand = useRef14(false);
5054
+ const didAutoExpand = useRef15(false);
4839
5055
  useEffect13(() => {
4840
5056
  if (didAutoExpand.current) return;
4841
5057
  didAutoExpand.current = true;
@@ -4875,6 +5091,12 @@ function TreeDataGrid({
4875
5091
  const showRowActionsColumn = Boolean(rowActions?.length);
4876
5092
  const showSelectionColumn = controlledSelectedIds !== void 0;
4877
5093
  const totalColumnCount = visibleColumns.length + (showRowActionsColumn ? 1 : 0) + (showSelectionColumn ? 1 : 0);
5094
+ const { columnSizing, setColumnSize } = useColumnSizing(controlledColumnSizing, onColumnSizingChange);
5095
+ const columnWidthStyle = (column) => {
5096
+ const width = enableColumnResizing ? columnSizing[column.id] ?? column.width : column.width;
5097
+ return width ? { width } : void 0;
5098
+ };
5099
+ const fixedTableWidth = enableColumnResizing && !showRowActionsColumn && visibleColumns.every((c) => columnWidthStyle(c)) ? visibleColumns.reduce((sum, c) => sum + Number(columnWidthStyle(c)?.width), showSelectionColumn ? SELECTION_COLUMN_WIDTH : 0) : void 0;
4878
5100
  const { theadRef, groupHeaderTop } = useStickyGroupHeaderTop(Boolean(groupBy));
4879
5101
  const selectionStates = useMemo11(
4880
5102
  () => showSelectionColumn ? computeSelectionStates(data, accessors, childrenMap, controlledSelectedIds ?? EMPTY_SELECTED_IDS) : void 0,
@@ -4908,14 +5130,15 @@ function TreeDataGrid({
4908
5130
  }
4909
5131
  const bodyTdClassByColumn = useMemo11(() => {
4910
5132
  const map = /* @__PURE__ */ new Map();
4911
- for (const column of visibleColumns) map.set(column.id, `p-2 ${alignClassName(column)}`);
5133
+ const clip = enableColumnResizing ? "overflow-hidden " : "";
5134
+ for (const column of visibleColumns) map.set(column.id, `${clip}p-2 ${alignClassName(column)}`);
4912
5135
  return map;
4913
- }, [visibleColumns]);
5136
+ }, [visibleColumns, enableColumnResizing]);
4914
5137
  const hasColumnSummary = visibleColumns.some((column) => column.summary);
4915
5138
  function renderGroupSummaryCells(rows) {
4916
- return visibleColumns.map((column) => /* @__PURE__ */ jsx35("td", { className: cn(bodyTdClassByColumn.get(column.id), "font-medium"), children: column.summary?.(rows) }, column.id));
5139
+ return visibleColumns.map((column) => /* @__PURE__ */ jsx37("td", { className: cn(bodyTdClassByColumn.get(column.id), "font-medium"), children: column.summary?.(rows) }, column.id));
4917
5140
  }
4918
- const scrollRef = useRef14(null);
5141
+ const scrollRef = useRef15(null);
4919
5142
  const shouldVirtualize = !groupBy && flatRows.length > virtualizeThreshold;
4920
5143
  const virtualizer = useVirtualizer2({
4921
5144
  count: flatRows.length,
@@ -4928,7 +5151,7 @@ function TreeDataGrid({
4928
5151
  const rowProps = getRowProps?.(flatRow.row, flatRow.depth, index);
4929
5152
  const rowTestId = getRowTestId?.(flatRow.row) ?? `tree-row-${flatRow.id}`;
4930
5153
  const isOddRow = zebra && index % 2 === 1;
4931
- return /* @__PURE__ */ jsxs21(
5154
+ return /* @__PURE__ */ jsxs22(
4932
5155
  "tr",
4933
5156
  {
4934
5157
  ref: measureRef,
@@ -4941,9 +5164,9 @@ function TreeDataGrid({
4941
5164
  isOddRow && "bg-foreground/5"
4942
5165
  ) : `border-b border-border divide-x divide-border${isOddRow ? " bg-foreground/5" : ""}`,
4943
5166
  children: [
4944
- showSelectionColumn && /* @__PURE__ */ jsx35("td", { className: "p-1", style: { width: SELECTION_COLUMN_WIDTH }, children: (() => {
5167
+ showSelectionColumn && /* @__PURE__ */ jsx37("td", { className: "p-1", style: { width: SELECTION_COLUMN_WIDTH }, children: (() => {
4945
5168
  const state = resolveSelectionState(flatRow.row, flatRow.id);
4946
- return /* @__PURE__ */ jsx35(
5169
+ return /* @__PURE__ */ jsx37(
4947
5170
  Checkbox,
4948
5171
  {
4949
5172
  "aria-label": `Select row ${flatRow.id}`,
@@ -4954,7 +5177,7 @@ function TreeDataGrid({
4954
5177
  }
4955
5178
  );
4956
5179
  })() }),
4957
- visibleColumns.map((column) => /* @__PURE__ */ jsx35("td", { className: bodyTdClassByColumn.get(column.id), children: column.id === treeColId ? /* @__PURE__ */ jsx35(
5180
+ visibleColumns.map((column) => /* @__PURE__ */ jsx37("td", { className: bodyTdClassByColumn.get(column.id), children: column.id === treeColId ? /* @__PURE__ */ jsx37(
4958
5181
  TreeCell,
4959
5182
  {
4960
5183
  flatRow,
@@ -4962,12 +5185,13 @@ function TreeDataGrid({
4962
5185
  indentSize,
4963
5186
  isLoading: loadingIds.has(flatRow.id),
4964
5187
  error: errorIds.get(flatRow.id),
5188
+ labels,
4965
5189
  onToggle: () => toggleExpand(flatRow.row),
4966
5190
  onRetry: () => retry(flatRow.row),
4967
5191
  editingCtx: editingState.ctx
4968
5192
  }
4969
5193
  ) : renderCell(column, flatRow.row, editingState.ctx) }, column.id)),
4970
- showRowActionsColumn && rowActions && /* @__PURE__ */ jsx35("td", { className: "p-2", children: /* @__PURE__ */ jsx35(
5194
+ showRowActionsColumn && rowActions && /* @__PURE__ */ jsx37("td", { className: "p-2", children: /* @__PURE__ */ jsx37(
4971
5195
  ActionsMenu,
4972
5196
  {
4973
5197
  items: rowActions,
@@ -4983,8 +5207,9 @@ function TreeDataGrid({
4983
5207
  const virtualItems = shouldVirtualize ? virtualizer.getVirtualItems() : [];
4984
5208
  const paddingTop = virtualItems.length > 0 ? virtualItems[0].start : 0;
4985
5209
  const paddingBottom = virtualItems.length > 0 ? virtualizer.getTotalSize() - virtualItems[virtualItems.length - 1].end : 0;
4986
- return /* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-2", "data-testid": "tree-datagrid", children: [
4987
- editing && editingState.pendingEdits.size > 0 && /* @__PURE__ */ jsx35(
5210
+ return /* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-2", "data-testid": "tree-datagrid", children: [
5211
+ hasError && data.length > 0 && /* @__PURE__ */ jsx37("div", { className: "flex shrink-0 items-center rounded-md border border-destructive/40 bg-destructive/10 px-2 py-1", children: /* @__PURE__ */ jsx37(GridInlineError, { error, onRetry, labels }) }),
5212
+ editing && editingState.pendingEdits.size > 0 && /* @__PURE__ */ jsx37(
4988
5213
  EditingBar,
4989
5214
  {
4990
5215
  editing,
@@ -4995,146 +5220,167 @@ function TreeDataGrid({
4995
5220
  testIdPrefix: "tree-datagrid"
4996
5221
  }
4997
5222
  ),
4998
- /* @__PURE__ */ jsx35(
5223
+ /* @__PURE__ */ jsx37(
4999
5224
  "div",
5000
5225
  {
5001
5226
  ref: scrollRef,
5002
5227
  "data-testid": testId,
5003
5228
  className: "overflow-y-auto",
5004
5229
  style: { maxHeight: maxBodyHeight },
5005
- children: /* @__PURE__ */ jsxs21("table", { className: "w-full border-collapse text-sm", children: [
5006
- /* @__PURE__ */ jsx35("thead", { ref: theadRef, children: /* @__PURE__ */ jsxs21("tr", { className: "divide-x divide-border", children: [
5007
- showSelectionColumn && /* @__PURE__ */ jsx35(
5008
- "th",
5009
- {
5010
- className: "sticky top-0 z-20 border-b border-border bg-muted p-1",
5011
- style: { width: SELECTION_COLUMN_WIDTH },
5012
- children: /* @__PURE__ */ jsx35(
5013
- Checkbox,
5230
+ children: /* @__PURE__ */ jsxs22(
5231
+ "table",
5232
+ {
5233
+ className: cn(
5234
+ "border-collapse text-sm",
5235
+ fixedTableWidth === void 0 && "w-full",
5236
+ enableColumnResizing && "table-fixed"
5237
+ ),
5238
+ style: fixedTableWidth === void 0 ? void 0 : { width: fixedTableWidth },
5239
+ children: [
5240
+ /* @__PURE__ */ jsx37("thead", { ref: theadRef, children: /* @__PURE__ */ jsxs22("tr", { className: "divide-x divide-border", children: [
5241
+ showSelectionColumn && /* @__PURE__ */ jsx37(
5242
+ "th",
5014
5243
  {
5015
- "aria-label": "Select all visible rows",
5016
- checked: allVisibleSelected,
5017
- onCheckedChange: toggleAllVisibleSelected
5244
+ className: "sticky top-0 z-20 border-b border-border bg-muted p-1",
5245
+ style: { width: SELECTION_COLUMN_WIDTH },
5246
+ children: /* @__PURE__ */ jsx37(
5247
+ Checkbox,
5248
+ {
5249
+ "aria-label": "Select all visible rows",
5250
+ checked: allVisibleSelected,
5251
+ onCheckedChange: toggleAllVisibleSelected
5252
+ }
5253
+ )
5018
5254
  }
5019
- )
5020
- }
5021
- ),
5022
- visibleColumns.map((column) => /* @__PURE__ */ jsx35(
5023
- "th",
5024
- {
5025
- style: column.width ? { width: column.width } : void 0,
5026
- className: cn(
5027
- "sticky top-0 z-20 border-b border-border bg-muted p-2 font-medium",
5028
- alignClassName(column)
5029
5255
  ),
5030
- children: column.header
5031
- },
5032
- column.id
5033
- )),
5034
- showRowActionsColumn && /* @__PURE__ */ jsx35("th", { className: "sticky top-0 z-20 border-b border-border bg-muted p-2", "aria-label": "Row actions" })
5035
- ] }) }),
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" }),
5038
- "Loading..."
5039
- ] }) : "No results." }) }) : groupedBuckets ? groupedBuckets.map((bucket) => {
5040
- const groupExpanded = isGroupExpanded(bucket.key);
5041
- return /* @__PURE__ */ jsxs21(Fragment5, { children: [
5042
- /* @__PURE__ */ jsx35("tr", { "data-testid": `group-header-${bucket.key}`, children: /* @__PURE__ */ jsx35(
5043
- "td",
5044
- {
5045
- colSpan: totalColumnCount,
5046
- className: cn(
5047
- "sticky z-20 border-b p-2 font-medium",
5048
- zebra ? "bg-muted" : "bg-background"
5049
- ),
5050
- style: { top: groupHeaderTop },
5051
- children: /* @__PURE__ */ jsxs21(
5052
- "button",
5256
+ visibleColumns.map((column) => /* @__PURE__ */ jsxs22(
5257
+ "th",
5258
+ {
5259
+ style: columnWidthStyle(column),
5260
+ className: cn(
5261
+ "sticky top-0 z-20 border-b border-border bg-muted p-2 font-medium",
5262
+ enableColumnResizing && "overflow-hidden",
5263
+ alignClassName(column)
5264
+ ),
5265
+ children: [
5266
+ column.header,
5267
+ enableColumnResizing && /* @__PURE__ */ jsx37(
5268
+ ColumnResizeHandle,
5269
+ {
5270
+ columnId: column.id,
5271
+ label: String(column.header),
5272
+ width: columnSizing[column.id] ?? column.width,
5273
+ onResize: setColumnSize
5274
+ }
5275
+ )
5276
+ ]
5277
+ },
5278
+ column.id
5279
+ )),
5280
+ showRowActionsColumn && /* @__PURE__ */ jsx37("th", { className: "sticky top-0 z-20 border-b border-border bg-muted p-2", "aria-label": "Row actions" })
5281
+ ] }) }),
5282
+ /* @__PURE__ */ jsx37("tbody", { children: data.length === 0 ? /* @__PURE__ */ jsx37("tr", { children: /* @__PURE__ */ jsx37("td", { colSpan: totalColumnCount, className: "p-4 text-center text-muted-foreground", children: loading ? /* @__PURE__ */ jsx37(LoadingRows, { label: labels.loading }) : hasError ? /* @__PURE__ */ jsx37(GridErrorState, { error, onRetry, labels }) : labels.noResults }) }) : groupedBuckets ? groupedBuckets.map((bucket) => {
5283
+ const groupExpanded = isGroupExpanded(bucket.key);
5284
+ return /* @__PURE__ */ jsxs22(Fragment5, { children: [
5285
+ /* @__PURE__ */ jsx37("tr", { "data-testid": `group-header-${bucket.key}`, children: /* @__PURE__ */ jsx37(
5286
+ "td",
5287
+ {
5288
+ colSpan: totalColumnCount,
5289
+ className: cn(
5290
+ "sticky z-20 border-b p-2 font-medium",
5291
+ zebra ? "bg-muted" : "bg-background"
5292
+ ),
5293
+ style: { top: groupHeaderTop },
5294
+ children: /* @__PURE__ */ jsxs22(
5295
+ "button",
5296
+ {
5297
+ type: "button",
5298
+ className: "flex w-full items-center gap-1 text-left",
5299
+ onClick: () => toggleGroupExpanded(bucket.key),
5300
+ "aria-expanded": groupExpanded,
5301
+ children: [
5302
+ /* @__PURE__ */ jsx37(
5303
+ ChevronRightIcon3,
5304
+ {
5305
+ className: `h-4 w-4 shrink-0 transition-transform${groupExpanded ? " rotate-90" : ""}`,
5306
+ "aria-hidden": true
5307
+ }
5308
+ ),
5309
+ renderGroupHeader ? renderGroupHeader(bucket.key, bucket.roots, groupExpanded) : `${bucket.key} (${bucket.roots.length})`
5310
+ ]
5311
+ }
5312
+ )
5313
+ }
5314
+ ) }),
5315
+ hasColumnSummary && /* @__PURE__ */ jsxs22(
5316
+ "tr",
5053
5317
  {
5054
- type: "button",
5055
- className: "flex w-full items-center gap-1 text-left",
5056
- onClick: () => toggleGroupExpanded(bucket.key),
5057
- "aria-expanded": groupExpanded,
5318
+ "data-testid": `group-summary-${bucket.key}`,
5319
+ className: "border-b border-border divide-x divide-border",
5058
5320
  children: [
5059
- /* @__PURE__ */ jsx35(
5060
- ChevronRight2,
5321
+ showSelectionColumn && /* @__PURE__ */ jsx37(
5322
+ "td",
5061
5323
  {
5062
- className: `h-4 w-4 shrink-0 transition-transform${groupExpanded ? " rotate-90" : ""}`,
5063
- "aria-hidden": true
5324
+ className: cn("p-2", zebra ? "bg-muted" : "bg-background"),
5325
+ style: { width: SELECTION_COLUMN_WIDTH }
5064
5326
  }
5065
5327
  ),
5066
- renderGroupHeader ? renderGroupHeader(bucket.key, bucket.roots, groupExpanded) : `${bucket.key} (${bucket.roots.length})`
5328
+ renderGroupSummaryCells(bucket.roots),
5329
+ showRowActionsColumn && /* @__PURE__ */ jsx37("td", { className: cn("p-2", zebra ? "bg-muted" : "bg-background"), "aria-hidden": true })
5067
5330
  ]
5068
5331
  }
5069
- )
5070
- }
5071
- ) }),
5072
- hasColumnSummary && /* @__PURE__ */ jsxs21(
5073
- "tr",
5074
- {
5075
- "data-testid": `group-summary-${bucket.key}`,
5076
- className: "border-b border-border divide-x divide-border",
5077
- children: [
5078
- showSelectionColumn && /* @__PURE__ */ jsx35(
5079
- "td",
5080
- {
5081
- className: cn("p-2", zebra ? "bg-muted" : "bg-background"),
5082
- style: { width: SELECTION_COLUMN_WIDTH }
5083
- }
5084
- ),
5085
- renderGroupSummaryCells(bucket.roots),
5086
- showRowActionsColumn && /* @__PURE__ */ jsx35("td", { className: cn("p-2", zebra ? "bg-muted" : "bg-background"), "aria-hidden": true })
5087
- ]
5088
- }
5089
- ),
5090
- groupExpanded && (() => {
5091
- const startIndex = groupedRender?.startIndexByBucket.get(bucket.key) ?? 0;
5092
- return bucket.flatRows.map((flatRow, i) => renderRow(flatRow, startIndex + i));
5093
- })()
5094
- ] }, `group-${bucket.key}`);
5095
- }) : shouldVirtualize ? /* @__PURE__ */ jsxs21(Fragment6, { children: [
5096
- paddingTop > 0 && /* @__PURE__ */ jsx35("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx35("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingTop } }) }),
5097
- virtualItems.map(
5098
- (virtualItem) => renderRow(flatRows[virtualItem.index], virtualItem.index, (el) => virtualizer.measureElement(el))
5099
- ),
5100
- paddingBottom > 0 && /* @__PURE__ */ jsx35("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx35(
5101
- "td",
5102
- {
5103
- colSpan: totalColumnCount,
5104
- style: { padding: 0, border: "none", height: paddingBottom }
5105
- }
5106
- ) })
5107
- ] }) : flatRows.map((flatRow, index) => renderRow(flatRow, index)) }),
5108
- showTotals && hasColumnSummary && // Sticky to the BOTTOM of the scroll container, mirroring the
5109
- // `<thead>`'s own `top-0` stickiness — see `<DataGrid>`'s own
5110
- // `renderTotalsFooter` for the full reasoning. Summarizes `data`
5111
- // (the root-level rows), not `flatRows`/`allFlatRows` — same
5112
- // "roots only" scope `groupBy` itself uses, and for the same
5113
- // reason (a child's value is usually already folded into its
5114
- // parent's).
5115
- /* @__PURE__ */ jsx35("tfoot", { children: /* @__PURE__ */ jsxs21("tr", { "data-testid": "totals-row", className: "divide-x divide-border", children: [
5116
- showSelectionColumn && /* @__PURE__ */ jsx35(
5117
- "td",
5118
- {
5119
- className: "sticky bottom-0 z-20 border-t border-border bg-muted p-2",
5120
- style: { width: SELECTION_COLUMN_WIDTH }
5121
- }
5122
- ),
5123
- visibleColumns.map((column) => /* @__PURE__ */ jsx35(
5124
- "td",
5125
- {
5126
- style: column.width ? { width: column.width } : void 0,
5127
- className: cn(
5128
- "sticky bottom-0 z-20 border-t border-border bg-muted p-2 font-medium",
5129
- alignClassName(column)
5332
+ ),
5333
+ groupExpanded && (() => {
5334
+ const startIndex = groupedRender?.startIndexByBucket.get(bucket.key) ?? 0;
5335
+ return bucket.flatRows.map((flatRow, i) => renderRow(flatRow, startIndex + i));
5336
+ })()
5337
+ ] }, `group-${bucket.key}`);
5338
+ }) : shouldVirtualize ? /* @__PURE__ */ jsxs22(Fragment6, { children: [
5339
+ paddingTop > 0 && /* @__PURE__ */ jsx37("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx37("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingTop } }) }),
5340
+ virtualItems.map(
5341
+ (virtualItem) => renderRow(flatRows[virtualItem.index], virtualItem.index, (el) => virtualizer.measureElement(el))
5130
5342
  ),
5131
- children: column.summary?.(data)
5132
- },
5133
- column.id
5134
- )),
5135
- showRowActionsColumn && /* @__PURE__ */ jsx35("td", { className: "sticky bottom-0 z-20 border-t border-border bg-muted p-2", "aria-hidden": true })
5136
- ] }) })
5137
- ] })
5343
+ paddingBottom > 0 && /* @__PURE__ */ jsx37("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx37(
5344
+ "td",
5345
+ {
5346
+ colSpan: totalColumnCount,
5347
+ style: { padding: 0, border: "none", height: paddingBottom }
5348
+ }
5349
+ ) })
5350
+ ] }) : flatRows.map((flatRow, index) => renderRow(flatRow, index)) }),
5351
+ showTotals && hasColumnSummary && // Sticky to the BOTTOM of the scroll container, mirroring the
5352
+ // `<thead>`'s own `top-0` stickiness — see `<DataGrid>`'s own
5353
+ // `renderTotalsFooter` for the full reasoning. Summarizes `data`
5354
+ // (the root-level rows), not `flatRows`/`allFlatRows` — same
5355
+ // "roots only" scope `groupBy` itself uses, and for the same
5356
+ // reason (a child's value is usually already folded into its
5357
+ // parent's).
5358
+ /* @__PURE__ */ jsx37("tfoot", { children: /* @__PURE__ */ jsxs22("tr", { "data-testid": "totals-row", className: "divide-x divide-border", children: [
5359
+ showSelectionColumn && /* @__PURE__ */ jsx37(
5360
+ "td",
5361
+ {
5362
+ className: "sticky bottom-0 z-20 border-t border-border bg-muted p-2",
5363
+ style: { width: SELECTION_COLUMN_WIDTH }
5364
+ }
5365
+ ),
5366
+ visibleColumns.map((column) => /* @__PURE__ */ jsx37(
5367
+ "td",
5368
+ {
5369
+ style: columnWidthStyle(column),
5370
+ className: cn(
5371
+ "sticky bottom-0 z-20 border-t border-border bg-muted p-2 font-medium",
5372
+ enableColumnResizing && "overflow-hidden",
5373
+ alignClassName(column)
5374
+ ),
5375
+ children: column.summary?.(data)
5376
+ },
5377
+ column.id
5378
+ )),
5379
+ showRowActionsColumn && /* @__PURE__ */ jsx37("td", { className: "sticky bottom-0 z-20 border-t border-border bg-muted p-2", "aria-hidden": true })
5380
+ ] }) })
5381
+ ]
5382
+ }
5383
+ )
5138
5384
  }
5139
5385
  )
5140
5386
  ] });
@@ -5174,6 +5420,7 @@ export {
5174
5420
  defaultAlign,
5175
5421
  defaultFilterLabels,
5176
5422
  defaultFormat,
5423
+ defaultGridStatusLabels,
5177
5424
  editErrorId,
5178
5425
  evaluateFilter,
5179
5426
  extendRangeForFill,
@@ -5203,6 +5450,7 @@ export {
5203
5450
  resolveMenuItems,
5204
5451
  storageKeyFor,
5205
5452
  toDate,
5453
+ toErrorInfo,
5206
5454
  useCellEditingState,
5207
5455
  useCellSelection,
5208
5456
  useDebouncedCallback,