@hexclave/dashboard-ui-components 1.0.48 → 1.0.51

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.
@@ -1 +1 @@
1
- {"version":3,"file":"data-grid-AJi1TNDa.d.ts","names":[],"sources":["../src/components/data-grid/data-grid.tsx"],"mappings":";;;iBAoEgB,mCAAA,CAAoC,MAA0B,EAAlB,WAAW;;AAAvE;;;;AAA8E;AAgiB9E;;;;;;;;;;;AAAyD;;;;;;;;;;;;;;;;;;;;;iBAAzC,QAAA,OAAe,KAAA,EAAO,aAAa,CAAC,IAAA,gCAAK,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"data-grid-AJi1TNDa.d.ts","names":[],"sources":["../src/components/data-grid/data-grid.tsx"],"mappings":";;;iBAyEgB,mCAAA,CAAoC,MAA0B,EAAlB,WAAW;;AAAvE;;;;AAA8E;AAgiB9E;;;;;;;;;;;AAAyD;;;;;;;;;;;;;;;;;;;;;iBAAzC,QAAA,OAAe,KAAA,EAAO,aAAa,CAAC,IAAA,gCAAK,GAAA,CAAA,OAAA"}
@@ -3,8 +3,8 @@ import React from "react";
3
3
 
4
4
  //#region src/components/button.d.ts
5
5
  declare const designButtonVariants: (props?: ({
6
- variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | "plain" | null | undefined;
7
- size?: "default" | "sm" | "lg" | "icon" | null | undefined;
6
+ variant?: "plain" | "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
7
+ size?: "sm" | "lg" | "default" | "icon" | null | undefined;
8
8
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
9
9
  type DesignOriginalButtonProps = {
10
10
  asChild?: boolean;
@@ -35,8 +35,8 @@ declare const DesignButton: React.FC<{
35
35
  } & {
36
36
  asChild?: boolean;
37
37
  } & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<(props?: ({
38
- variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | "plain" | null | undefined;
39
- size?: "default" | "sm" | "lg" | "icon" | null | undefined;
38
+ variant?: "plain" | "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
39
+ size?: "sm" | "lg" | "default" | "icon" | null | undefined;
40
40
  } & import("class-variance-authority/types").ClassProp) | undefined) => string> & {
41
41
  ref?: React.Ref<HTMLButtonElement> | undefined;
42
42
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"data-grid.d.ts","names":[],"sources":["../../../../src/components/data-grid/data-grid.tsx"],"mappings":";;;iBAoEgB,mCAAA,CAAoC,MAA0B,EAAlB,WAAW;;AAAvE;;;;AAA8E;AAgiB9E;;;;;;;;;;;AAAyD;;;;;;;;;;;;;;;;;;;;;iBAAzC,QAAA,OAAe,KAAA,EAAO,aAAa,CAAC,IAAA,gCAAK,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"data-grid.d.ts","names":[],"sources":["../../../../src/components/data-grid/data-grid.tsx"],"mappings":";;;iBAyEgB,mCAAA,CAAoC,MAA0B,EAAlB,WAAW;;AAAvE;;;;AAA8E;AAgiB9E;;;;;;;;;;;AAAyD;;;;;;;;;;;;;;;;;;;;;iBAAzC,QAAA,OAAe,KAAA,EAAO,aAAa,CAAC,IAAA,gCAAK,GAAA,CAAA,OAAA"}
@@ -13,6 +13,7 @@ import { DEFAULT_COL_WIDTH, clampColumnWidth, getEffectiveMaxWidth, getEffective
13
13
  import { DataGridExportDialog } from "./data-grid-export-dialog.js";
14
14
  import { DataGridToolbar } from "./data-grid-toolbar.js";
15
15
  //#region src/components/data-grid/data-grid.tsx
16
+ const DEFAULT_INFINITE_MAX_HEIGHT = "calc(100dvh - 16rem)";
16
17
  function getEventTargetElement(target) {
17
18
  if (target instanceof Element) return target;
18
19
  if (target instanceof Node) return target.parentElement;
@@ -753,14 +754,15 @@ function DataGrid(props) {
753
754
  ]);
754
755
  const allSelected = rowIds.length > 0 && rowIds.every((id) => state.selection.selectedIds.has(id));
755
756
  const someSelected = !allSelected && rowIds.some((id) => state.selection.selectedIds.has(id));
756
- const infiniteScrollRootRef = paginationMode === "infinite" && (fillHeight || maxHeight != null) ? scrollContainerRef : void 0;
757
+ const effectiveMaxHeight = maxHeight ?? (paginationMode === "infinite" && !fillHeight ? DEFAULT_INFINITE_MAX_HEIGHT : void 0);
758
+ const infiniteScrollRootRef = paginationMode === "infinite" && (fillHeight || effectiveMaxHeight != null) ? scrollContainerRef : void 0;
757
759
  const headers = useMemo(() => table.getHeaderGroups()[0]?.headers.filter((h) => visibleColumns.some((c) => c.id === h.column.id)) ?? [], [table, visibleColumns]);
758
760
  const headerByColId = useMemo(() => {
759
761
  const m = /* @__PURE__ */ new Map();
760
762
  for (const h of headers) m.set(h.column.id, h);
761
763
  return m;
762
764
  }, [headers]);
763
- const isBounded = fillHeight || maxHeight != null;
765
+ const isBounded = fillHeight || effectiveMaxHeight != null;
764
766
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(DataGridExportDialog, {
765
767
  open: exportDialogOpen,
766
768
  onOpenChange: setExportDialogOpen,
@@ -771,9 +773,9 @@ function DataGrid(props) {
771
773
  }), /* @__PURE__ */ jsxs("div", {
772
774
  ref: gridRef,
773
775
  className: cn("isolate flex w-full min-w-0 max-w-full flex-col bg-transparent rounded-[calc(var(--radius)*2)]", fillHeight ? "min-h-0 h-full" : "min-h-0 h-auto", isBounded && "overflow-hidden", className),
774
- style: maxHeight != null ? {
776
+ style: effectiveMaxHeight != null ? {
775
777
  ...cssVars,
776
- maxHeight
778
+ maxHeight: effectiveMaxHeight
777
779
  } : cssVars,
778
780
  role: "grid",
779
781
  "aria-rowcount": totalRowCount ?? rows.length,
@@ -782,7 +784,7 @@ function DataGrid(props) {
782
784
  /* @__PURE__ */ jsxs("div", {
783
785
  ref: stickyChromeRef,
784
786
  className: "sticky z-30 w-full min-w-0 shrink-0 overflow-visible rounded-t-[calc(var(--radius)*2)] bg-white/90 dark:bg-background backdrop-blur-xl",
785
- style: { top: stickyTop ?? (maxHeight != null ? 0 : "var(--data-grid-sticky-top, 0px)") },
787
+ style: { top: stickyTop ?? (effectiveMaxHeight != null ? 0 : "var(--data-grid-sticky-top, 0px)") },
786
788
  children: [toolbar !== false && /* @__PURE__ */ jsx("div", {
787
789
  className: "relative bg-transparent",
788
790
  children: toolbar ? toolbar(toolbarCtx) : /* @__PURE__ */ jsx(DataGridToolbar, {
@@ -1 +1 @@
1
- {"version":3,"file":"data-grid.js","names":[],"sources":["../../../../src/components/data-grid/data-grid.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n ArrowDown,\n ArrowUp,\n CaretDown,\n CaretUp,\n CheckSquare,\n MinusSquare,\n Square,\n} from \"@phosphor-icons/react\";\nimport { throwErr } from \"@hexclave/shared/dist/utils/errors\";\nimport { cn } from \"@hexclave/ui\";\nimport {\n type ColumnDef,\n type ColumnOrderState,\n type ColumnPinningState,\n type ColumnSizingState,\n type RowSelectionState,\n type SortingState,\n type VisibilityState,\n type Header,\n type Updater,\n getCoreRowModel,\n useReactTable,\n} from \"@tanstack/react-table\";\nimport { useVirtualizer, type VirtualItem } from \"@tanstack/react-virtual\";\nimport React, {\n type CSSProperties,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { DesignSkeleton } from \"../skeleton\";\nimport { DEFAULT_COL_WIDTH, clampColumnWidth, getEffectiveMaxWidth, getEffectiveMinWidth } from \"./data-grid-sizing\";\nimport { DataGridExportDialog } from \"./data-grid-export-dialog\";\nimport { DataGridToolbar } from \"./data-grid-toolbar\";\nimport { formatGridDate, resolveColumnValue } from \"./state\";\nimport { resolveDataGridStrings } from \"./strings\";\nimport type {\n DataGridCellContext,\n DataGridColumnDef,\n DataGridDateDisplay,\n DataGridFooterContext,\n DataGridHeaderContext,\n DataGridPaginationMode,\n DataGridProps,\n DataGridSelectionModel,\n DataGridSortItem,\n DataGridSortModel,\n DataGridState,\n DataGridStrings,\n DataGridToolbarContext,\n RowId,\n} from \"./types\";\n\n// ─── Row click target ────────────────────────────────────────────────\n\nfunction getEventTargetElement(target: EventTarget | null): Element | null {\n if (target instanceof Element) return target;\n if (target instanceof Node) return target.parentElement;\n return null;\n}\n\nexport function isDataGridInteractiveRowClickTarget(target: EventTarget | null): boolean {\n const el = getEventTargetElement(target);\n return el?.closest([\n \"a\",\n \"button\",\n \"input\",\n \"select\",\n \"textarea\",\n \"[role=\\\"button\\\"]\",\n \"[role=\\\"menuitem\\\"]\",\n \"[contenteditable]:not([contenteditable=\\\"false\\\"])\",\n \"[data-no-row-click]\",\n ].join(\",\")) != null;\n}\n\nfunction shouldIgnoreRowClick(event: React.MouseEvent): boolean {\n return event.defaultPrevented || isDataGridInteractiveRowClickTarget(event.target);\n}\n\n// ─── State translators (DataGridState ⇄ TanStack) ────────────────────\n\nfunction toTanstackSorting(sorting: DataGridSortModel): SortingState {\n return sorting.map((s) => ({ id: s.columnId, desc: s.direction === \"desc\" }));\n}\n\nfunction fromTanstackSorting(sorting: SortingState): DataGridSortModel {\n return sorting.map((s) => ({ columnId: s.id, direction: s.desc ? \"desc\" : \"asc\" }));\n}\n\nfunction toTanstackRowSelection(ids: ReadonlySet<RowId>): RowSelectionState {\n const out: RowSelectionState = {};\n for (const id of ids) out[id] = true;\n return out;\n}\n\nfunction resolveUpdater<T>(updater: Updater<T>, current: T): T {\n return typeof updater === \"function\" ? (updater as (old: T) => T)(current) : updater;\n}\n\n// ─── Flex column width distribution ──────────────────────────────────\n\nfunction distributeFlexWidths<TRow>(\n sizes: Record<string, number>,\n visibleColumns: readonly DataGridColumnDef<TRow>[],\n available: number,\n): void {\n const flexCols = visibleColumns.filter((c) => c.flex != null && c.flex > 0);\n if (flexCols.length === 0 || available <= 0) return;\n const totalFlex = flexCols.reduce((acc, c) => acc + (c.flex ?? 0), 0);\n let remaining = available;\n flexCols.forEach((col, i) => {\n const isLast = i === flexCols.length - 1;\n const share = isLast\n ? remaining\n : Math.floor(available * ((col.flex ?? 0) / totalFlex));\n const max = col.maxWidth ?? Infinity;\n const add = Math.max(0, Math.min(share, max - sizes[col.id]));\n sizes[col.id] += add;\n remaining -= add;\n });\n}\n\n// ─── Selection logic (with shift-range anchor) ───────────────────────\n\ntype SelectionInput = {\n current: DataGridSelectionModel;\n rowId: RowId;\n mode: \"single\" | \"multiple\";\n modifiers: { shift: boolean; ctrl: boolean };\n allRowIds: readonly RowId[];\n};\n\nfunction selectSingle(current: DataGridSelectionModel, rowId: RowId): DataGridSelectionModel {\n const isSelected = current.selectedIds.has(rowId);\n return {\n selectedIds: isSelected ? new Set() : new Set([rowId]),\n anchorId: isSelected ? null : rowId,\n };\n}\n\nfunction selectRange(\n current: DataGridSelectionModel,\n rowId: RowId,\n allRowIds: readonly RowId[],\n additive: boolean,\n): DataGridSelectionModel | null {\n if (current.anchorId == null) return null;\n const anchorIdx = allRowIds.indexOf(current.anchorId);\n const currentIdx = allRowIds.indexOf(rowId);\n if (anchorIdx < 0 || currentIdx < 0) return null;\n const start = Math.min(anchorIdx, currentIdx);\n const end = Math.max(anchorIdx, currentIdx);\n const next = additive ? new Set(current.selectedIds) : new Set<RowId>();\n for (let i = start; i <= end; i++) next.add(allRowIds[i]!);\n return { selectedIds: next, anchorId: current.anchorId };\n}\n\nfunction selectToggle(current: DataGridSelectionModel, rowId: RowId): DataGridSelectionModel {\n const next = new Set(current.selectedIds);\n if (next.has(rowId)) next.delete(rowId);\n else next.add(rowId);\n return { selectedIds: next, anchorId: rowId };\n}\n\nfunction nextSelection(input: SelectionInput): DataGridSelectionModel {\n const { current, rowId, mode, modifiers, allRowIds } = input;\n if (mode === \"single\") return selectSingle(current, rowId);\n if (modifiers.shift) {\n const range = selectRange(current, rowId, allRowIds, modifiers.ctrl);\n if (range != null) return range;\n }\n if (modifiers.ctrl) return selectToggle(current, rowId);\n return { selectedIds: new Set([rowId]), anchorId: rowId };\n}\n\n// ─── Header cell ─────────────────────────────────────────────────────\n\nfunction HeaderCell<TRow>({\n header,\n col,\n resizable,\n}: {\n header: Header<TRow, unknown>;\n col: DataGridColumnDef<TRow>;\n resizable: boolean;\n}) {\n const sorted = header.column.getIsSorted(); // false | \"asc\" | \"desc\"\n const sortIndex = header.column.getSortIndex();\n const totalSorts = header.column.getCanMultiSort()\n ? header.getContext().table.getState().sorting.length\n : 0;\n const ctx: DataGridHeaderContext<TRow> = {\n columnId: col.id,\n columnDef: col,\n isSorted: sorted === false ? false : sorted,\n sortIndex: totalSorts > 1 && sortIndex >= 0 ? sortIndex + 1 : null,\n };\n const label = typeof col.header === \"function\" ? col.header(ctx) : col.header;\n const sortable = header.column.getCanSort();\n const canResize = resizable && header.column.getCanResize();\n const isResizing = header.column.getIsResizing();\n\n return (\n <div\n className={cn(\n \"group/header relative flex items-center gap-1.5 px-3 select-none bg-transparent overflow-hidden\",\n \"border-r border-black/[0.04] dark:border-white/[0.04] last:border-r-0\",\n sortable && \"cursor-pointer\",\n )}\n style={{ width: `calc(var(--col-${col.id}-size) * 1px)` }}\n data-col-id={col.id}\n onClick={sortable ? header.column.getToggleSortingHandler() : undefined}\n role=\"columnheader\"\n aria-sort={sorted === \"asc\" ? \"ascending\" : sorted === \"desc\" ? \"descending\" : \"none\"}\n >\n <span\n className={cn(\n \"flex-1 min-w-0 truncate text-xs font-semibold uppercase tracking-wider text-muted-foreground\",\n col.align === \"center\" && \"text-center\",\n col.align === \"right\" && \"text-right\",\n )}\n >\n {label}\n </span>\n\n {sorted && (\n <span className=\"flex items-center gap-0.5 text-foreground/60\">\n {sorted === \"asc\"\n ? <ArrowUp className=\"h-3 w-3\" weight=\"bold\" />\n : <ArrowDown className=\"h-3 w-3\" weight=\"bold\" />}\n {ctx.sortIndex != null && (\n <span className=\"text-[10px] font-medium tabular-nums\">{ctx.sortIndex}</span>\n )}\n </span>\n )}\n\n {!sorted && sortable && (\n <span className=\"hidden group-hover/header:flex items-center text-foreground/20\">\n <CaretUp className=\"h-2.5 w-2.5 -mb-[1px]\" weight=\"bold\" />\n <CaretDown className=\"h-2.5 w-2.5 -mt-[1px]\" weight=\"bold\" />\n </span>\n )}\n\n {canResize && (\n <div\n onMouseDown={header.getResizeHandler()}\n onTouchStart={header.getResizeHandler()}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n }}\n className={cn(\n \"absolute right-0 top-0 bottom-0 z-10 w-[5px] cursor-col-resize touch-none\",\n \"group-hover/header:bg-foreground/[0.06] hover:!bg-blue-500/30\",\n \"transition-colors duration-100\",\n isResizing && \"bg-blue-500/40\",\n )}\n />\n )}\n </div>\n );\n}\n\n// ─── Data cell ───────────────────────────────────────────────────────\n\nfunction DataCell<TRow>({\n col,\n row,\n rowId,\n rowIndex,\n isSelected,\n dateDisplay,\n}: {\n col: DataGridColumnDef<TRow>;\n row: TRow;\n rowId: RowId;\n rowIndex: number;\n isSelected: boolean;\n dateDisplay: DataGridDateDisplay;\n}) {\n const value = resolveColumnValue(col, row);\n const ctx: DataGridCellContext<TRow> = { row, rowId, rowIndex, value, columnId: col.id, isSelected, dateDisplay };\n\n const isDateCol = col.type === \"date\" || col.type === \"dateTime\";\n let content: React.ReactNode;\n if (col.renderCell) content = col.renderCell(ctx);\n else if (isDateCol) content = renderDateCell(value, dateDisplay, col);\n else content = formatCellValue(value);\n\n const hasCellClick = col.onCellClick || col.onCellDoubleClick;\n const isWrap = col.cellOverflow === \"wrap\";\n\n return (\n <div\n className={cn(\n \"flex px-3 bg-transparent overflow-hidden\",\n \"border-r border-black/[0.04] dark:border-white/[0.04] last:border-r-0\",\n \"text-sm text-foreground\",\n isWrap ? \"items-start py-2\" : \"items-center\",\n col.align === \"center\" && \"justify-center\",\n col.align === \"right\" && \"justify-end\",\n hasCellClick && \"cursor-pointer\",\n )}\n style={{ width: `calc(var(--col-${col.id}-size) * 1px)` }}\n data-col-id={col.id}\n role=\"gridcell\"\n onClick={col.onCellClick ? (e) => {\n e.stopPropagation();\n col.onCellClick!(ctx, e);\n } : undefined}\n onDoubleClick={col.onCellDoubleClick ? (e) => {\n e.stopPropagation();\n col.onCellDoubleClick!(ctx, e);\n } : undefined}\n >\n <div className={cn(\"min-w-0\", isWrap ? \"flex-1\" : \"truncate\")}>{content}</div>\n </div>\n );\n}\n\nfunction formatCellValue(value: unknown): React.ReactNode {\n if (value == null) return <span className=\"text-muted-foreground/40\">-</span>;\n if (typeof value === \"boolean\") {\n return (\n <span className={cn(\n \"inline-flex items-center px-1.5 py-0.5 rounded-md text-xs font-medium\",\n value\n ? \"bg-emerald-500/10 text-emerald-600 dark:text-emerald-400\"\n : \"bg-foreground/[0.04] text-muted-foreground\",\n )}>\n {value ? \"Yes\" : \"No\"}\n </span>\n );\n }\n if (value instanceof Date) {\n return <span className=\"tabular-nums text-muted-foreground\">{value.toLocaleDateString()}</span>;\n }\n return <span className=\"truncate\">{String(value)}</span>;\n}\n\nfunction renderDateCell<TRow>(\n value: unknown,\n dateDisplay: DataGridDateDisplay,\n col: DataGridColumnDef<TRow>,\n): React.ReactNode {\n const { display, tooltip } = formatGridDate(value, dateDisplay, {\n parseValue: col.parseValue,\n dateFormat: col.dateFormat,\n });\n if (display == null) return <span className=\"text-muted-foreground/40\">-</span>;\n return (\n <span className=\"tabular-nums text-muted-foreground truncate cursor-help\" title={tooltip ?? undefined}>\n {display}\n </span>\n );\n}\n\n// ─── Skeleton row ────────────────────────────────────────────────────\n\nfunction hashStringToInt(value: string): number {\n let hash = 0;\n for (let i = 0; i < value.length; i++) hash = ((hash << 5) - hash + value.charCodeAt(i)) | 0;\n return Math.abs(hash);\n}\n\nfunction SkeletonRow({\n columns,\n height,\n showCheckbox,\n}: {\n columns: readonly DataGridColumnDef<any>[];\n height: number;\n showCheckbox?: boolean;\n}) {\n return (\n <div className=\"flex\" style={{ height }} role=\"row\">\n {showCheckbox && (\n <div className=\"flex items-center justify-center border-r border-black/[0.04] dark:border-white/[0.04]\" style={{ width: 44 }}>\n <DesignSkeleton className=\"h-4 w-4 rounded\" />\n </div>\n )}\n {columns.map((col) => (\n <div\n key={col.id}\n className=\"flex items-center px-3 border-r border-black/[0.04] dark:border-white/[0.04] last:border-r-0\"\n style={{ width: `calc(var(--col-${col.id}-size) * 1px)` }}\n >\n <DesignSkeleton className=\"h-3.5 rounded-md\" style={{ width: `${40 + (hashStringToInt(col.id) % 40)}%` }} />\n </div>\n ))}\n </div>\n );\n}\n\n// ─── Selection checkbox ──────────────────────────────────────────────\n\nfunction SelectionCheckbox({\n checked,\n indeterminate,\n onChange,\n ariaLabel,\n title,\n}: {\n checked: boolean;\n indeterminate?: boolean;\n onChange: (event: React.MouseEvent<HTMLButtonElement>) => void;\n ariaLabel: string;\n title?: string;\n}) {\n const Icon = indeterminate ? MinusSquare : checked ? CheckSquare : Square;\n return (\n <button\n className={cn(\n \"flex items-center justify-center w-full h-full\",\n \"hover:bg-foreground/[0.04] transition-colors duration-75\",\n checked || indeterminate\n ? \"text-blue-600 dark:text-blue-400\"\n : \"text-muted-foreground/40 hover:text-muted-foreground/60\",\n )}\n onClick={(e) => {\n e.stopPropagation();\n onChange(e);\n }}\n aria-label={ariaLabel}\n title={title ?? ariaLabel}\n role=\"checkbox\"\n aria-checked={indeterminate ? \"mixed\" : checked}\n >\n <Icon className=\"h-4 w-4\" weight={checked || indeterminate ? \"fill\" : \"regular\"} />\n </button>\n );\n}\n\n// ─── Infinite scroll sentinel ────────────────────────────────────────\n\nconst NOOP = () => {};\n\nfunction InfiniteScrollSentinel({\n onIntersect,\n isLoading,\n rootRef,\n strings,\n}: {\n onIntersect: () => void;\n isLoading: boolean;\n rootRef?: React.RefObject<Element | null>;\n strings: DataGridStrings;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n // Read `onIntersect` through a ref so the observer never has to be\n // re-created when the callback identity changes. `onLoadMore` (and thus\n // `onIntersect`) changes on every `isLoadingMore`/`hasMore` toggle; if the\n // observer were re-created each time, a freshly-created observer re-reports\n // the sentinel's *current* intersection state, so a sentinel that stays in\n // view keeps firing `onIntersect` after every page. That auto-loads the\n // entire dataset back-to-back (defeating \"load on scroll\") and OOM-crashes\n // the tab on long transaction/customer histories. A single stable observer\n // only fires on genuine intersection *changes* (real user scrolls).\n const onIntersectRef = useRef(onIntersect);\n onIntersectRef.current = onIntersect;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const observer = new IntersectionObserver(\n (entries) => { if (entries[0]?.isIntersecting) onIntersectRef.current(); },\n { root: rootRef?.current ?? null, rootMargin: \"200px\" },\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [rootRef]);\n return (\n <div ref={ref} className=\"flex items-center justify-center py-4\">\n {isLoading && (\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <div className=\"h-3 w-3 rounded-full border-2 border-current border-t-transparent animate-spin\" />\n {strings.loadingMore}\n </div>\n )}\n </div>\n );\n}\n\n// ─── Footer ──────────────────────────────────────────────────────────\n\nfunction DefaultFooter<TRow>({\n ctx,\n pagination,\n onChange,\n}: {\n ctx: DataGridFooterContext<TRow>;\n pagination: DataGridPaginationMode;\n onChange: React.Dispatch<React.SetStateAction<DataGridState>>;\n}) {\n const { state, totalRowCount, visibleRowCount, selectedRowCount, strings } = ctx;\n const totalPages = totalRowCount != null\n ? Math.max(1, Math.ceil(totalRowCount / state.pagination.pageSize))\n : undefined;\n\n const setPage = (pageIndex: number) =>\n onChange((s) => ({ ...s, pagination: { ...s.pagination, pageIndex } }));\n const setPageSize = (pageSize: number) =>\n onChange((s) => ({ ...s, pagination: { ...s.pagination, pageSize, pageIndex: 0 } }));\n\n return (\n <div className=\"flex items-center justify-between px-4 py-2.5 border-t border-foreground/[0.06] text-xs text-muted-foreground\">\n <div className=\"flex items-center gap-3\">\n {selectedRowCount > 0 && (\n <span className=\"font-medium text-foreground\">{strings.rowsSelected(selectedRowCount)}</span>\n )}\n {totalRowCount != null && <span>{visibleRowCount} of {totalRowCount} rows</span>}\n </div>\n\n {pagination !== \"infinite\" && totalPages != null && (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex items-center gap-1.5\">\n <span>{strings.rowsPerPage}</span>\n <select\n className={cn(\n \"h-7 rounded-lg border border-black/[0.08] dark:border-white/[0.06] px-1.5\",\n \"bg-white dark:bg-background shadow-sm ring-1 ring-black/[0.08] dark:ring-white/[0.06]\",\n \"text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-foreground/[0.1]\",\n \"cursor-pointer transition-all duration-150 hover:transition-none hover:ring-black/[0.12] dark:hover:ring-white/[0.1]\",\n )}\n value={state.pagination.pageSize}\n onChange={(e) => setPageSize(Number(e.target.value))}\n >\n {[10, 25, 50, 100].map((size) => <option key={size} value={size}>{size}</option>)}\n </select>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n className={cn(\n \"h-7 w-7 flex items-center justify-center rounded-lg\",\n \"hover:bg-foreground/[0.04] disabled:opacity-30 disabled:cursor-not-allowed\",\n \"transition-colors duration-75\",\n )}\n onClick={() => setPage(state.pagination.pageIndex - 1)}\n disabled={state.pagination.pageIndex === 0}\n aria-label=\"Previous page\"\n >\n <CaretUp className=\"h-3.5 w-3.5 -rotate-90\" weight=\"bold\" />\n </button>\n <span className=\"px-2 tabular-nums font-medium\">\n {strings.pageOf(state.pagination.pageIndex + 1, totalPages)}\n </span>\n <button\n className={cn(\n \"h-7 w-7 flex items-center justify-center rounded-lg\",\n \"hover:bg-foreground/[0.04] disabled:opacity-30 disabled:cursor-not-allowed\",\n \"transition-colors duration-75\",\n )}\n onClick={() => setPage(state.pagination.pageIndex + 1)}\n disabled={state.pagination.pageIndex >= totalPages - 1}\n aria-label=\"Next page\"\n >\n <CaretDown className=\"h-3.5 w-3.5 -rotate-90\" weight=\"bold\" />\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// ─── Main DataGrid ───────────────────────────────────────────────────\n\n/**\n * Interactive table built on TanStack Table v8. Sorting, column sizing,\n * visibility, ordering, and pinning are owned by the table instance; we\n * layer virtualization, sticky toolbar/header/footer, infinite scroll,\n * quick search, CSV export, and date-format toggling on top.\n *\n * The grid is display-only — it does not fetch or page data itself. Pair\n * with `useDataSource` for client- or server-side data and pass the\n * already-processed slice through `rows`.\n *\n * ```tsx\n * const columns = useMemo(() => [...], []);\n * const [gridState, setGridState] = useState(() => createDefaultDataGridState(columns));\n * const gridData = useDataSource({\n * data: users, columns, getRowId: (r) => r.id,\n * sorting: gridState.sorting,\n * quickSearch: gridState.quickSearch,\n * pagination: gridState.pagination,\n * paginationMode: \"client\",\n * });\n *\n * <DataGrid\n * columns={columns}\n * rows={gridData.rows}\n * getRowId={(r) => r.id}\n * totalRowCount={gridData.totalRowCount}\n * isLoading={gridData.isLoading}\n * state={gridState}\n * onChange={setGridState}\n * />\n * ```\n *\n * Iron rules:\n * - `rows` is always `gridData.rows`, never your raw array.\n * - Columns must be stable (define outside the component or wrap in `useMemo`).\n * - Initialize state with `createDefaultDataGridState(columns)`.\n * - `renderCell` must be a pure function — no React hooks inside.\n */\nexport function DataGrid<TRow>(props: DataGridProps<TRow>) {\n const {\n columns: allColumns,\n rows,\n getRowId,\n totalRowCount,\n isLoading = false,\n isRefetching = false,\n hasMore = false,\n isLoadingMore = false,\n onLoadMore,\n state,\n onChange,\n paginationMode = \"paginated\",\n selectionMode = \"none\",\n resizable = true,\n rowHeight: rowHeightProp = 44,\n estimatedRowHeight: estimatedRowHeightProp,\n headerHeight = 44,\n overscan = 5,\n maxHeight,\n fillHeight = true,\n stickyTop,\n toolbar,\n toolbarExtra,\n emptyState,\n loadingState,\n footer,\n footerExtra,\n exportFilename = \"export\",\n exportOptions,\n strings: stringsOverride,\n className,\n onRowClick,\n onRowDoubleClick,\n onSelectionChange,\n onSortChange,\n onColumnResize,\n onColumnVisibilityChange,\n } = props;\n\n const isDynamicRowHeight = rowHeightProp === \"auto\";\n const fixedRowHeight = isDynamicRowHeight ? undefined : rowHeightProp;\n const estimatedRowHeight = estimatedRowHeightProp ?? (fixedRowHeight ?? 44);\n\n const strings = useMemo(() => resolveDataGridStrings(stringsOverride), [stringsOverride]);\n\n // ── Build TanStack column defs from our column defs ──────────\n const tableColumns = useMemo<ColumnDef<TRow>[]>(\n () =>\n allColumns.map((col) => ({\n id: col.id,\n accessorFn: (row) => resolveColumnValue(col, row),\n header: typeof col.header === \"string\" ? col.header : col.id,\n size: col.width ?? DEFAULT_COL_WIDTH,\n minSize: getEffectiveMinWidth(col),\n maxSize: getEffectiveMaxWidth(col),\n enableSorting: col.sortable !== false,\n enableHiding: col.hideable !== false,\n enableResizing: col.resizable !== false,\n enableMultiSort: true,\n })),\n [allColumns],\n );\n\n // ── Translate our state ⇄ TanStack state via change handlers ───\n const tanstackSorting = useMemo(() => toTanstackSorting(state.sorting), [state.sorting]);\n const tanstackRowSelection = useMemo(\n () => toTanstackRowSelection(state.selection.selectedIds),\n [state.selection.selectedIds],\n );\n // ColumnSizing/Visibility/Order/Pinning share the same shape with TanStack.\n const tanstackColumnPinning = useMemo<ColumnPinningState>(\n () => ({ left: [...state.columnPinning.left], right: [...state.columnPinning.right] }),\n [state.columnPinning],\n );\n const tanstackColumnOrder = useMemo<ColumnOrderState>(\n () => [...state.columnOrder],\n [state.columnOrder],\n );\n\n const allColumnsRef = useRef(allColumns);\n allColumnsRef.current = allColumns;\n\n const handleSortingChange = useCallback(\n (updater: Updater<SortingState>) => {\n const next = resolveUpdater(updater, toTanstackSorting(state.sorting));\n const ours: DataGridSortItem[] = fromTanstackSorting(next).map((s) => ({ ...s }));\n // Reset to page 0 — page N of the new sort order is meaningless when\n // the order itself changed, and would silently scroll past relevant\n // rows.\n onChange((s) => ({\n ...s,\n sorting: ours,\n pagination: { ...s.pagination, pageIndex: 0 },\n }));\n onSortChange?.(ours);\n },\n [onChange, onSortChange, state.sorting],\n );\n\n const handleColumnSizingChange = useCallback(\n (updater: Updater<ColumnSizingState>) => {\n const next = resolveUpdater(updater, state.columnWidths);\n // Clamp each new width to our canvas-measured min and explicit max.\n const clamped: Record<string, number> = {};\n for (const [id, w] of Object.entries(next)) {\n const col = allColumnsRef.current.find((c) => c.id === id);\n clamped[id] = col ? clampColumnWidth(col, w) : w;\n }\n onChange((s) => ({ ...s, columnWidths: clamped }));\n // Fire onColumnResize for any column whose width changed.\n if (onColumnResize) {\n for (const [id, w] of Object.entries(clamped)) {\n if (state.columnWidths[id] !== w) onColumnResize(id, w);\n }\n }\n },\n [onChange, onColumnResize, state.columnWidths],\n );\n\n const handleVisibilityChange = useCallback(\n (updater: Updater<VisibilityState>) => {\n const next = resolveUpdater(updater, state.columnVisibility);\n onChange((s) => ({ ...s, columnVisibility: next }));\n onColumnVisibilityChange?.(next);\n },\n [onChange, onColumnVisibilityChange, state.columnVisibility],\n );\n\n const handleColumnOrderChange = useCallback(\n (updater: Updater<ColumnOrderState>) => {\n const next = resolveUpdater(updater, [...state.columnOrder]);\n onChange((s) => ({ ...s, columnOrder: next }));\n },\n [onChange, state.columnOrder],\n );\n\n const handleColumnPinningChange = useCallback(\n (updater: Updater<ColumnPinningState>) => {\n const current: ColumnPinningState = {\n left: [...state.columnPinning.left],\n right: [...state.columnPinning.right],\n };\n const next = resolveUpdater(updater, current);\n onChange((s) => ({\n ...s,\n columnPinning: { left: next.left ?? [], right: next.right ?? [] },\n }));\n },\n [onChange, state.columnPinning],\n );\n\n // ── TanStack Table instance ──────────────────────────────────\n const table = useReactTable<TRow>({\n data: rows as TRow[],\n columns: tableColumns,\n getRowId: (row) => getRowId(row),\n getCoreRowModel: getCoreRowModel(),\n state: {\n sorting: tanstackSorting,\n columnVisibility: state.columnVisibility,\n columnSizing: state.columnWidths,\n columnOrder: tanstackColumnOrder,\n columnPinning: tanstackColumnPinning,\n rowSelection: tanstackRowSelection,\n },\n onSortingChange: handleSortingChange,\n onColumnSizingChange: handleColumnSizingChange,\n onColumnVisibilityChange: handleVisibilityChange,\n onColumnOrderChange: handleColumnOrderChange,\n onColumnPinningChange: handleColumnPinningChange,\n columnResizeMode: \"onEnd\",\n enableRowSelection: selectionMode !== \"none\",\n enableMultiRowSelection: selectionMode === \"multiple\",\n enableColumnResizing: resizable,\n manualSorting: true,\n manualPagination: true,\n manualFiltering: true,\n });\n\n // ── Visible columns (in TanStack-resolved order, after visibility) ──\n const visibleColumns = useMemo(() => {\n const colMap = new Map(allColumns.map((c) => [c.id, c]));\n return table\n .getVisibleLeafColumns()\n .map((c) => colMap.get(c.id))\n .filter(Boolean) as DataGridColumnDef<TRow>[];\n }, [allColumns, table, state.columnOrder, state.columnVisibility]);\n\n // ── Row IDs (stable across this render) ──────────────────────\n const rowIds = useMemo(() => rows.map(getRowId), [rows, getRowId]);\n\n // ── Container width tracking (for `flex` column distribution) ─\n // Measure the scroll container's clientWidth, which excludes the vertical\n // scrollbar — using the outer grid would leave a few pixels of phantom\n // horizontal scroll when rows overflow.\n const [containerWidth, setContainerWidth] = useState(0);\n useLayoutEffect(() => {\n const grid = gridRef.current;\n const scroller = scrollContainerRef.current;\n if (!grid) return;\n const update = (entries?: ResizeObserverEntry[]) => {\n let measured = 0;\n if (entries != null) {\n for (const entry of entries) {\n measured = Math.max(measured, entry.contentRect.width);\n }\n }\n if (measured <= 0) {\n const scrollerWidth = scroller?.clientWidth ?? 0;\n const gridWidth = grid.clientWidth;\n measured = scrollerWidth > 0 ? scrollerWidth : gridWidth;\n }\n if (measured > 0) setContainerWidth(measured);\n };\n update();\n const observer = new ResizeObserver((entries) => update(entries));\n observer.observe(grid);\n if (scroller) observer.observe(scroller);\n return () => observer.disconnect();\n }, []);\n\n // ── Column width CSS variables (TanStack pattern) ────────────\n // With `columnResizeMode: \"onEnd\"`, live drag width comes from deltaOffset; committed sizes update on pointer-up.\n const columnSizingInfo = table.getState().columnSizingInfo;\n const columnSizes = useMemo<Record<string, number>>(() => {\n const sizes: Record<string, number> = {};\n let baseTotal = selectionMode !== \"none\" ? 44 : 0;\n const resizingId = columnSizingInfo.isResizingColumn || null;\n const deltaOffset = columnSizingInfo.deltaOffset ?? 0;\n for (const col of visibleColumns) {\n const tsCol = table.getColumn(col.id);\n const baseSize = tsCol?.getSize() ?? col.width ?? DEFAULT_COL_WIDTH;\n const liveSize = resizingId === col.id\n ? clampColumnWidth(col, baseSize + deltaOffset)\n : baseSize;\n sizes[col.id] = liveSize;\n baseTotal += liveSize;\n }\n distributeFlexWidths(sizes, visibleColumns, containerWidth - baseTotal);\n return sizes;\n }, [visibleColumns, table, columnSizingInfo, state.columnWidths, containerWidth, selectionMode]);\n\n const totalContentWidth = useMemo(() => {\n let total = selectionMode !== \"none\" ? 44 : 0;\n for (const col of visibleColumns) total += columnSizes[col.id] ?? 0;\n return total;\n }, [visibleColumns, columnSizes, selectionMode]);\n\n const cssVars = useMemo<CSSProperties>(() => {\n const vars: Record<string, string | number> = { \"--grid-total-w\": `${totalContentWidth}px` };\n for (const col of visibleColumns) {\n vars[`--col-${col.id}-size`] = columnSizes[col.id];\n }\n return vars as CSSProperties;\n }, [visibleColumns, columnSizes, totalContentWidth]);\n\n // ── Selection handlers ───────────────────────────────────────\n const fireSelection = useCallback(\n (next: DataGridSelectionModel) => {\n onChange((s) => ({ ...s, selection: next }));\n if (onSelectionChange) {\n const idSet = next.selectedIds;\n const selectedRows = rows.filter((r) => idSet.has(getRowId(r)));\n onSelectionChange(idSet, selectedRows);\n }\n },\n [onChange, onSelectionChange, rows, getRowId],\n );\n\n const handleRowClick = useCallback(\n (row: TRow, rowId: RowId, event: React.MouseEvent) => {\n if (selectionMode !== \"none\") {\n const next = nextSelection({\n current: state.selection,\n rowId,\n mode: selectionMode,\n modifiers: { shift: event.shiftKey, ctrl: event.metaKey || event.ctrlKey },\n allRowIds: rowIds,\n });\n fireSelection(next);\n }\n onRowClick?.(row, rowId, event);\n },\n [selectionMode, state.selection, rowIds, fireSelection, onRowClick],\n );\n\n const handleSelectAll = useCallback(() => {\n const allSelectedNow = rowIds.length > 0 && rowIds.every((id) => state.selection.selectedIds.has(id));\n fireSelection(\n allSelectedNow\n ? { selectedIds: new Set(), anchorId: null }\n : { selectedIds: new Set(rowIds), anchorId: null },\n );\n }, [rowIds, state.selection.selectedIds, fireSelection]);\n\n // ── Export ───────────────────────────────────────────────────\n const [exportDialogOpen, setExportDialogOpen] = useState(false);\n const handleExportCsv = useCallback(() => {\n setExportDialogOpen(true);\n }, []);\n\n // ── Virtualizer ──────────────────────────────────────────────\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const headerScrollRef = useRef<HTMLDivElement>(null);\n const stickyChromeRef = useRef<HTMLDivElement>(null);\n const rowsClipRef = useRef<HTMLDivElement>(null);\n const gridRef = useRef<HTMLDivElement>(null);\n const measureElementFn = useCallback((el: Element) => el.getBoundingClientRect().height, []);\n\n const rowVirtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => scrollContainerRef.current,\n estimateSize: () => estimatedRowHeight,\n overscan,\n getItemKey: (index) => {\n const row = rows[index];\n return row != null ? String(getRowId(row)) : index;\n },\n ...(isDynamicRowHeight ? { measureElement: measureElementFn } : {}),\n });\n\n // ── Sticky chrome clipping ───────────────────────────────────\n useLayoutEffect(() => {\n const gridEl = gridRef.current;\n const stickyEl = stickyChromeRef.current;\n const bodyEl = scrollContainerRef.current;\n const clipEl = rowsClipRef.current;\n if (!gridEl || !stickyEl || !bodyEl || !clipEl) return;\n\n const updateClip = () => {\n const stickyRect = stickyEl.getBoundingClientRect();\n const clipRect = clipEl.getBoundingClientRect();\n const overlap = Math.max(0, stickyRect.bottom - clipRect.top);\n clipEl.style.setProperty(\"--data-grid-sticky-overlap\", `${overlap}px`);\n };\n updateClip();\n bodyEl.addEventListener(\"scroll\", updateClip);\n window.addEventListener(\"scroll\", updateClip, true);\n window.addEventListener(\"resize\", updateClip);\n const observer = new ResizeObserver(updateClip);\n observer.observe(gridEl);\n observer.observe(stickyEl);\n observer.observe(bodyEl);\n return () => {\n bodyEl.removeEventListener(\"scroll\", updateClip);\n window.removeEventListener(\"scroll\", updateClip, true);\n window.removeEventListener(\"resize\", updateClip);\n observer.disconnect();\n };\n }, []);\n\n const handleBodyScroll = useCallback(() => {\n const body = scrollContainerRef.current;\n const header = headerScrollRef.current;\n if (body && header) header.scrollLeft = body.scrollLeft;\n }, []);\n\n // ── Toolbar / Footer context ─────────────────────────────────\n const toolbarCtx: DataGridToolbarContext<TRow> = useMemo(\n () => ({\n state,\n onChange,\n columns: allColumns,\n visibleColumns,\n totalRowCount,\n selectedRowCount: state.selection.selectedIds.size,\n strings,\n exportCsv: handleExportCsv,\n }),\n [state, onChange, allColumns, visibleColumns, totalRowCount, strings, handleExportCsv],\n );\n const footerCtx: DataGridFooterContext<TRow> = useMemo(\n () => ({\n state,\n totalRowCount,\n visibleRowCount: rows.length,\n selectedRowCount: state.selection.selectedIds.size,\n paginationMode,\n strings,\n }),\n [state, totalRowCount, rows.length, paginationMode, strings],\n );\n\n const allSelected = rowIds.length > 0 && rowIds.every((id) => state.selection.selectedIds.has(id));\n const someSelected = !allSelected && rowIds.some((id) => state.selection.selectedIds.has(id));\n const infiniteScrollRootRef =\n paginationMode === \"infinite\" && (fillHeight || maxHeight != null)\n ? scrollContainerRef\n : undefined;\n\n // ── Header rendering helper (TanStack header objects, in order) ──\n const headers: Header<TRow, unknown>[] = useMemo(\n () =>\n table\n .getHeaderGroups()[0]?.headers\n .filter((h) => visibleColumns.some((c) => c.id === h.column.id)) ?? [],\n [table, visibleColumns],\n );\n const headerByColId = useMemo(() => {\n const m = new Map<string, Header<TRow, unknown>>();\n for (const h of headers) m.set(h.column.id, h);\n return m;\n }, [headers]);\n\n const isBounded = fillHeight || maxHeight != null;\n\n return (\n <>\n <DataGridExportDialog\n open={exportDialogOpen}\n onOpenChange={setExportDialogOpen}\n rows={rows}\n columns={visibleColumns}\n exportFilename={exportFilename}\n exportOptions={exportOptions}\n />\n <div\n ref={gridRef}\n className={cn(\n \"isolate flex w-full min-w-0 max-w-full flex-col bg-transparent rounded-[calc(var(--radius)*2)]\",\n fillHeight ? \"min-h-0 h-full\" : \"min-h-0 h-auto\",\n isBounded && \"overflow-hidden\",\n className,\n )}\n style={maxHeight != null ? { ...cssVars, maxHeight } : cssVars}\n role=\"grid\"\n aria-rowcount={totalRowCount ?? rows.length}\n aria-colcount={visibleColumns.length}\n >\n <div\n ref={stickyChromeRef}\n className=\"sticky z-30 w-full min-w-0 shrink-0 overflow-visible rounded-t-[calc(var(--radius)*2)] bg-white/90 dark:bg-background backdrop-blur-xl\"\n style={{ top: stickyTop ?? (maxHeight != null ? 0 : \"var(--data-grid-sticky-top, 0px)\") }}\n >\n {toolbar !== false && (\n <div className=\"relative bg-transparent\">\n {toolbar\n ? toolbar(toolbarCtx)\n : (\n <DataGridToolbar\n ctx={toolbarCtx}\n extra={typeof toolbarExtra === \"function\" ? toolbarExtra(toolbarCtx) : toolbarExtra}\n />\n )}\n </div>\n )}\n\n <div className=\"relative\">\n {isRefetching && (\n <div className=\"absolute top-0 left-0 right-0 h-0.5 z-30 bg-foreground/[0.04] overflow-hidden\">\n <div className=\"h-full w-1/3 bg-blue-500/60 rounded-full animate-pulse\" />\n </div>\n )}\n <div\n ref={headerScrollRef}\n className=\"w-full min-w-0 shrink-0 overflow-hidden border-b border-foreground/[0.06]\"\n >\n <div\n className=\"flex\"\n style={{ height: headerHeight, minWidth: totalContentWidth }}\n role=\"row\"\n >\n {selectionMode !== \"none\" && (\n <div\n className=\"flex items-center justify-center border-r border-foreground/[0.04]\"\n style={{ width: 44 }}\n >\n {selectionMode === \"multiple\" && (\n <SelectionCheckbox\n checked={allSelected}\n indeterminate={someSelected}\n onChange={handleSelectAll}\n ariaLabel=\"Select all rows on this page\"\n title=\"Select all rows on this page\"\n />\n )}\n </div>\n )}\n {visibleColumns.map((col) => {\n const header = headerByColId.get(col.id);\n if (!header) return null;\n return <HeaderCell key={col.id} header={header} col={col} resizable={resizable} />;\n })}\n </div>\n </div>\n </div>\n </div>\n\n <div\n ref={scrollContainerRef}\n className={cn(\n \"relative z-0 w-full min-w-0 overflow-auto bg-transparent\",\n isBounded ? \"min-h-0 flex-1\" : \"flex-none\",\n \"[&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar]:h-1.5\",\n \"[&::-webkit-scrollbar-track]:bg-transparent\",\n \"[&::-webkit-scrollbar-thumb]:bg-foreground/[0.08] [&::-webkit-scrollbar-thumb]:rounded-full\",\n \"[&::-webkit-scrollbar-thumb]:hover:bg-foreground/[0.15]\",\n )}\n onScroll={handleBodyScroll}\n >\n <div\n ref={rowsClipRef}\n data-data-grid-rows-clip=\"\"\n className=\"relative z-0\"\n style={{\n minWidth: totalContentWidth,\n clipPath: \"inset(var(--data-grid-sticky-overlap, 0px) 0 0 0)\",\n }}\n >\n {isLoading && (\n <div style={{ minWidth: totalContentWidth }}>\n {loadingState ?? Array.from({ length: 8 }).map((_, i) => (\n <SkeletonRow\n key={i}\n columns={visibleColumns}\n height={estimatedRowHeight}\n showCheckbox={selectionMode !== \"none\"}\n />\n ))}\n </div>\n )}\n\n {!isLoading && rows.length === 0 && (\n <div\n className=\"flex items-center justify-center py-16 text-sm text-muted-foreground\"\n style={{ minWidth: totalContentWidth }}\n >\n {emptyState ?? strings.noData}\n </div>\n )}\n\n {!isLoading && rows.length > 0 && (\n <div\n style={{\n height: rowVirtualizer.getTotalSize(),\n width: \"100%\",\n minWidth: totalContentWidth,\n position: \"relative\",\n }}\n >\n {rowVirtualizer.getVirtualItems().map((virtualRow: VirtualItem) => {\n const row = rows[virtualRow.index] ?? throwErr(\n `DataGrid: virtualized row index ${virtualRow.index} out of range (rows.length=${rows.length})`,\n );\n const rowId = getRowId(row);\n const isSelected = state.selection.selectedIds.has(rowId);\n const isOddRow = virtualRow.index % 2 === 1;\n return (\n <div\n key={rowId}\n ref={isDynamicRowHeight ? rowVirtualizer.measureElement : undefined}\n data-index={virtualRow.index}\n className={cn(\n \"absolute left-0 w-full flex\",\n \"border-b border-black/[0.03] dark:border-white/[0.03]\",\n \"transition-colors duration-75\",\n isSelected\n ? \"bg-blue-500/[0.06] dark:bg-blue-400/[0.08] hover:bg-blue-500/[0.08] dark:hover:bg-blue-400/[0.1]\"\n : isOddRow\n ? \"bg-foreground/[0.02] dark:bg-foreground/[0.03] hover:bg-foreground/[0.04] dark:hover:bg-foreground/[0.06]\"\n : \"hover:bg-foreground/[0.025] dark:hover:bg-foreground/[0.04]\",\n (selectionMode !== \"none\" || onRowClick) && \"cursor-pointer\",\n )}\n style={{\n ...(isDynamicRowHeight\n ? { minHeight: estimatedRowHeight }\n : { height: fixedRowHeight }),\n transform: `translateY(${virtualRow.start}px)`,\n }}\n onClick={(e) => { if (!shouldIgnoreRowClick(e)) handleRowClick(row, rowId, e); }}\n onDoubleClick={(e) => { if (!shouldIgnoreRowClick(e)) onRowDoubleClick?.(row, rowId, e); }}\n role=\"row\"\n aria-rowindex={virtualRow.index + 2}\n aria-selected={isSelected}\n data-row-id={rowId}\n data-state={isSelected ? \"selected\" : undefined}\n >\n {selectionMode !== \"none\" && (\n <div\n className=\"flex items-center justify-center border-r border-black/[0.04] dark:border-white/[0.04]\"\n style={{ width: 44 }}\n >\n <SelectionCheckbox\n checked={isSelected}\n onChange={(event) => handleRowClick(row, rowId, event)}\n ariaLabel={`Select row ${rowId}`}\n />\n </div>\n )}\n {visibleColumns.map((col) => (\n <DataCell\n key={col.id}\n col={col}\n row={row}\n rowId={rowId}\n rowIndex={virtualRow.index}\n isSelected={isSelected}\n dateDisplay={state.dateDisplay}\n />\n ))}\n </div>\n );\n })}\n </div>\n )}\n\n {paginationMode === \"infinite\" && hasMore && !isLoading && (\n <InfiniteScrollSentinel\n onIntersect={onLoadMore ?? NOOP}\n isLoading={isLoadingMore}\n rootRef={infiniteScrollRootRef}\n strings={strings}\n />\n )}\n </div>\n </div>\n\n {footer !== false && (\n <div className=\"sticky bottom-0 z-30 shrink-0 overflow-hidden rounded-b-[calc(var(--radius)*2)] bg-white/90 dark:bg-background backdrop-blur-xl\">\n {footer ? footer(footerCtx) : <DefaultFooter ctx={footerCtx} pagination={paginationMode} onChange={onChange} />}\n {footerExtra && (typeof footerExtra === \"function\" ? footerExtra(footerCtx) : footerExtra)}\n </div>\n )}\n </div>\n </>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AA8DA,SAAS,sBAAsB,QAA4C;CACzE,IAAI,kBAAkB,SAAS,OAAO;CACtC,IAAI,kBAAkB,MAAM,OAAO,OAAO;CAC1C,OAAO;AACT;AAEA,SAAgB,oCAAoC,QAAqC;CAEvF,OADW,sBAAsB,MACzB,CAAC,EAAE,QAAQ;EACjB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK;AAClB;AAEA,SAAS,qBAAqB,OAAkC;CAC9D,OAAO,MAAM,oBAAoB,oCAAoC,MAAM,MAAM;AACnF;AAIA,SAAS,kBAAkB,SAA0C;CACnE,OAAO,QAAQ,KAAK,OAAO;EAAE,IAAI,EAAE;EAAU,MAAM,EAAE,cAAc;CAAO,EAAE;AAC9E;AAEA,SAAS,oBAAoB,SAA0C;CACrE,OAAO,QAAQ,KAAK,OAAO;EAAE,UAAU,EAAE;EAAI,WAAW,EAAE,OAAO,SAAS;CAAM,EAAE;AACpF;AAEA,SAAS,uBAAuB,KAA4C;CAC1E,MAAM,MAAyB,CAAC;CAChC,KAAK,MAAM,MAAM,KAAK,IAAI,MAAM;CAChC,OAAO;AACT;AAEA,SAAS,eAAkB,SAAqB,SAAe;CAC7D,OAAO,OAAO,YAAY,aAAc,QAA0B,OAAO,IAAI;AAC/E;AAIA,SAAS,qBACP,OACA,gBACA,WACM;CACN,MAAM,WAAW,eAAe,QAAQ,MAAM,EAAE,QAAQ,QAAQ,EAAE,OAAO,CAAC;CAC1E,IAAI,SAAS,WAAW,KAAK,aAAa,GAAG;CAC7C,MAAM,YAAY,SAAS,QAAQ,KAAK,MAAM,OAAO,EAAE,QAAQ,IAAI,CAAC;CACpE,IAAI,YAAY;CAChB,SAAS,SAAS,KAAK,MAAM;EAE3B,MAAM,QADS,MAAM,SAAS,SAAS,IAEnC,YACA,KAAK,MAAM,cAAc,IAAI,QAAQ,KAAK,UAAU;EACxD,MAAM,MAAM,IAAI,YAAY;EAC5B,MAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM,MAAM,IAAI,GAAG,CAAC;EAC5D,MAAM,IAAI,OAAO;EACjB,aAAa;CACf,CAAC;AACH;AAYA,SAAS,aAAa,SAAiC,OAAsC;CAC3F,MAAM,aAAa,QAAQ,YAAY,IAAI,KAAK;CAChD,OAAO;EACL,aAAa,6BAAa,IAAI,IAAI,oBAAI,IAAI,IAAI,CAAC,KAAK,CAAC;EACrD,UAAU,aAAa,OAAO;CAChC;AACF;AAEA,SAAS,YACP,SACA,OACA,WACA,UAC+B;CAC/B,IAAI,QAAQ,YAAY,MAAM,OAAO;CACrC,MAAM,YAAY,UAAU,QAAQ,QAAQ,QAAQ;CACpD,MAAM,aAAa,UAAU,QAAQ,KAAK;CAC1C,IAAI,YAAY,KAAK,aAAa,GAAG,OAAO;CAC5C,MAAM,QAAQ,KAAK,IAAI,WAAW,UAAU;CAC5C,MAAM,MAAM,KAAK,IAAI,WAAW,UAAU;CAC1C,MAAM,OAAO,WAAW,IAAI,IAAI,QAAQ,WAAW,oBAAI,IAAI,IAAW;CACtE,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,KAAK,KAAK,IAAI,UAAU,EAAG;CACzD,OAAO;EAAE,aAAa;EAAM,UAAU,QAAQ;CAAS;AACzD;AAEA,SAAS,aAAa,SAAiC,OAAsC;CAC3F,MAAM,OAAO,IAAI,IAAI,QAAQ,WAAW;CACxC,IAAI,KAAK,IAAI,KAAK,GAAG,KAAK,OAAO,KAAK;MACjC,KAAK,IAAI,KAAK;CACnB,OAAO;EAAE,aAAa;EAAM,UAAU;CAAM;AAC9C;AAEA,SAAS,cAAc,OAA+C;CACpE,MAAM,EAAE,SAAS,OAAO,MAAM,WAAW,cAAc;CACvD,IAAI,SAAS,UAAU,OAAO,aAAa,SAAS,KAAK;CACzD,IAAI,UAAU,OAAO;EACnB,MAAM,QAAQ,YAAY,SAAS,OAAO,WAAW,UAAU,IAAI;EACnE,IAAI,SAAS,MAAM,OAAO;CAC5B;CACA,IAAI,UAAU,MAAM,OAAO,aAAa,SAAS,KAAK;CACtD,OAAO;EAAE,6BAAa,IAAI,IAAI,CAAC,KAAK,CAAC;EAAG,UAAU;CAAM;AAC1D;AAIA,SAAS,WAAiB,EACxB,QACA,KACA,aAKC;CACD,MAAM,SAAS,OAAO,OAAO,YAAY;CACzC,MAAM,YAAY,OAAO,OAAO,aAAa;CAC7C,MAAM,aAAa,OAAO,OAAO,gBAAgB,IAC7C,OAAO,WAAW,CAAC,CAAC,MAAM,SAAS,CAAC,CAAC,QAAQ,SAC7C;CACJ,MAAM,MAAmC;EACvC,UAAU,IAAI;EACd,WAAW;EACX,UAAU,WAAW,QAAQ,QAAQ;EACrC,WAAW,aAAa,KAAK,aAAa,IAAI,YAAY,IAAI;CAChE;CACA,MAAM,QAAQ,OAAO,IAAI,WAAW,aAAa,IAAI,OAAO,GAAG,IAAI,IAAI;CACvE,MAAM,WAAW,OAAO,OAAO,WAAW;CAC1C,MAAM,YAAY,aAAa,OAAO,OAAO,aAAa;CAC1D,MAAM,aAAa,OAAO,OAAO,cAAc;CAE/C,OACE,qBAAC,OAAD;EACE,WAAW,GACT,mGACA,yEACA,YAAY,gBACd;EACA,OAAO,EAAE,OAAO,kBAAkB,IAAI,GAAG,eAAe;EACxD,eAAa,IAAI;EACjB,SAAS,WAAW,OAAO,OAAO,wBAAwB,IAAI,KAAA;EAC9D,MAAK;EACL,aAAW,WAAW,QAAQ,cAAc,WAAW,SAAS,eAAe;YAVjF;GAYE,oBAAC,QAAD;IACE,WAAW,GACT,gGACA,IAAI,UAAU,YAAY,eAC1B,IAAI,UAAU,WAAW,YAC3B;cAEC;GACG,CAAA;GAEL,UACC,qBAAC,QAAD;IAAM,WAAU;cAAhB,CACG,WAAW,QACR,oBAAC,SAAD;KAAS,WAAU;KAAU,QAAO;IAAQ,CAAA,IAC5C,oBAAC,WAAD;KAAW,WAAU;KAAU,QAAO;IAAQ,CAAA,GACjD,IAAI,aAAa,QAChB,oBAAC,QAAD;KAAM,WAAU;eAAwC,IAAI;IAAgB,CAAA,CAE1E;;GAGP,CAAC,UAAU,YACV,qBAAC,QAAD;IAAM,WAAU;cAAhB,CACE,oBAAC,SAAD;KAAS,WAAU;KAAwB,QAAO;IAAQ,CAAA,GAC1D,oBAAC,WAAD;KAAW,WAAU;KAAwB,QAAO;IAAQ,CAAA,CACxD;;GAGP,aACC,oBAAC,OAAD;IACE,aAAa,OAAO,iBAAiB;IACrC,cAAc,OAAO,iBAAiB;IACtC,UAAU,MAAM;KACd,EAAE,eAAe;KACjB,EAAE,gBAAgB;IACpB;IACA,WAAW,GACT,6EACA,iEACA,kCACA,cAAc,gBAChB;GACD,CAAA;EAEA;;AAET;AAIA,SAAS,SAAe,EACtB,KACA,KACA,OACA,UACA,YACA,eAQC;CACD,MAAM,QAAQ,mBAAmB,KAAK,GAAG;CACzC,MAAM,MAAiC;EAAE;EAAK;EAAO;EAAU;EAAO,UAAU,IAAI;EAAI;EAAY;CAAY;CAEhH,MAAM,YAAY,IAAI,SAAS,UAAU,IAAI,SAAS;CACtD,IAAI;CACJ,IAAI,IAAI,YAAY,UAAU,IAAI,WAAW,GAAG;MAC3C,IAAI,WAAW,UAAU,eAAe,OAAO,aAAa,GAAG;MAC/D,UAAU,gBAAgB,KAAK;CAEpC,MAAM,eAAe,IAAI,eAAe,IAAI;CAC5C,MAAM,SAAS,IAAI,iBAAiB;CAEpC,OACE,oBAAC,OAAD;EACE,WAAW,GACT,4CACA,yEACA,2BACA,SAAS,qBAAqB,gBAC9B,IAAI,UAAU,YAAY,kBAC1B,IAAI,UAAU,WAAW,eACzB,gBAAgB,gBAClB;EACA,OAAO,EAAE,OAAO,kBAAkB,IAAI,GAAG,eAAe;EACxD,eAAa,IAAI;EACjB,MAAK;EACL,SAAS,IAAI,eAAe,MAAM;GAChC,EAAE,gBAAgB;GAClB,IAAI,YAAa,KAAK,CAAC;EACzB,IAAI,KAAA;EACJ,eAAe,IAAI,qBAAqB,MAAM;GAC5C,EAAE,gBAAgB;GAClB,IAAI,kBAAmB,KAAK,CAAC;EAC/B,IAAI,KAAA;YAEJ,oBAAC,OAAD;GAAK,WAAW,GAAG,WAAW,SAAS,WAAW,UAAU;aAAI;EAAa,CAAA;CAC1E,CAAA;AAET;AAEA,SAAS,gBAAgB,OAAiC;CACxD,IAAI,SAAS,MAAM,OAAO,oBAAC,QAAD;EAAM,WAAU;YAA2B;CAAO,CAAA;CAC5E,IAAI,OAAO,UAAU,WACnB,OACE,oBAAC,QAAD;EAAM,WAAW,GACf,yEACA,QACI,6DACA,4CACN;YACG,QAAQ,QAAQ;CACb,CAAA;CAGV,IAAI,iBAAiB,MACnB,OAAO,oBAAC,QAAD;EAAM,WAAU;YAAsC,MAAM,mBAAmB;CAAQ,CAAA;CAEhG,OAAO,oBAAC,QAAD;EAAM,WAAU;YAAY,OAAO,KAAK;CAAQ,CAAA;AACzD;AAEA,SAAS,eACP,OACA,aACA,KACiB;CACjB,MAAM,EAAE,SAAS,YAAY,eAAe,OAAO,aAAa;EAC9D,YAAY,IAAI;EAChB,YAAY,IAAI;CAClB,CAAC;CACD,IAAI,WAAW,MAAM,OAAO,oBAAC,QAAD;EAAM,WAAU;YAA2B;CAAO,CAAA;CAC9E,OACE,oBAAC,QAAD;EAAM,WAAU;EAA0D,OAAO,WAAW,KAAA;YACzF;CACG,CAAA;AAEV;AAIA,SAAS,gBAAgB,OAAuB;CAC9C,IAAI,OAAO;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,QAAS,QAAQ,KAAK,OAAO,MAAM,WAAW,CAAC,IAAK;CAC3F,OAAO,KAAK,IAAI,IAAI;AACtB;AAEA,SAAS,YAAY,EACnB,SACA,QACA,gBAKC;CACD,OACE,qBAAC,OAAD;EAAK,WAAU;EAAO,OAAO,EAAE,OAAO;EAAG,MAAK;YAA9C,CACG,gBACC,oBAAC,OAAD;GAAK,WAAU;GAAyF,OAAO,EAAE,OAAO,GAAG;aACzH,oBAAC,gBAAD,EAAgB,WAAU,kBAAmB,CAAA;EAC1C,CAAA,GAEN,QAAQ,KAAK,QACZ,oBAAC,OAAD;GAEE,WAAU;GACV,OAAO,EAAE,OAAO,kBAAkB,IAAI,GAAG,eAAe;aAExD,oBAAC,gBAAD;IAAgB,WAAU;IAAmB,OAAO,EAAE,OAAO,GAAG,KAAM,gBAAgB,IAAI,EAAE,IAAI,GAAI,GAAG;GAAI,CAAA;EACxG,GALE,IAAI,EAKN,CACN,CACE;;AAET;AAIA,SAAS,kBAAkB,EACzB,SACA,eACA,UACA,WACA,SAOC;CACD,MAAM,OAAO,gBAAgB,cAAc,UAAU,cAAc;CACnE,OACE,oBAAC,UAAD;EACE,WAAW,GACT,kDACA,4DACA,WAAW,gBACP,qCACA,yDACN;EACA,UAAU,MAAM;GACd,EAAE,gBAAgB;GAClB,SAAS,CAAC;EACZ;EACA,cAAY;EACZ,OAAO,SAAS;EAChB,MAAK;EACL,gBAAc,gBAAgB,UAAU;YAExC,oBAAC,MAAD;GAAM,WAAU;GAAU,QAAQ,WAAW,gBAAgB,SAAS;EAAY,CAAA;CAC5E,CAAA;AAEZ;AAIA,MAAM,aAAa,CAAC;AAEpB,SAAS,uBAAuB,EAC9B,aACA,WACA,SACA,WAMC;CACD,MAAM,MAAM,OAAuB,IAAI;CAUvC,MAAM,iBAAiB,OAAO,WAAW;CACzC,eAAe,UAAU;CACzB,gBAAgB;EACd,MAAM,KAAK,IAAI;EACf,IAAI,CAAC,IAAI;EACT,MAAM,WAAW,IAAI,sBAClB,YAAY;GAAE,IAAI,QAAQ,EAAE,EAAE,gBAAgB,eAAe,QAAQ;EAAG,GACzE;GAAE,MAAM,SAAS,WAAW;GAAM,YAAY;EAAQ,CACxD;EACA,SAAS,QAAQ,EAAE;EACnB,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,OAAO,CAAC;CACZ,OACE,oBAAC,OAAD;EAAU;EAAK,WAAU;YACtB,aACC,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD,EAAK,WAAU,iFAAkF,CAAA,GAChG,QAAQ,WACN;;CAEJ,CAAA;AAET;AAIA,SAAS,cAAoB,EAC3B,KACA,YACA,YAKC;CACD,MAAM,EAAE,OAAO,eAAe,iBAAiB,kBAAkB,YAAY;CAC7E,MAAM,aAAa,iBAAiB,OAChC,KAAK,IAAI,GAAG,KAAK,KAAK,gBAAgB,MAAM,WAAW,QAAQ,CAAC,IAChE,KAAA;CAEJ,MAAM,WAAW,cACf,UAAU,OAAO;EAAE,GAAG;EAAG,YAAY;GAAE,GAAG,EAAE;GAAY;EAAU;CAAE,EAAE;CACxE,MAAM,eAAe,aACnB,UAAU,OAAO;EAAE,GAAG;EAAG,YAAY;GAAE,GAAG,EAAE;GAAY;GAAU,WAAW;EAAE;CAAE,EAAE;CAErF,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACG,mBAAmB,KAClB,oBAAC,QAAD;IAAM,WAAU;cAA+B,QAAQ,aAAa,gBAAgB;GAAQ,CAAA,GAE7F,iBAAiB,QAAQ,qBAAC,QAAD,EAAA,UAAA;IAAO;IAAgB;IAAK;IAAc;GAAW,EAAA,CAAA,CAC5E;MAEJ,eAAe,cAAc,cAAc,QAC1C,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,QAAD,EAAA,UAAO,QAAQ,YAAkB,CAAA,GACjC,oBAAC,UAAD;KACE,WAAW,GACT,6EACA,yFACA,uFACA,sHACF;KACA,OAAO,MAAM,WAAW;KACxB,WAAW,MAAM,YAAY,OAAO,EAAE,OAAO,KAAK,CAAC;eAElD;MAAC;MAAI;MAAI;MAAI;KAAG,CAAC,CAAC,KAAK,SAAS,oBAAC,UAAD;MAAmB,OAAO;gBAAO;KAAa,GAAjC,IAAiC,CAAC;IAC1E,CAAA,CACL;OACL,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,UAAD;MACE,WAAW,GACT,uDACA,8EACA,+BACF;MACA,eAAe,QAAQ,MAAM,WAAW,YAAY,CAAC;MACrD,UAAU,MAAM,WAAW,cAAc;MACzC,cAAW;gBAEX,oBAAC,SAAD;OAAS,WAAU;OAAyB,QAAO;MAAQ,CAAA;KACrD,CAAA;KACR,oBAAC,QAAD;MAAM,WAAU;gBACb,QAAQ,OAAO,MAAM,WAAW,YAAY,GAAG,UAAU;KACtD,CAAA;KACN,oBAAC,UAAD;MACE,WAAW,GACT,uDACA,8EACA,+BACF;MACA,eAAe,QAAQ,MAAM,WAAW,YAAY,CAAC;MACrD,UAAU,MAAM,WAAW,aAAa,aAAa;MACrD,cAAW;gBAEX,oBAAC,WAAD;OAAW,WAAU;OAAyB,QAAO;MAAQ,CAAA;KACvD,CAAA;IACL;KACF;IAEJ;;AAET;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,SAAe,OAA4B;CACzD,MAAM,EACJ,SAAS,YACT,MACA,UACA,eACA,YAAY,OACZ,eAAe,OACf,UAAU,OACV,gBAAgB,OAChB,YACA,OACA,UACA,iBAAiB,aACjB,gBAAgB,QAChB,YAAY,MACZ,WAAW,gBAAgB,IAC3B,oBAAoB,wBACpB,eAAe,IACf,WAAW,GACX,WACA,aAAa,MACb,WACA,SACA,cACA,YACA,cACA,QACA,aACA,iBAAiB,UACjB,eACA,SAAS,iBACT,WACA,YACA,kBACA,mBACA,cACA,gBACA,6BACE;CAEJ,MAAM,qBAAqB,kBAAkB;CAC7C,MAAM,iBAAiB,qBAAqB,KAAA,IAAY;CACxD,MAAM,qBAAqB,0BAA2B,kBAAkB;CAExE,MAAM,UAAU,cAAc,uBAAuB,eAAe,GAAG,CAAC,eAAe,CAAC;CAGxF,MAAM,eAAe,cAEjB,WAAW,KAAK,SAAS;EACvB,IAAI,IAAI;EACR,aAAa,QAAQ,mBAAmB,KAAK,GAAG;EAChD,QAAQ,OAAO,IAAI,WAAW,WAAW,IAAI,SAAS,IAAI;EAC1D,MAAM,IAAI,SAAS;EACnB,SAAS,qBAAqB,GAAG;EACjC,SAAS,qBAAqB,GAAG;EACjC,eAAe,IAAI,aAAa;EAChC,cAAc,IAAI,aAAa;EAC/B,gBAAgB,IAAI,cAAc;EAClC,iBAAiB;CACnB,EAAE,GACJ,CAAC,UAAU,CACb;CAGA,MAAM,kBAAkB,cAAc,kBAAkB,MAAM,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC;CACvF,MAAM,uBAAuB,cACrB,uBAAuB,MAAM,UAAU,WAAW,GACxD,CAAC,MAAM,UAAU,WAAW,CAC9B;CAEA,MAAM,wBAAwB,eACrB;EAAE,MAAM,CAAC,GAAG,MAAM,cAAc,IAAI;EAAG,OAAO,CAAC,GAAG,MAAM,cAAc,KAAK;CAAE,IACpF,CAAC,MAAM,aAAa,CACtB;CACA,MAAM,sBAAsB,cACpB,CAAC,GAAG,MAAM,WAAW,GAC3B,CAAC,MAAM,WAAW,CACpB;CAEA,MAAM,gBAAgB,OAAO,UAAU;CACvC,cAAc,UAAU;CAExB,MAAM,sBAAsB,aACzB,YAAmC;EAElC,MAAM,OAA2B,oBADpB,eAAe,SAAS,kBAAkB,MAAM,OAAO,CACZ,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,GAAG,EAAE,EAAE;EAIhF,UAAU,OAAO;GACf,GAAG;GACH,SAAS;GACT,YAAY;IAAE,GAAG,EAAE;IAAY,WAAW;GAAE;EAC9C,EAAE;EACF,eAAe,IAAI;CACrB,GACA;EAAC;EAAU;EAAc,MAAM;CAAO,CACxC;CAEA,MAAM,2BAA2B,aAC9B,YAAwC;EACvC,MAAM,OAAO,eAAe,SAAS,MAAM,YAAY;EAEvD,MAAM,UAAkC,CAAC;EACzC,KAAK,MAAM,CAAC,IAAI,MAAM,OAAO,QAAQ,IAAI,GAAG;GAC1C,MAAM,MAAM,cAAc,QAAQ,MAAM,MAAM,EAAE,OAAO,EAAE;GACzD,QAAQ,MAAM,MAAM,iBAAiB,KAAK,CAAC,IAAI;EACjD;EACA,UAAU,OAAO;GAAE,GAAG;GAAG,cAAc;EAAQ,EAAE;EAEjD,IAAI;QACG,MAAM,CAAC,IAAI,MAAM,OAAO,QAAQ,OAAO,GAC1C,IAAI,MAAM,aAAa,QAAQ,GAAG,eAAe,IAAI,CAAC;EAAA;CAG5D,GACA;EAAC;EAAU;EAAgB,MAAM;CAAY,CAC/C;CAEA,MAAM,yBAAyB,aAC5B,YAAsC;EACrC,MAAM,OAAO,eAAe,SAAS,MAAM,gBAAgB;EAC3D,UAAU,OAAO;GAAE,GAAG;GAAG,kBAAkB;EAAK,EAAE;EAClD,2BAA2B,IAAI;CACjC,GACA;EAAC;EAAU;EAA0B,MAAM;CAAgB,CAC7D;CAEA,MAAM,0BAA0B,aAC7B,YAAuC;EACtC,MAAM,OAAO,eAAe,SAAS,CAAC,GAAG,MAAM,WAAW,CAAC;EAC3D,UAAU,OAAO;GAAE,GAAG;GAAG,aAAa;EAAK,EAAE;CAC/C,GACA,CAAC,UAAU,MAAM,WAAW,CAC9B;CAEA,MAAM,4BAA4B,aAC/B,YAAyC;EAKxC,MAAM,OAAO,eAAe,SAAS;GAHnC,MAAM,CAAC,GAAG,MAAM,cAAc,IAAI;GAClC,OAAO,CAAC,GAAG,MAAM,cAAc,KAAK;EAEK,CAAC;EAC5C,UAAU,OAAO;GACf,GAAG;GACH,eAAe;IAAE,MAAM,KAAK,QAAQ,CAAC;IAAG,OAAO,KAAK,SAAS,CAAC;GAAE;EAClE,EAAE;CACJ,GACA,CAAC,UAAU,MAAM,aAAa,CAChC;CAGA,MAAM,QAAQ,cAAoB;EAChC,MAAM;EACN,SAAS;EACT,WAAW,QAAQ,SAAS,GAAG;EAC/B,iBAAiB,gBAAgB;EACjC,OAAO;GACL,SAAS;GACT,kBAAkB,MAAM;GACxB,cAAc,MAAM;GACpB,aAAa;GACb,eAAe;GACf,cAAc;EAChB;EACA,iBAAiB;EACjB,sBAAsB;EACtB,0BAA0B;EAC1B,qBAAqB;EACrB,uBAAuB;EACvB,kBAAkB;EAClB,oBAAoB,kBAAkB;EACtC,yBAAyB,kBAAkB;EAC3C,sBAAsB;EACtB,eAAe;EACf,kBAAkB;EAClB,iBAAiB;CACnB,CAAC;CAGD,MAAM,iBAAiB,cAAc;EACnC,MAAM,SAAS,IAAI,IAAI,WAAW,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;EACvD,OAAO,MACJ,sBAAsB,CAAC,CACvB,KAAK,MAAM,OAAO,IAAI,EAAE,EAAE,CAAC,CAAC,CAC5B,OAAO,OAAO;CACnB,GAAG;EAAC;EAAY;EAAO,MAAM;EAAa,MAAM;CAAgB,CAAC;CAGjE,MAAM,SAAS,cAAc,KAAK,IAAI,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC;CAMjE,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,CAAC;CACtD,sBAAsB;EACpB,MAAM,OAAO,QAAQ;EACrB,MAAM,WAAW,mBAAmB;EACpC,IAAI,CAAC,MAAM;EACX,MAAM,UAAU,YAAoC;GAClD,IAAI,WAAW;GACf,IAAI,WAAW,MACb,KAAK,MAAM,SAAS,SAClB,WAAW,KAAK,IAAI,UAAU,MAAM,YAAY,KAAK;GAGzD,IAAI,YAAY,GAAG;IACjB,MAAM,gBAAgB,UAAU,eAAe;IAC/C,MAAM,YAAY,KAAK;IACvB,WAAW,gBAAgB,IAAI,gBAAgB;GACjD;GACA,IAAI,WAAW,GAAG,kBAAkB,QAAQ;EAC9C;EACA,OAAO;EACP,MAAM,WAAW,IAAI,gBAAgB,YAAY,OAAO,OAAO,CAAC;EAChE,SAAS,QAAQ,IAAI;EACrB,IAAI,UAAU,SAAS,QAAQ,QAAQ;EACvC,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,CAAC;CAIL,MAAM,mBAAmB,MAAM,SAAS,CAAC,CAAC;CAC1C,MAAM,cAAc,cAAsC;EACxD,MAAM,QAAgC,CAAC;EACvC,IAAI,YAAY,kBAAkB,SAAS,KAAK;EAChD,MAAM,aAAa,iBAAiB,oBAAoB;EACxD,MAAM,cAAc,iBAAiB,eAAe;EACpD,KAAK,MAAM,OAAO,gBAAgB;GAEhC,MAAM,WADQ,MAAM,UAAU,IAAI,EACb,CAAC,EAAE,QAAQ,KAAK,IAAI,SAAS;GAClD,MAAM,WAAW,eAAe,IAAI,KAChC,iBAAiB,KAAK,WAAW,WAAW,IAC5C;GACJ,MAAM,IAAI,MAAM;GAChB,aAAa;EACf;EACA,qBAAqB,OAAO,gBAAgB,iBAAiB,SAAS;EACtE,OAAO;CACT,GAAG;EAAC;EAAgB;EAAO;EAAkB,MAAM;EAAc;EAAgB;CAAa,CAAC;CAE/F,MAAM,oBAAoB,cAAc;EACtC,IAAI,QAAQ,kBAAkB,SAAS,KAAK;EAC5C,KAAK,MAAM,OAAO,gBAAgB,SAAS,YAAY,IAAI,OAAO;EAClE,OAAO;CACT,GAAG;EAAC;EAAgB;EAAa;CAAa,CAAC;CAE/C,MAAM,UAAU,cAA6B;EAC3C,MAAM,OAAwC,EAAE,kBAAkB,GAAG,kBAAkB,IAAI;EAC3F,KAAK,MAAM,OAAO,gBAChB,KAAK,SAAS,IAAI,GAAG,UAAU,YAAY,IAAI;EAEjD,OAAO;CACT,GAAG;EAAC;EAAgB;EAAa;CAAiB,CAAC;CAGnD,MAAM,gBAAgB,aACnB,SAAiC;EAChC,UAAU,OAAO;GAAE,GAAG;GAAG,WAAW;EAAK,EAAE;EAC3C,IAAI,mBAAmB;GACrB,MAAM,QAAQ,KAAK;GAEnB,kBAAkB,OADG,KAAK,QAAQ,MAAM,MAAM,IAAI,SAAS,CAAC,CAAC,CACzB,CAAC;EACvC;CACF,GACA;EAAC;EAAU;EAAmB;EAAM;CAAQ,CAC9C;CAEA,MAAM,iBAAiB,aACpB,KAAW,OAAc,UAA4B;EACpD,IAAI,kBAAkB,QAQpB,cAPa,cAAc;GACzB,SAAS,MAAM;GACf;GACA,MAAM;GACN,WAAW;IAAE,OAAO,MAAM;IAAU,MAAM,MAAM,WAAW,MAAM;GAAQ;GACzE,WAAW;EACb,CACiB,CAAC;EAEpB,aAAa,KAAK,OAAO,KAAK;CAChC,GACA;EAAC;EAAe,MAAM;EAAW;EAAQ;EAAe;CAAU,CACpE;CAEA,MAAM,kBAAkB,kBAAkB;EAExC,cADuB,OAAO,SAAS,KAAK,OAAO,OAAO,OAAO,MAAM,UAAU,YAAY,IAAI,EAAE,CAAC,IAG9F;GAAE,6BAAa,IAAI,IAAI;GAAG,UAAU;EAAK,IACzC;GAAE,aAAa,IAAI,IAAI,MAAM;GAAG,UAAU;EAAK,CACrD;CACF,GAAG;EAAC;EAAQ,MAAM,UAAU;EAAa;CAAa,CAAC;CAGvD,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,KAAK;CAC9D,MAAM,kBAAkB,kBAAkB;EACxC,oBAAoB,IAAI;CAC1B,GAAG,CAAC,CAAC;CAGL,MAAM,qBAAqB,OAAuB,IAAI;CACtD,MAAM,kBAAkB,OAAuB,IAAI;CACnD,MAAM,kBAAkB,OAAuB,IAAI;CACnD,MAAM,cAAc,OAAuB,IAAI;CAC/C,MAAM,UAAU,OAAuB,IAAI;CAC3C,MAAM,mBAAmB,aAAa,OAAgB,GAAG,sBAAsB,CAAC,CAAC,QAAQ,CAAC,CAAC;CAE3F,MAAM,iBAAiB,eAAe;EACpC,OAAO,KAAK;EACZ,wBAAwB,mBAAmB;EAC3C,oBAAoB;EACpB;EACA,aAAa,UAAU;GACrB,MAAM,MAAM,KAAK;GACjB,OAAO,OAAO,OAAO,OAAO,SAAS,GAAG,CAAC,IAAI;EAC/C;EACA,GAAI,qBAAqB,EAAE,gBAAgB,iBAAiB,IAAI,CAAC;CACnE,CAAC;CAGD,sBAAsB;EACpB,MAAM,SAAS,QAAQ;EACvB,MAAM,WAAW,gBAAgB;EACjC,MAAM,SAAS,mBAAmB;EAClC,MAAM,SAAS,YAAY;EAC3B,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,UAAU,CAAC,QAAQ;EAEhD,MAAM,mBAAmB;GACvB,MAAM,aAAa,SAAS,sBAAsB;GAClD,MAAM,WAAW,OAAO,sBAAsB;GAC9C,MAAM,UAAU,KAAK,IAAI,GAAG,WAAW,SAAS,SAAS,GAAG;GAC5D,OAAO,MAAM,YAAY,8BAA8B,GAAG,QAAQ,GAAG;EACvE;EACA,WAAW;EACX,OAAO,iBAAiB,UAAU,UAAU;EAC5C,OAAO,iBAAiB,UAAU,YAAY,IAAI;EAClD,OAAO,iBAAiB,UAAU,UAAU;EAC5C,MAAM,WAAW,IAAI,eAAe,UAAU;EAC9C,SAAS,QAAQ,MAAM;EACvB,SAAS,QAAQ,QAAQ;EACzB,SAAS,QAAQ,MAAM;EACvB,aAAa;GACX,OAAO,oBAAoB,UAAU,UAAU;GAC/C,OAAO,oBAAoB,UAAU,YAAY,IAAI;GACrD,OAAO,oBAAoB,UAAU,UAAU;GAC/C,SAAS,WAAW;EACtB;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,mBAAmB,kBAAkB;EACzC,MAAM,OAAO,mBAAmB;EAChC,MAAM,SAAS,gBAAgB;EAC/B,IAAI,QAAQ,QAAQ,OAAO,aAAa,KAAK;CAC/C,GAAG,CAAC,CAAC;CAGL,MAAM,aAA2C,eACxC;EACL;EACA;EACA,SAAS;EACT;EACA;EACA,kBAAkB,MAAM,UAAU,YAAY;EAC9C;EACA,WAAW;CACb,IACA;EAAC;EAAO;EAAU;EAAY;EAAgB;EAAe;EAAS;CAAe,CACvF;CACA,MAAM,YAAyC,eACtC;EACL;EACA;EACA,iBAAiB,KAAK;EACtB,kBAAkB,MAAM,UAAU,YAAY;EAC9C;EACA;CACF,IACA;EAAC;EAAO;EAAe,KAAK;EAAQ;EAAgB;CAAO,CAC7D;CAEA,MAAM,cAAc,OAAO,SAAS,KAAK,OAAO,OAAO,OAAO,MAAM,UAAU,YAAY,IAAI,EAAE,CAAC;CACjG,MAAM,eAAe,CAAC,eAAe,OAAO,MAAM,OAAO,MAAM,UAAU,YAAY,IAAI,EAAE,CAAC;CAC5F,MAAM,wBACJ,mBAAmB,eAAe,cAAc,aAAa,QACzD,qBACA,KAAA;CAGN,MAAM,UAAmC,cAErC,MACG,gBAAgB,CAAC,CAAC,EAAE,EAAE,QACtB,QAAQ,MAAM,eAAe,MAAM,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,GACzE,CAAC,OAAO,cAAc,CACxB;CACA,MAAM,gBAAgB,cAAc;EAClC,MAAM,oBAAI,IAAI,IAAmC;EACjD,KAAK,MAAM,KAAK,SAAS,EAAE,IAAI,EAAE,OAAO,IAAI,CAAC;EAC7C,OAAO;CACT,GAAG,CAAC,OAAO,CAAC;CAEZ,MAAM,YAAY,cAAc,aAAa;CAE7C,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,sBAAD;EACE,MAAM;EACN,cAAc;EACR;EACN,SAAS;EACO;EACD;CAChB,CAAA,GACD,qBAAC,OAAD;EACE,KAAK;EACL,WAAW,GACT,kGACA,aAAa,mBAAmB,kBAChC,aAAa,mBACb,SACF;EACA,OAAO,aAAa,OAAO;GAAE,GAAG;GAAS;EAAU,IAAI;EACvD,MAAK;EACL,iBAAe,iBAAiB,KAAK;EACrC,iBAAe,eAAe;YAXhC;GAaE,qBAAC,OAAD;IACE,KAAK;IACL,WAAU;IACV,OAAO,EAAE,KAAK,cAAc,aAAa,OAAO,IAAI,oCAAoC;cAH1F,CAKG,YAAY,SACX,oBAAC,OAAD;KAAK,WAAU;eACZ,UACG,QAAQ,UAAU,IAElB,oBAAC,iBAAD;MACE,KAAK;MACL,OAAO,OAAO,iBAAiB,aAAa,aAAa,UAAU,IAAI;KACxE,CAAA;IAEF,CAAA,GAGP,qBAAC,OAAD;KAAK,WAAU;eAAf,CACG,gBACC,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,OAAD,EAAK,WAAU,yDAA0D,CAAA;KACtE,CAAA,GAEP,oBAAC,OAAD;MACE,KAAK;MACL,WAAU;gBAEV,qBAAC,OAAD;OACE,WAAU;OACV,OAAO;QAAE,QAAQ;QAAc,UAAU;OAAkB;OAC3D,MAAK;iBAHP,CAKG,kBAAkB,UACjB,oBAAC,OAAD;QACE,WAAU;QACV,OAAO,EAAE,OAAO,GAAG;kBAElB,kBAAkB,cACjB,oBAAC,mBAAD;SACE,SAAS;SACT,eAAe;SACf,UAAU;SACV,WAAU;SACV,OAAM;QACP,CAAA;OAEA,CAAA,GAEN,eAAe,KAAK,QAAQ;QAC3B,MAAM,SAAS,cAAc,IAAI,IAAI,EAAE;QACvC,IAAI,CAAC,QAAQ,OAAO;QACpB,OAAO,oBAAC,YAAD;SAAiC;SAAa;SAAgB;QAAY,GAAzD,IAAI,EAAqD;OACnF,CAAC,CACE;;KACF,CAAA,CACF;MACF;;GAEL,oBAAC,OAAD;IACE,KAAK;IACL,WAAW,GACX,4DACA,YAAY,mBAAmB,aAC/B,6DACA,+CACA,+FACA,yDACF;IACE,UAAU;cAEV,qBAAC,OAAD;KACE,KAAK;KACL,4BAAyB;KACzB,WAAU;KACV,OAAO;MACL,UAAU;MACV,UAAU;KACZ;eAPF;MASG,aACC,oBAAC,OAAD;OAAK,OAAO,EAAE,UAAU,kBAAkB;iBACvC,gBAAgB,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,MACjD,oBAAC,aAAD;QAEE,SAAS;QACT,QAAQ;QACR,cAAc,kBAAkB;OACjC,GAJM,CAIN,CACF;MACE,CAAA;MAGN,CAAC,aAAa,KAAK,WAAW,KAC7B,oBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,UAAU,kBAAkB;iBAEpC,cAAc,QAAQ;MACpB,CAAA;MAGN,CAAC,aAAa,KAAK,SAAS,KAC3B,oBAAC,OAAD;OACE,OAAO;QACL,QAAQ,eAAe,aAAa;QACpC,OAAO;QACP,UAAU;QACV,UAAU;OACZ;iBAEC,eAAe,gBAAgB,CAAC,CAAC,KAAK,eAA4B;QACjE,MAAM,MAAM,KAAK,WAAW,UAAU,SACtC,mCAAmC,WAAW,MAAM,6BAA6B,KAAK,OAAO,EAC/F;QACE,MAAM,QAAQ,SAAS,GAAG;QAC1B,MAAM,aAAa,MAAM,UAAU,YAAY,IAAI,KAAK;QACxD,MAAM,WAAW,WAAW,QAAQ,MAAM;QAC1C,OACE,qBAAC,OAAD;SAEE,KAAK,qBAAqB,eAAe,iBAAiB,KAAA;SAC1D,cAAY,WAAW;SACvB,WAAW,GACX,+BACA,yDACA,iCACA,aACI,qGACA,WACE,8GACA,gEACL,kBAAkB,UAAU,eAAe,gBAC9C;SACE,OAAO;UACL,GAAI,qBACA,EAAE,WAAW,mBAAmB,IAChC,EAAE,QAAQ,eAAe;UAC7B,WAAW,cAAc,WAAW,MAAM;SAC5C;SACA,UAAU,MAAM;UAAE,IAAI,CAAC,qBAAqB,CAAC,GAAG,eAAe,KAAK,OAAO,CAAC;SAAG;SAC/E,gBAAgB,MAAM;UAAE,IAAI,CAAC,qBAAqB,CAAC,GAAG,mBAAmB,KAAK,OAAO,CAAC;SAAG;SACzF,MAAK;SACL,iBAAe,WAAW,QAAQ;SAClC,iBAAe;SACf,eAAa;SACb,cAAY,aAAa,aAAa,KAAA;mBA3BxC,CA6BG,kBAAkB,UACjB,oBAAC,OAAD;UACE,WAAU;UACV,OAAO,EAAE,OAAO,GAAG;oBAEnB,oBAAC,mBAAD;WACE,SAAS;WACT,WAAW,UAAU,eAAe,KAAK,OAAO,KAAK;WACrD,WAAW,cAAc;UAC1B,CAAA;SACE,CAAA,GAEN,eAAe,KAAK,QACnB,oBAAC,UAAD;UAEO;UACA;UACE;UACP,UAAU,WAAW;UACT;UACZ,aAAa,MAAM;SACpB,GAPM,IAAI,EAOV,CACF,CACE;WAnDE,KAmDF;OAET,CAAC;MACE,CAAA;MAGN,mBAAmB,cAAc,WAAW,CAAC,aAC5C,oBAAC,wBAAD;OACE,aAAa,cAAc;OAC3B,WAAW;OACX,SAAS;OACA;MACV,CAAA;KAEA;;GACF,CAAA;GAEJ,WAAW,SACV,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,SAAS,OAAO,SAAS,IAAI,oBAAC,eAAD;KAAe,KAAK;KAAW,YAAY;KAA0B;IAAW,CAAA,GAC7G,gBAAgB,OAAO,gBAAgB,aAAa,YAAY,SAAS,IAAI,YAC3E;;EAEJ;GACL,EAAA,CAAA;AAEN"}
1
+ {"version":3,"file":"data-grid.js","names":[],"sources":["../../../../src/components/data-grid/data-grid.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n ArrowDown,\n ArrowUp,\n CaretDown,\n CaretUp,\n CheckSquare,\n MinusSquare,\n Square,\n} from \"@phosphor-icons/react\";\nimport { throwErr } from \"@hexclave/shared/dist/utils/errors\";\nimport { cn } from \"@hexclave/ui\";\nimport {\n type ColumnDef,\n type ColumnOrderState,\n type ColumnPinningState,\n type ColumnSizingState,\n type RowSelectionState,\n type SortingState,\n type VisibilityState,\n type Header,\n type Updater,\n getCoreRowModel,\n useReactTable,\n} from \"@tanstack/react-table\";\nimport { useVirtualizer, type VirtualItem } from \"@tanstack/react-virtual\";\nimport React, {\n type CSSProperties,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { DesignSkeleton } from \"../skeleton\";\nimport { DEFAULT_COL_WIDTH, clampColumnWidth, getEffectiveMaxWidth, getEffectiveMinWidth } from \"./data-grid-sizing\";\nimport { DataGridExportDialog } from \"./data-grid-export-dialog\";\nimport { DataGridToolbar } from \"./data-grid-toolbar\";\nimport { formatGridDate, resolveColumnValue } from \"./state\";\nimport { resolveDataGridStrings } from \"./strings\";\nimport type {\n DataGridCellContext,\n DataGridColumnDef,\n DataGridDateDisplay,\n DataGridFooterContext,\n DataGridHeaderContext,\n DataGridPaginationMode,\n DataGridProps,\n DataGridSelectionModel,\n DataGridSortItem,\n DataGridSortModel,\n DataGridState,\n DataGridStrings,\n DataGridToolbarContext,\n RowId,\n} from \"./types\";\n\n// Viewport-relative fallback height for infinite-scroll grids that the caller left unbounded\n// (no `fillHeight`, no `maxHeight`). Leaves ~16rem of room for the top bar, page header, and grid\n// toolbar. See the `effectiveMaxHeight` comment in DataGrid for why an infinite grid must be bounded.\nconst DEFAULT_INFINITE_MAX_HEIGHT = \"calc(100dvh - 16rem)\";\n\n// ─── Row click target ────────────────────────────────────────────────\n\nfunction getEventTargetElement(target: EventTarget | null): Element | null {\n if (target instanceof Element) return target;\n if (target instanceof Node) return target.parentElement;\n return null;\n}\n\nexport function isDataGridInteractiveRowClickTarget(target: EventTarget | null): boolean {\n const el = getEventTargetElement(target);\n return el?.closest([\n \"a\",\n \"button\",\n \"input\",\n \"select\",\n \"textarea\",\n \"[role=\\\"button\\\"]\",\n \"[role=\\\"menuitem\\\"]\",\n \"[contenteditable]:not([contenteditable=\\\"false\\\"])\",\n \"[data-no-row-click]\",\n ].join(\",\")) != null;\n}\n\nfunction shouldIgnoreRowClick(event: React.MouseEvent): boolean {\n return event.defaultPrevented || isDataGridInteractiveRowClickTarget(event.target);\n}\n\n// ─── State translators (DataGridState ⇄ TanStack) ────────────────────\n\nfunction toTanstackSorting(sorting: DataGridSortModel): SortingState {\n return sorting.map((s) => ({ id: s.columnId, desc: s.direction === \"desc\" }));\n}\n\nfunction fromTanstackSorting(sorting: SortingState): DataGridSortModel {\n return sorting.map((s) => ({ columnId: s.id, direction: s.desc ? \"desc\" : \"asc\" }));\n}\n\nfunction toTanstackRowSelection(ids: ReadonlySet<RowId>): RowSelectionState {\n const out: RowSelectionState = {};\n for (const id of ids) out[id] = true;\n return out;\n}\n\nfunction resolveUpdater<T>(updater: Updater<T>, current: T): T {\n return typeof updater === \"function\" ? (updater as (old: T) => T)(current) : updater;\n}\n\n// ─── Flex column width distribution ──────────────────────────────────\n\nfunction distributeFlexWidths<TRow>(\n sizes: Record<string, number>,\n visibleColumns: readonly DataGridColumnDef<TRow>[],\n available: number,\n): void {\n const flexCols = visibleColumns.filter((c) => c.flex != null && c.flex > 0);\n if (flexCols.length === 0 || available <= 0) return;\n const totalFlex = flexCols.reduce((acc, c) => acc + (c.flex ?? 0), 0);\n let remaining = available;\n flexCols.forEach((col, i) => {\n const isLast = i === flexCols.length - 1;\n const share = isLast\n ? remaining\n : Math.floor(available * ((col.flex ?? 0) / totalFlex));\n const max = col.maxWidth ?? Infinity;\n const add = Math.max(0, Math.min(share, max - sizes[col.id]));\n sizes[col.id] += add;\n remaining -= add;\n });\n}\n\n// ─── Selection logic (with shift-range anchor) ───────────────────────\n\ntype SelectionInput = {\n current: DataGridSelectionModel;\n rowId: RowId;\n mode: \"single\" | \"multiple\";\n modifiers: { shift: boolean; ctrl: boolean };\n allRowIds: readonly RowId[];\n};\n\nfunction selectSingle(current: DataGridSelectionModel, rowId: RowId): DataGridSelectionModel {\n const isSelected = current.selectedIds.has(rowId);\n return {\n selectedIds: isSelected ? new Set() : new Set([rowId]),\n anchorId: isSelected ? null : rowId,\n };\n}\n\nfunction selectRange(\n current: DataGridSelectionModel,\n rowId: RowId,\n allRowIds: readonly RowId[],\n additive: boolean,\n): DataGridSelectionModel | null {\n if (current.anchorId == null) return null;\n const anchorIdx = allRowIds.indexOf(current.anchorId);\n const currentIdx = allRowIds.indexOf(rowId);\n if (anchorIdx < 0 || currentIdx < 0) return null;\n const start = Math.min(anchorIdx, currentIdx);\n const end = Math.max(anchorIdx, currentIdx);\n const next = additive ? new Set(current.selectedIds) : new Set<RowId>();\n for (let i = start; i <= end; i++) next.add(allRowIds[i]!);\n return { selectedIds: next, anchorId: current.anchorId };\n}\n\nfunction selectToggle(current: DataGridSelectionModel, rowId: RowId): DataGridSelectionModel {\n const next = new Set(current.selectedIds);\n if (next.has(rowId)) next.delete(rowId);\n else next.add(rowId);\n return { selectedIds: next, anchorId: rowId };\n}\n\nfunction nextSelection(input: SelectionInput): DataGridSelectionModel {\n const { current, rowId, mode, modifiers, allRowIds } = input;\n if (mode === \"single\") return selectSingle(current, rowId);\n if (modifiers.shift) {\n const range = selectRange(current, rowId, allRowIds, modifiers.ctrl);\n if (range != null) return range;\n }\n if (modifiers.ctrl) return selectToggle(current, rowId);\n return { selectedIds: new Set([rowId]), anchorId: rowId };\n}\n\n// ─── Header cell ─────────────────────────────────────────────────────\n\nfunction HeaderCell<TRow>({\n header,\n col,\n resizable,\n}: {\n header: Header<TRow, unknown>;\n col: DataGridColumnDef<TRow>;\n resizable: boolean;\n}) {\n const sorted = header.column.getIsSorted(); // false | \"asc\" | \"desc\"\n const sortIndex = header.column.getSortIndex();\n const totalSorts = header.column.getCanMultiSort()\n ? header.getContext().table.getState().sorting.length\n : 0;\n const ctx: DataGridHeaderContext<TRow> = {\n columnId: col.id,\n columnDef: col,\n isSorted: sorted === false ? false : sorted,\n sortIndex: totalSorts > 1 && sortIndex >= 0 ? sortIndex + 1 : null,\n };\n const label = typeof col.header === \"function\" ? col.header(ctx) : col.header;\n const sortable = header.column.getCanSort();\n const canResize = resizable && header.column.getCanResize();\n const isResizing = header.column.getIsResizing();\n\n return (\n <div\n className={cn(\n \"group/header relative flex items-center gap-1.5 px-3 select-none bg-transparent overflow-hidden\",\n \"border-r border-black/[0.04] dark:border-white/[0.04] last:border-r-0\",\n sortable && \"cursor-pointer\",\n )}\n style={{ width: `calc(var(--col-${col.id}-size) * 1px)` }}\n data-col-id={col.id}\n onClick={sortable ? header.column.getToggleSortingHandler() : undefined}\n role=\"columnheader\"\n aria-sort={sorted === \"asc\" ? \"ascending\" : sorted === \"desc\" ? \"descending\" : \"none\"}\n >\n <span\n className={cn(\n \"flex-1 min-w-0 truncate text-xs font-semibold uppercase tracking-wider text-muted-foreground\",\n col.align === \"center\" && \"text-center\",\n col.align === \"right\" && \"text-right\",\n )}\n >\n {label}\n </span>\n\n {sorted && (\n <span className=\"flex items-center gap-0.5 text-foreground/60\">\n {sorted === \"asc\"\n ? <ArrowUp className=\"h-3 w-3\" weight=\"bold\" />\n : <ArrowDown className=\"h-3 w-3\" weight=\"bold\" />}\n {ctx.sortIndex != null && (\n <span className=\"text-[10px] font-medium tabular-nums\">{ctx.sortIndex}</span>\n )}\n </span>\n )}\n\n {!sorted && sortable && (\n <span className=\"hidden group-hover/header:flex items-center text-foreground/20\">\n <CaretUp className=\"h-2.5 w-2.5 -mb-[1px]\" weight=\"bold\" />\n <CaretDown className=\"h-2.5 w-2.5 -mt-[1px]\" weight=\"bold\" />\n </span>\n )}\n\n {canResize && (\n <div\n onMouseDown={header.getResizeHandler()}\n onTouchStart={header.getResizeHandler()}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n }}\n className={cn(\n \"absolute right-0 top-0 bottom-0 z-10 w-[5px] cursor-col-resize touch-none\",\n \"group-hover/header:bg-foreground/[0.06] hover:!bg-blue-500/30\",\n \"transition-colors duration-100\",\n isResizing && \"bg-blue-500/40\",\n )}\n />\n )}\n </div>\n );\n}\n\n// ─── Data cell ───────────────────────────────────────────────────────\n\nfunction DataCell<TRow>({\n col,\n row,\n rowId,\n rowIndex,\n isSelected,\n dateDisplay,\n}: {\n col: DataGridColumnDef<TRow>;\n row: TRow;\n rowId: RowId;\n rowIndex: number;\n isSelected: boolean;\n dateDisplay: DataGridDateDisplay;\n}) {\n const value = resolveColumnValue(col, row);\n const ctx: DataGridCellContext<TRow> = { row, rowId, rowIndex, value, columnId: col.id, isSelected, dateDisplay };\n\n const isDateCol = col.type === \"date\" || col.type === \"dateTime\";\n let content: React.ReactNode;\n if (col.renderCell) content = col.renderCell(ctx);\n else if (isDateCol) content = renderDateCell(value, dateDisplay, col);\n else content = formatCellValue(value);\n\n const hasCellClick = col.onCellClick || col.onCellDoubleClick;\n const isWrap = col.cellOverflow === \"wrap\";\n\n return (\n <div\n className={cn(\n \"flex px-3 bg-transparent overflow-hidden\",\n \"border-r border-black/[0.04] dark:border-white/[0.04] last:border-r-0\",\n \"text-sm text-foreground\",\n isWrap ? \"items-start py-2\" : \"items-center\",\n col.align === \"center\" && \"justify-center\",\n col.align === \"right\" && \"justify-end\",\n hasCellClick && \"cursor-pointer\",\n )}\n style={{ width: `calc(var(--col-${col.id}-size) * 1px)` }}\n data-col-id={col.id}\n role=\"gridcell\"\n onClick={col.onCellClick ? (e) => {\n e.stopPropagation();\n col.onCellClick!(ctx, e);\n } : undefined}\n onDoubleClick={col.onCellDoubleClick ? (e) => {\n e.stopPropagation();\n col.onCellDoubleClick!(ctx, e);\n } : undefined}\n >\n <div className={cn(\"min-w-0\", isWrap ? \"flex-1\" : \"truncate\")}>{content}</div>\n </div>\n );\n}\n\nfunction formatCellValue(value: unknown): React.ReactNode {\n if (value == null) return <span className=\"text-muted-foreground/40\">-</span>;\n if (typeof value === \"boolean\") {\n return (\n <span className={cn(\n \"inline-flex items-center px-1.5 py-0.5 rounded-md text-xs font-medium\",\n value\n ? \"bg-emerald-500/10 text-emerald-600 dark:text-emerald-400\"\n : \"bg-foreground/[0.04] text-muted-foreground\",\n )}>\n {value ? \"Yes\" : \"No\"}\n </span>\n );\n }\n if (value instanceof Date) {\n return <span className=\"tabular-nums text-muted-foreground\">{value.toLocaleDateString()}</span>;\n }\n return <span className=\"truncate\">{String(value)}</span>;\n}\n\nfunction renderDateCell<TRow>(\n value: unknown,\n dateDisplay: DataGridDateDisplay,\n col: DataGridColumnDef<TRow>,\n): React.ReactNode {\n const { display, tooltip } = formatGridDate(value, dateDisplay, {\n parseValue: col.parseValue,\n dateFormat: col.dateFormat,\n });\n if (display == null) return <span className=\"text-muted-foreground/40\">-</span>;\n return (\n <span className=\"tabular-nums text-muted-foreground truncate cursor-help\" title={tooltip ?? undefined}>\n {display}\n </span>\n );\n}\n\n// ─── Skeleton row ────────────────────────────────────────────────────\n\nfunction hashStringToInt(value: string): number {\n let hash = 0;\n for (let i = 0; i < value.length; i++) hash = ((hash << 5) - hash + value.charCodeAt(i)) | 0;\n return Math.abs(hash);\n}\n\nfunction SkeletonRow({\n columns,\n height,\n showCheckbox,\n}: {\n columns: readonly DataGridColumnDef<any>[];\n height: number;\n showCheckbox?: boolean;\n}) {\n return (\n <div className=\"flex\" style={{ height }} role=\"row\">\n {showCheckbox && (\n <div className=\"flex items-center justify-center border-r border-black/[0.04] dark:border-white/[0.04]\" style={{ width: 44 }}>\n <DesignSkeleton className=\"h-4 w-4 rounded\" />\n </div>\n )}\n {columns.map((col) => (\n <div\n key={col.id}\n className=\"flex items-center px-3 border-r border-black/[0.04] dark:border-white/[0.04] last:border-r-0\"\n style={{ width: `calc(var(--col-${col.id}-size) * 1px)` }}\n >\n <DesignSkeleton className=\"h-3.5 rounded-md\" style={{ width: `${40 + (hashStringToInt(col.id) % 40)}%` }} />\n </div>\n ))}\n </div>\n );\n}\n\n// ─── Selection checkbox ──────────────────────────────────────────────\n\nfunction SelectionCheckbox({\n checked,\n indeterminate,\n onChange,\n ariaLabel,\n title,\n}: {\n checked: boolean;\n indeterminate?: boolean;\n onChange: (event: React.MouseEvent<HTMLButtonElement>) => void;\n ariaLabel: string;\n title?: string;\n}) {\n const Icon = indeterminate ? MinusSquare : checked ? CheckSquare : Square;\n return (\n <button\n className={cn(\n \"flex items-center justify-center w-full h-full\",\n \"hover:bg-foreground/[0.04] transition-colors duration-75\",\n checked || indeterminate\n ? \"text-blue-600 dark:text-blue-400\"\n : \"text-muted-foreground/40 hover:text-muted-foreground/60\",\n )}\n onClick={(e) => {\n e.stopPropagation();\n onChange(e);\n }}\n aria-label={ariaLabel}\n title={title ?? ariaLabel}\n role=\"checkbox\"\n aria-checked={indeterminate ? \"mixed\" : checked}\n >\n <Icon className=\"h-4 w-4\" weight={checked || indeterminate ? \"fill\" : \"regular\"} />\n </button>\n );\n}\n\n// ─── Infinite scroll sentinel ────────────────────────────────────────\n\nconst NOOP = () => {};\n\nfunction InfiniteScrollSentinel({\n onIntersect,\n isLoading,\n rootRef,\n strings,\n}: {\n onIntersect: () => void;\n isLoading: boolean;\n rootRef?: React.RefObject<Element | null>;\n strings: DataGridStrings;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n // Read `onIntersect` through a ref so the observer never has to be\n // re-created when the callback identity changes. `onLoadMore` (and thus\n // `onIntersect`) changes on every `isLoadingMore`/`hasMore` toggle; if the\n // observer were re-created each time, a freshly-created observer re-reports\n // the sentinel's *current* intersection state, so a sentinel that stays in\n // view keeps firing `onIntersect` after every page. That auto-loads the\n // entire dataset back-to-back (defeating \"load on scroll\") and OOM-crashes\n // the tab on long transaction/customer histories. A single stable observer\n // only fires on genuine intersection *changes* (real user scrolls).\n const onIntersectRef = useRef(onIntersect);\n onIntersectRef.current = onIntersect;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const observer = new IntersectionObserver(\n (entries) => { if (entries[0]?.isIntersecting) onIntersectRef.current(); },\n { root: rootRef?.current ?? null, rootMargin: \"200px\" },\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [rootRef]);\n return (\n <div ref={ref} className=\"flex items-center justify-center py-4\">\n {isLoading && (\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <div className=\"h-3 w-3 rounded-full border-2 border-current border-t-transparent animate-spin\" />\n {strings.loadingMore}\n </div>\n )}\n </div>\n );\n}\n\n// ─── Footer ──────────────────────────────────────────────────────────\n\nfunction DefaultFooter<TRow>({\n ctx,\n pagination,\n onChange,\n}: {\n ctx: DataGridFooterContext<TRow>;\n pagination: DataGridPaginationMode;\n onChange: React.Dispatch<React.SetStateAction<DataGridState>>;\n}) {\n const { state, totalRowCount, visibleRowCount, selectedRowCount, strings } = ctx;\n const totalPages = totalRowCount != null\n ? Math.max(1, Math.ceil(totalRowCount / state.pagination.pageSize))\n : undefined;\n\n const setPage = (pageIndex: number) =>\n onChange((s) => ({ ...s, pagination: { ...s.pagination, pageIndex } }));\n const setPageSize = (pageSize: number) =>\n onChange((s) => ({ ...s, pagination: { ...s.pagination, pageSize, pageIndex: 0 } }));\n\n return (\n <div className=\"flex items-center justify-between px-4 py-2.5 border-t border-foreground/[0.06] text-xs text-muted-foreground\">\n <div className=\"flex items-center gap-3\">\n {selectedRowCount > 0 && (\n <span className=\"font-medium text-foreground\">{strings.rowsSelected(selectedRowCount)}</span>\n )}\n {totalRowCount != null && <span>{visibleRowCount} of {totalRowCount} rows</span>}\n </div>\n\n {pagination !== \"infinite\" && totalPages != null && (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex items-center gap-1.5\">\n <span>{strings.rowsPerPage}</span>\n <select\n className={cn(\n \"h-7 rounded-lg border border-black/[0.08] dark:border-white/[0.06] px-1.5\",\n \"bg-white dark:bg-background shadow-sm ring-1 ring-black/[0.08] dark:ring-white/[0.06]\",\n \"text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-foreground/[0.1]\",\n \"cursor-pointer transition-all duration-150 hover:transition-none hover:ring-black/[0.12] dark:hover:ring-white/[0.1]\",\n )}\n value={state.pagination.pageSize}\n onChange={(e) => setPageSize(Number(e.target.value))}\n >\n {[10, 25, 50, 100].map((size) => <option key={size} value={size}>{size}</option>)}\n </select>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n className={cn(\n \"h-7 w-7 flex items-center justify-center rounded-lg\",\n \"hover:bg-foreground/[0.04] disabled:opacity-30 disabled:cursor-not-allowed\",\n \"transition-colors duration-75\",\n )}\n onClick={() => setPage(state.pagination.pageIndex - 1)}\n disabled={state.pagination.pageIndex === 0}\n aria-label=\"Previous page\"\n >\n <CaretUp className=\"h-3.5 w-3.5 -rotate-90\" weight=\"bold\" />\n </button>\n <span className=\"px-2 tabular-nums font-medium\">\n {strings.pageOf(state.pagination.pageIndex + 1, totalPages)}\n </span>\n <button\n className={cn(\n \"h-7 w-7 flex items-center justify-center rounded-lg\",\n \"hover:bg-foreground/[0.04] disabled:opacity-30 disabled:cursor-not-allowed\",\n \"transition-colors duration-75\",\n )}\n onClick={() => setPage(state.pagination.pageIndex + 1)}\n disabled={state.pagination.pageIndex >= totalPages - 1}\n aria-label=\"Next page\"\n >\n <CaretDown className=\"h-3.5 w-3.5 -rotate-90\" weight=\"bold\" />\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// ─── Main DataGrid ───────────────────────────────────────────────────\n\n/**\n * Interactive table built on TanStack Table v8. Sorting, column sizing,\n * visibility, ordering, and pinning are owned by the table instance; we\n * layer virtualization, sticky toolbar/header/footer, infinite scroll,\n * quick search, CSV export, and date-format toggling on top.\n *\n * The grid is display-only — it does not fetch or page data itself. Pair\n * with `useDataSource` for client- or server-side data and pass the\n * already-processed slice through `rows`.\n *\n * ```tsx\n * const columns = useMemo(() => [...], []);\n * const [gridState, setGridState] = useState(() => createDefaultDataGridState(columns));\n * const gridData = useDataSource({\n * data: users, columns, getRowId: (r) => r.id,\n * sorting: gridState.sorting,\n * quickSearch: gridState.quickSearch,\n * pagination: gridState.pagination,\n * paginationMode: \"client\",\n * });\n *\n * <DataGrid\n * columns={columns}\n * rows={gridData.rows}\n * getRowId={(r) => r.id}\n * totalRowCount={gridData.totalRowCount}\n * isLoading={gridData.isLoading}\n * state={gridState}\n * onChange={setGridState}\n * />\n * ```\n *\n * Iron rules:\n * - `rows` is always `gridData.rows`, never your raw array.\n * - Columns must be stable (define outside the component or wrap in `useMemo`).\n * - Initialize state with `createDefaultDataGridState(columns)`.\n * - `renderCell` must be a pure function — no React hooks inside.\n */\nexport function DataGrid<TRow>(props: DataGridProps<TRow>) {\n const {\n columns: allColumns,\n rows,\n getRowId,\n totalRowCount,\n isLoading = false,\n isRefetching = false,\n hasMore = false,\n isLoadingMore = false,\n onLoadMore,\n state,\n onChange,\n paginationMode = \"paginated\",\n selectionMode = \"none\",\n resizable = true,\n rowHeight: rowHeightProp = 44,\n estimatedRowHeight: estimatedRowHeightProp,\n headerHeight = 44,\n overscan = 5,\n maxHeight,\n fillHeight = true,\n stickyTop,\n toolbar,\n toolbarExtra,\n emptyState,\n loadingState,\n footer,\n footerExtra,\n exportFilename = \"export\",\n exportOptions,\n strings: stringsOverride,\n className,\n onRowClick,\n onRowDoubleClick,\n onSelectionChange,\n onSortChange,\n onColumnResize,\n onColumnVisibilityChange,\n } = props;\n\n const isDynamicRowHeight = rowHeightProp === \"auto\";\n const fixedRowHeight = isDynamicRowHeight ? undefined : rowHeightProp;\n const estimatedRowHeight = estimatedRowHeightProp ?? (fixedRowHeight ?? 44);\n\n const strings = useMemo(() => resolveDataGridStrings(stringsOverride), [stringsOverride]);\n\n // ── Build TanStack column defs from our column defs ──────────\n const tableColumns = useMemo<ColumnDef<TRow>[]>(\n () =>\n allColumns.map((col) => ({\n id: col.id,\n accessorFn: (row) => resolveColumnValue(col, row),\n header: typeof col.header === \"string\" ? col.header : col.id,\n size: col.width ?? DEFAULT_COL_WIDTH,\n minSize: getEffectiveMinWidth(col),\n maxSize: getEffectiveMaxWidth(col),\n enableSorting: col.sortable !== false,\n enableHiding: col.hideable !== false,\n enableResizing: col.resizable !== false,\n enableMultiSort: true,\n })),\n [allColumns],\n );\n\n // ── Translate our state ⇄ TanStack state via change handlers ───\n const tanstackSorting = useMemo(() => toTanstackSorting(state.sorting), [state.sorting]);\n const tanstackRowSelection = useMemo(\n () => toTanstackRowSelection(state.selection.selectedIds),\n [state.selection.selectedIds],\n );\n // ColumnSizing/Visibility/Order/Pinning share the same shape with TanStack.\n const tanstackColumnPinning = useMemo<ColumnPinningState>(\n () => ({ left: [...state.columnPinning.left], right: [...state.columnPinning.right] }),\n [state.columnPinning],\n );\n const tanstackColumnOrder = useMemo<ColumnOrderState>(\n () => [...state.columnOrder],\n [state.columnOrder],\n );\n\n const allColumnsRef = useRef(allColumns);\n allColumnsRef.current = allColumns;\n\n const handleSortingChange = useCallback(\n (updater: Updater<SortingState>) => {\n const next = resolveUpdater(updater, toTanstackSorting(state.sorting));\n const ours: DataGridSortItem[] = fromTanstackSorting(next).map((s) => ({ ...s }));\n // Reset to page 0 — page N of the new sort order is meaningless when\n // the order itself changed, and would silently scroll past relevant\n // rows.\n onChange((s) => ({\n ...s,\n sorting: ours,\n pagination: { ...s.pagination, pageIndex: 0 },\n }));\n onSortChange?.(ours);\n },\n [onChange, onSortChange, state.sorting],\n );\n\n const handleColumnSizingChange = useCallback(\n (updater: Updater<ColumnSizingState>) => {\n const next = resolveUpdater(updater, state.columnWidths);\n // Clamp each new width to our canvas-measured min and explicit max.\n const clamped: Record<string, number> = {};\n for (const [id, w] of Object.entries(next)) {\n const col = allColumnsRef.current.find((c) => c.id === id);\n clamped[id] = col ? clampColumnWidth(col, w) : w;\n }\n onChange((s) => ({ ...s, columnWidths: clamped }));\n // Fire onColumnResize for any column whose width changed.\n if (onColumnResize) {\n for (const [id, w] of Object.entries(clamped)) {\n if (state.columnWidths[id] !== w) onColumnResize(id, w);\n }\n }\n },\n [onChange, onColumnResize, state.columnWidths],\n );\n\n const handleVisibilityChange = useCallback(\n (updater: Updater<VisibilityState>) => {\n const next = resolveUpdater(updater, state.columnVisibility);\n onChange((s) => ({ ...s, columnVisibility: next }));\n onColumnVisibilityChange?.(next);\n },\n [onChange, onColumnVisibilityChange, state.columnVisibility],\n );\n\n const handleColumnOrderChange = useCallback(\n (updater: Updater<ColumnOrderState>) => {\n const next = resolveUpdater(updater, [...state.columnOrder]);\n onChange((s) => ({ ...s, columnOrder: next }));\n },\n [onChange, state.columnOrder],\n );\n\n const handleColumnPinningChange = useCallback(\n (updater: Updater<ColumnPinningState>) => {\n const current: ColumnPinningState = {\n left: [...state.columnPinning.left],\n right: [...state.columnPinning.right],\n };\n const next = resolveUpdater(updater, current);\n onChange((s) => ({\n ...s,\n columnPinning: { left: next.left ?? [], right: next.right ?? [] },\n }));\n },\n [onChange, state.columnPinning],\n );\n\n // ── TanStack Table instance ──────────────────────────────────\n const table = useReactTable<TRow>({\n data: rows as TRow[],\n columns: tableColumns,\n getRowId: (row) => getRowId(row),\n getCoreRowModel: getCoreRowModel(),\n state: {\n sorting: tanstackSorting,\n columnVisibility: state.columnVisibility,\n columnSizing: state.columnWidths,\n columnOrder: tanstackColumnOrder,\n columnPinning: tanstackColumnPinning,\n rowSelection: tanstackRowSelection,\n },\n onSortingChange: handleSortingChange,\n onColumnSizingChange: handleColumnSizingChange,\n onColumnVisibilityChange: handleVisibilityChange,\n onColumnOrderChange: handleColumnOrderChange,\n onColumnPinningChange: handleColumnPinningChange,\n columnResizeMode: \"onEnd\",\n enableRowSelection: selectionMode !== \"none\",\n enableMultiRowSelection: selectionMode === \"multiple\",\n enableColumnResizing: resizable,\n manualSorting: true,\n manualPagination: true,\n manualFiltering: true,\n });\n\n // ── Visible columns (in TanStack-resolved order, after visibility) ──\n const visibleColumns = useMemo(() => {\n const colMap = new Map(allColumns.map((c) => [c.id, c]));\n return table\n .getVisibleLeafColumns()\n .map((c) => colMap.get(c.id))\n .filter(Boolean) as DataGridColumnDef<TRow>[];\n }, [allColumns, table, state.columnOrder, state.columnVisibility]);\n\n // ── Row IDs (stable across this render) ──────────────────────\n const rowIds = useMemo(() => rows.map(getRowId), [rows, getRowId]);\n\n // ── Container width tracking (for `flex` column distribution) ─\n // Measure the scroll container's clientWidth, which excludes the vertical\n // scrollbar — using the outer grid would leave a few pixels of phantom\n // horizontal scroll when rows overflow.\n const [containerWidth, setContainerWidth] = useState(0);\n useLayoutEffect(() => {\n const grid = gridRef.current;\n const scroller = scrollContainerRef.current;\n if (!grid) return;\n const update = (entries?: ResizeObserverEntry[]) => {\n let measured = 0;\n if (entries != null) {\n for (const entry of entries) {\n measured = Math.max(measured, entry.contentRect.width);\n }\n }\n if (measured <= 0) {\n const scrollerWidth = scroller?.clientWidth ?? 0;\n const gridWidth = grid.clientWidth;\n measured = scrollerWidth > 0 ? scrollerWidth : gridWidth;\n }\n if (measured > 0) setContainerWidth(measured);\n };\n update();\n const observer = new ResizeObserver((entries) => update(entries));\n observer.observe(grid);\n if (scroller) observer.observe(scroller);\n return () => observer.disconnect();\n }, []);\n\n // ── Column width CSS variables (TanStack pattern) ────────────\n // With `columnResizeMode: \"onEnd\"`, live drag width comes from deltaOffset; committed sizes update on pointer-up.\n const columnSizingInfo = table.getState().columnSizingInfo;\n const columnSizes = useMemo<Record<string, number>>(() => {\n const sizes: Record<string, number> = {};\n let baseTotal = selectionMode !== \"none\" ? 44 : 0;\n const resizingId = columnSizingInfo.isResizingColumn || null;\n const deltaOffset = columnSizingInfo.deltaOffset ?? 0;\n for (const col of visibleColumns) {\n const tsCol = table.getColumn(col.id);\n const baseSize = tsCol?.getSize() ?? col.width ?? DEFAULT_COL_WIDTH;\n const liveSize = resizingId === col.id\n ? clampColumnWidth(col, baseSize + deltaOffset)\n : baseSize;\n sizes[col.id] = liveSize;\n baseTotal += liveSize;\n }\n distributeFlexWidths(sizes, visibleColumns, containerWidth - baseTotal);\n return sizes;\n }, [visibleColumns, table, columnSizingInfo, state.columnWidths, containerWidth, selectionMode]);\n\n const totalContentWidth = useMemo(() => {\n let total = selectionMode !== \"none\" ? 44 : 0;\n for (const col of visibleColumns) total += columnSizes[col.id] ?? 0;\n return total;\n }, [visibleColumns, columnSizes, selectionMode]);\n\n const cssVars = useMemo<CSSProperties>(() => {\n const vars: Record<string, string | number> = { \"--grid-total-w\": `${totalContentWidth}px` };\n for (const col of visibleColumns) {\n vars[`--col-${col.id}-size`] = columnSizes[col.id];\n }\n return vars as CSSProperties;\n }, [visibleColumns, columnSizes, totalContentWidth]);\n\n // ── Selection handlers ───────────────────────────────────────\n const fireSelection = useCallback(\n (next: DataGridSelectionModel) => {\n onChange((s) => ({ ...s, selection: next }));\n if (onSelectionChange) {\n const idSet = next.selectedIds;\n const selectedRows = rows.filter((r) => idSet.has(getRowId(r)));\n onSelectionChange(idSet, selectedRows);\n }\n },\n [onChange, onSelectionChange, rows, getRowId],\n );\n\n const handleRowClick = useCallback(\n (row: TRow, rowId: RowId, event: React.MouseEvent) => {\n if (selectionMode !== \"none\") {\n const next = nextSelection({\n current: state.selection,\n rowId,\n mode: selectionMode,\n modifiers: { shift: event.shiftKey, ctrl: event.metaKey || event.ctrlKey },\n allRowIds: rowIds,\n });\n fireSelection(next);\n }\n onRowClick?.(row, rowId, event);\n },\n [selectionMode, state.selection, rowIds, fireSelection, onRowClick],\n );\n\n const handleSelectAll = useCallback(() => {\n const allSelectedNow = rowIds.length > 0 && rowIds.every((id) => state.selection.selectedIds.has(id));\n fireSelection(\n allSelectedNow\n ? { selectedIds: new Set(), anchorId: null }\n : { selectedIds: new Set(rowIds), anchorId: null },\n );\n }, [rowIds, state.selection.selectedIds, fireSelection]);\n\n // ── Export ───────────────────────────────────────────────────\n const [exportDialogOpen, setExportDialogOpen] = useState(false);\n const handleExportCsv = useCallback(() => {\n setExportDialogOpen(true);\n }, []);\n\n // ── Virtualizer ──────────────────────────────────────────────\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const headerScrollRef = useRef<HTMLDivElement>(null);\n const stickyChromeRef = useRef<HTMLDivElement>(null);\n const rowsClipRef = useRef<HTMLDivElement>(null);\n const gridRef = useRef<HTMLDivElement>(null);\n const measureElementFn = useCallback((el: Element) => el.getBoundingClientRect().height, []);\n\n const rowVirtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => scrollContainerRef.current,\n estimateSize: () => estimatedRowHeight,\n overscan,\n getItemKey: (index) => {\n const row = rows[index];\n return row != null ? String(getRowId(row)) : index;\n },\n ...(isDynamicRowHeight ? { measureElement: measureElementFn } : {}),\n });\n\n // ── Sticky chrome clipping ───────────────────────────────────\n useLayoutEffect(() => {\n const gridEl = gridRef.current;\n const stickyEl = stickyChromeRef.current;\n const bodyEl = scrollContainerRef.current;\n const clipEl = rowsClipRef.current;\n if (!gridEl || !stickyEl || !bodyEl || !clipEl) return;\n\n const updateClip = () => {\n const stickyRect = stickyEl.getBoundingClientRect();\n const clipRect = clipEl.getBoundingClientRect();\n const overlap = Math.max(0, stickyRect.bottom - clipRect.top);\n clipEl.style.setProperty(\"--data-grid-sticky-overlap\", `${overlap}px`);\n };\n updateClip();\n bodyEl.addEventListener(\"scroll\", updateClip);\n window.addEventListener(\"scroll\", updateClip, true);\n window.addEventListener(\"resize\", updateClip);\n const observer = new ResizeObserver(updateClip);\n observer.observe(gridEl);\n observer.observe(stickyEl);\n observer.observe(bodyEl);\n return () => {\n bodyEl.removeEventListener(\"scroll\", updateClip);\n window.removeEventListener(\"scroll\", updateClip, true);\n window.removeEventListener(\"resize\", updateClip);\n observer.disconnect();\n };\n }, []);\n\n const handleBodyScroll = useCallback(() => {\n const body = scrollContainerRef.current;\n const header = headerScrollRef.current;\n if (body && header) header.scrollLeft = body.scrollLeft;\n }, []);\n\n // ── Toolbar / Footer context ─────────────────────────────────\n const toolbarCtx: DataGridToolbarContext<TRow> = useMemo(\n () => ({\n state,\n onChange,\n columns: allColumns,\n visibleColumns,\n totalRowCount,\n selectedRowCount: state.selection.selectedIds.size,\n strings,\n exportCsv: handleExportCsv,\n }),\n [state, onChange, allColumns, visibleColumns, totalRowCount, strings, handleExportCsv],\n );\n const footerCtx: DataGridFooterContext<TRow> = useMemo(\n () => ({\n state,\n totalRowCount,\n visibleRowCount: rows.length,\n selectedRowCount: state.selection.selectedIds.size,\n paginationMode,\n strings,\n }),\n [state, totalRowCount, rows.length, paginationMode, strings],\n );\n\n const allSelected = rowIds.length > 0 && rowIds.every((id) => state.selection.selectedIds.has(id));\n const someSelected = !allSelected && rowIds.some((id) => state.selection.selectedIds.has(id));\n\n // An infinite-scroll grid MUST have a height-bounded scroll container, otherwise the container\n // grows to fit every loaded row, the virtualizer measures it as fully visible, and it renders\n // all rows into the DOM — unbounded memory growth that eventually OOMs the tab (rows never stop\n // accumulating as the user scrolls). When the caller didn't bound it (no fillHeight, no maxHeight),\n // fall back to a viewport-relative cap so virtualization can actually window. Only applied to\n // infinite mode; paginated grids cap rows at the page size and are safe to render unbounded.\n const effectiveMaxHeight =\n maxHeight ?? (paginationMode === \"infinite\" && !fillHeight ? DEFAULT_INFINITE_MAX_HEIGHT : undefined);\n\n const infiniteScrollRootRef =\n paginationMode === \"infinite\" && (fillHeight || effectiveMaxHeight != null)\n ? scrollContainerRef\n : undefined;\n\n // ── Header rendering helper (TanStack header objects, in order) ──\n const headers: Header<TRow, unknown>[] = useMemo(\n () =>\n table\n .getHeaderGroups()[0]?.headers\n .filter((h) => visibleColumns.some((c) => c.id === h.column.id)) ?? [],\n [table, visibleColumns],\n );\n const headerByColId = useMemo(() => {\n const m = new Map<string, Header<TRow, unknown>>();\n for (const h of headers) m.set(h.column.id, h);\n return m;\n }, [headers]);\n\n const isBounded = fillHeight || effectiveMaxHeight != null;\n\n return (\n <>\n <DataGridExportDialog\n open={exportDialogOpen}\n onOpenChange={setExportDialogOpen}\n rows={rows}\n columns={visibleColumns}\n exportFilename={exportFilename}\n exportOptions={exportOptions}\n />\n <div\n ref={gridRef}\n className={cn(\n \"isolate flex w-full min-w-0 max-w-full flex-col bg-transparent rounded-[calc(var(--radius)*2)]\",\n fillHeight ? \"min-h-0 h-full\" : \"min-h-0 h-auto\",\n isBounded && \"overflow-hidden\",\n className,\n )}\n style={effectiveMaxHeight != null ? { ...cssVars, maxHeight: effectiveMaxHeight } : cssVars}\n role=\"grid\"\n aria-rowcount={totalRowCount ?? rows.length}\n aria-colcount={visibleColumns.length}\n >\n <div\n ref={stickyChromeRef}\n className=\"sticky z-30 w-full min-w-0 shrink-0 overflow-visible rounded-t-[calc(var(--radius)*2)] bg-white/90 dark:bg-background backdrop-blur-xl\"\n style={{ top: stickyTop ?? (effectiveMaxHeight != null ? 0 : \"var(--data-grid-sticky-top, 0px)\") }}\n >\n {toolbar !== false && (\n <div className=\"relative bg-transparent\">\n {toolbar\n ? toolbar(toolbarCtx)\n : (\n <DataGridToolbar\n ctx={toolbarCtx}\n extra={typeof toolbarExtra === \"function\" ? toolbarExtra(toolbarCtx) : toolbarExtra}\n />\n )}\n </div>\n )}\n\n <div className=\"relative\">\n {isRefetching && (\n <div className=\"absolute top-0 left-0 right-0 h-0.5 z-30 bg-foreground/[0.04] overflow-hidden\">\n <div className=\"h-full w-1/3 bg-blue-500/60 rounded-full animate-pulse\" />\n </div>\n )}\n <div\n ref={headerScrollRef}\n className=\"w-full min-w-0 shrink-0 overflow-hidden border-b border-foreground/[0.06]\"\n >\n <div\n className=\"flex\"\n style={{ height: headerHeight, minWidth: totalContentWidth }}\n role=\"row\"\n >\n {selectionMode !== \"none\" && (\n <div\n className=\"flex items-center justify-center border-r border-foreground/[0.04]\"\n style={{ width: 44 }}\n >\n {selectionMode === \"multiple\" && (\n <SelectionCheckbox\n checked={allSelected}\n indeterminate={someSelected}\n onChange={handleSelectAll}\n ariaLabel=\"Select all rows on this page\"\n title=\"Select all rows on this page\"\n />\n )}\n </div>\n )}\n {visibleColumns.map((col) => {\n const header = headerByColId.get(col.id);\n if (!header) return null;\n return <HeaderCell key={col.id} header={header} col={col} resizable={resizable} />;\n })}\n </div>\n </div>\n </div>\n </div>\n\n <div\n ref={scrollContainerRef}\n className={cn(\n \"relative z-0 w-full min-w-0 overflow-auto bg-transparent\",\n isBounded ? \"min-h-0 flex-1\" : \"flex-none\",\n \"[&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar]:h-1.5\",\n \"[&::-webkit-scrollbar-track]:bg-transparent\",\n \"[&::-webkit-scrollbar-thumb]:bg-foreground/[0.08] [&::-webkit-scrollbar-thumb]:rounded-full\",\n \"[&::-webkit-scrollbar-thumb]:hover:bg-foreground/[0.15]\",\n )}\n onScroll={handleBodyScroll}\n >\n <div\n ref={rowsClipRef}\n data-data-grid-rows-clip=\"\"\n className=\"relative z-0\"\n style={{\n minWidth: totalContentWidth,\n clipPath: \"inset(var(--data-grid-sticky-overlap, 0px) 0 0 0)\",\n }}\n >\n {isLoading && (\n <div style={{ minWidth: totalContentWidth }}>\n {loadingState ?? Array.from({ length: 8 }).map((_, i) => (\n <SkeletonRow\n key={i}\n columns={visibleColumns}\n height={estimatedRowHeight}\n showCheckbox={selectionMode !== \"none\"}\n />\n ))}\n </div>\n )}\n\n {!isLoading && rows.length === 0 && (\n <div\n className=\"flex items-center justify-center py-16 text-sm text-muted-foreground\"\n style={{ minWidth: totalContentWidth }}\n >\n {emptyState ?? strings.noData}\n </div>\n )}\n\n {!isLoading && rows.length > 0 && (\n <div\n style={{\n height: rowVirtualizer.getTotalSize(),\n width: \"100%\",\n minWidth: totalContentWidth,\n position: \"relative\",\n }}\n >\n {rowVirtualizer.getVirtualItems().map((virtualRow: VirtualItem) => {\n const row = rows[virtualRow.index] ?? throwErr(\n `DataGrid: virtualized row index ${virtualRow.index} out of range (rows.length=${rows.length})`,\n );\n const rowId = getRowId(row);\n const isSelected = state.selection.selectedIds.has(rowId);\n const isOddRow = virtualRow.index % 2 === 1;\n return (\n <div\n key={rowId}\n ref={isDynamicRowHeight ? rowVirtualizer.measureElement : undefined}\n data-index={virtualRow.index}\n className={cn(\n \"absolute left-0 w-full flex\",\n \"border-b border-black/[0.03] dark:border-white/[0.03]\",\n \"transition-colors duration-75\",\n isSelected\n ? \"bg-blue-500/[0.06] dark:bg-blue-400/[0.08] hover:bg-blue-500/[0.08] dark:hover:bg-blue-400/[0.1]\"\n : isOddRow\n ? \"bg-foreground/[0.02] dark:bg-foreground/[0.03] hover:bg-foreground/[0.04] dark:hover:bg-foreground/[0.06]\"\n : \"hover:bg-foreground/[0.025] dark:hover:bg-foreground/[0.04]\",\n (selectionMode !== \"none\" || onRowClick) && \"cursor-pointer\",\n )}\n style={{\n ...(isDynamicRowHeight\n ? { minHeight: estimatedRowHeight }\n : { height: fixedRowHeight }),\n transform: `translateY(${virtualRow.start}px)`,\n }}\n onClick={(e) => { if (!shouldIgnoreRowClick(e)) handleRowClick(row, rowId, e); }}\n onDoubleClick={(e) => { if (!shouldIgnoreRowClick(e)) onRowDoubleClick?.(row, rowId, e); }}\n role=\"row\"\n aria-rowindex={virtualRow.index + 2}\n aria-selected={isSelected}\n data-row-id={rowId}\n data-state={isSelected ? \"selected\" : undefined}\n >\n {selectionMode !== \"none\" && (\n <div\n className=\"flex items-center justify-center border-r border-black/[0.04] dark:border-white/[0.04]\"\n style={{ width: 44 }}\n >\n <SelectionCheckbox\n checked={isSelected}\n onChange={(event) => handleRowClick(row, rowId, event)}\n ariaLabel={`Select row ${rowId}`}\n />\n </div>\n )}\n {visibleColumns.map((col) => (\n <DataCell\n key={col.id}\n col={col}\n row={row}\n rowId={rowId}\n rowIndex={virtualRow.index}\n isSelected={isSelected}\n dateDisplay={state.dateDisplay}\n />\n ))}\n </div>\n );\n })}\n </div>\n )}\n\n {paginationMode === \"infinite\" && hasMore && !isLoading && (\n <InfiniteScrollSentinel\n onIntersect={onLoadMore ?? NOOP}\n isLoading={isLoadingMore}\n rootRef={infiniteScrollRootRef}\n strings={strings}\n />\n )}\n </div>\n </div>\n\n {footer !== false && (\n <div className=\"sticky bottom-0 z-30 shrink-0 overflow-hidden rounded-b-[calc(var(--radius)*2)] bg-white/90 dark:bg-background backdrop-blur-xl\">\n {footer ? footer(footerCtx) : <DefaultFooter ctx={footerCtx} pagination={paginationMode} onChange={onChange} />}\n {footerExtra && (typeof footerExtra === \"function\" ? footerExtra(footerCtx) : footerExtra)}\n </div>\n )}\n </div>\n </>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AA+DA,MAAM,8BAA8B;AAIpC,SAAS,sBAAsB,QAA4C;CACzE,IAAI,kBAAkB,SAAS,OAAO;CACtC,IAAI,kBAAkB,MAAM,OAAO,OAAO;CAC1C,OAAO;AACT;AAEA,SAAgB,oCAAoC,QAAqC;CAEvF,OADW,sBAAsB,MACzB,CAAC,EAAE,QAAQ;EACjB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK;AAClB;AAEA,SAAS,qBAAqB,OAAkC;CAC9D,OAAO,MAAM,oBAAoB,oCAAoC,MAAM,MAAM;AACnF;AAIA,SAAS,kBAAkB,SAA0C;CACnE,OAAO,QAAQ,KAAK,OAAO;EAAE,IAAI,EAAE;EAAU,MAAM,EAAE,cAAc;CAAO,EAAE;AAC9E;AAEA,SAAS,oBAAoB,SAA0C;CACrE,OAAO,QAAQ,KAAK,OAAO;EAAE,UAAU,EAAE;EAAI,WAAW,EAAE,OAAO,SAAS;CAAM,EAAE;AACpF;AAEA,SAAS,uBAAuB,KAA4C;CAC1E,MAAM,MAAyB,CAAC;CAChC,KAAK,MAAM,MAAM,KAAK,IAAI,MAAM;CAChC,OAAO;AACT;AAEA,SAAS,eAAkB,SAAqB,SAAe;CAC7D,OAAO,OAAO,YAAY,aAAc,QAA0B,OAAO,IAAI;AAC/E;AAIA,SAAS,qBACP,OACA,gBACA,WACM;CACN,MAAM,WAAW,eAAe,QAAQ,MAAM,EAAE,QAAQ,QAAQ,EAAE,OAAO,CAAC;CAC1E,IAAI,SAAS,WAAW,KAAK,aAAa,GAAG;CAC7C,MAAM,YAAY,SAAS,QAAQ,KAAK,MAAM,OAAO,EAAE,QAAQ,IAAI,CAAC;CACpE,IAAI,YAAY;CAChB,SAAS,SAAS,KAAK,MAAM;EAE3B,MAAM,QADS,MAAM,SAAS,SAAS,IAEnC,YACA,KAAK,MAAM,cAAc,IAAI,QAAQ,KAAK,UAAU;EACxD,MAAM,MAAM,IAAI,YAAY;EAC5B,MAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM,MAAM,IAAI,GAAG,CAAC;EAC5D,MAAM,IAAI,OAAO;EACjB,aAAa;CACf,CAAC;AACH;AAYA,SAAS,aAAa,SAAiC,OAAsC;CAC3F,MAAM,aAAa,QAAQ,YAAY,IAAI,KAAK;CAChD,OAAO;EACL,aAAa,6BAAa,IAAI,IAAI,oBAAI,IAAI,IAAI,CAAC,KAAK,CAAC;EACrD,UAAU,aAAa,OAAO;CAChC;AACF;AAEA,SAAS,YACP,SACA,OACA,WACA,UAC+B;CAC/B,IAAI,QAAQ,YAAY,MAAM,OAAO;CACrC,MAAM,YAAY,UAAU,QAAQ,QAAQ,QAAQ;CACpD,MAAM,aAAa,UAAU,QAAQ,KAAK;CAC1C,IAAI,YAAY,KAAK,aAAa,GAAG,OAAO;CAC5C,MAAM,QAAQ,KAAK,IAAI,WAAW,UAAU;CAC5C,MAAM,MAAM,KAAK,IAAI,WAAW,UAAU;CAC1C,MAAM,OAAO,WAAW,IAAI,IAAI,QAAQ,WAAW,oBAAI,IAAI,IAAW;CACtE,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,KAAK,KAAK,IAAI,UAAU,EAAG;CACzD,OAAO;EAAE,aAAa;EAAM,UAAU,QAAQ;CAAS;AACzD;AAEA,SAAS,aAAa,SAAiC,OAAsC;CAC3F,MAAM,OAAO,IAAI,IAAI,QAAQ,WAAW;CACxC,IAAI,KAAK,IAAI,KAAK,GAAG,KAAK,OAAO,KAAK;MACjC,KAAK,IAAI,KAAK;CACnB,OAAO;EAAE,aAAa;EAAM,UAAU;CAAM;AAC9C;AAEA,SAAS,cAAc,OAA+C;CACpE,MAAM,EAAE,SAAS,OAAO,MAAM,WAAW,cAAc;CACvD,IAAI,SAAS,UAAU,OAAO,aAAa,SAAS,KAAK;CACzD,IAAI,UAAU,OAAO;EACnB,MAAM,QAAQ,YAAY,SAAS,OAAO,WAAW,UAAU,IAAI;EACnE,IAAI,SAAS,MAAM,OAAO;CAC5B;CACA,IAAI,UAAU,MAAM,OAAO,aAAa,SAAS,KAAK;CACtD,OAAO;EAAE,6BAAa,IAAI,IAAI,CAAC,KAAK,CAAC;EAAG,UAAU;CAAM;AAC1D;AAIA,SAAS,WAAiB,EACxB,QACA,KACA,aAKC;CACD,MAAM,SAAS,OAAO,OAAO,YAAY;CACzC,MAAM,YAAY,OAAO,OAAO,aAAa;CAC7C,MAAM,aAAa,OAAO,OAAO,gBAAgB,IAC7C,OAAO,WAAW,CAAC,CAAC,MAAM,SAAS,CAAC,CAAC,QAAQ,SAC7C;CACJ,MAAM,MAAmC;EACvC,UAAU,IAAI;EACd,WAAW;EACX,UAAU,WAAW,QAAQ,QAAQ;EACrC,WAAW,aAAa,KAAK,aAAa,IAAI,YAAY,IAAI;CAChE;CACA,MAAM,QAAQ,OAAO,IAAI,WAAW,aAAa,IAAI,OAAO,GAAG,IAAI,IAAI;CACvE,MAAM,WAAW,OAAO,OAAO,WAAW;CAC1C,MAAM,YAAY,aAAa,OAAO,OAAO,aAAa;CAC1D,MAAM,aAAa,OAAO,OAAO,cAAc;CAE/C,OACE,qBAAC,OAAD;EACE,WAAW,GACT,mGACA,yEACA,YAAY,gBACd;EACA,OAAO,EAAE,OAAO,kBAAkB,IAAI,GAAG,eAAe;EACxD,eAAa,IAAI;EACjB,SAAS,WAAW,OAAO,OAAO,wBAAwB,IAAI,KAAA;EAC9D,MAAK;EACL,aAAW,WAAW,QAAQ,cAAc,WAAW,SAAS,eAAe;YAVjF;GAYE,oBAAC,QAAD;IACE,WAAW,GACT,gGACA,IAAI,UAAU,YAAY,eAC1B,IAAI,UAAU,WAAW,YAC3B;cAEC;GACG,CAAA;GAEL,UACC,qBAAC,QAAD;IAAM,WAAU;cAAhB,CACG,WAAW,QACR,oBAAC,SAAD;KAAS,WAAU;KAAU,QAAO;IAAQ,CAAA,IAC5C,oBAAC,WAAD;KAAW,WAAU;KAAU,QAAO;IAAQ,CAAA,GACjD,IAAI,aAAa,QAChB,oBAAC,QAAD;KAAM,WAAU;eAAwC,IAAI;IAAgB,CAAA,CAE1E;;GAGP,CAAC,UAAU,YACV,qBAAC,QAAD;IAAM,WAAU;cAAhB,CACE,oBAAC,SAAD;KAAS,WAAU;KAAwB,QAAO;IAAQ,CAAA,GAC1D,oBAAC,WAAD;KAAW,WAAU;KAAwB,QAAO;IAAQ,CAAA,CACxD;;GAGP,aACC,oBAAC,OAAD;IACE,aAAa,OAAO,iBAAiB;IACrC,cAAc,OAAO,iBAAiB;IACtC,UAAU,MAAM;KACd,EAAE,eAAe;KACjB,EAAE,gBAAgB;IACpB;IACA,WAAW,GACT,6EACA,iEACA,kCACA,cAAc,gBAChB;GACD,CAAA;EAEA;;AAET;AAIA,SAAS,SAAe,EACtB,KACA,KACA,OACA,UACA,YACA,eAQC;CACD,MAAM,QAAQ,mBAAmB,KAAK,GAAG;CACzC,MAAM,MAAiC;EAAE;EAAK;EAAO;EAAU;EAAO,UAAU,IAAI;EAAI;EAAY;CAAY;CAEhH,MAAM,YAAY,IAAI,SAAS,UAAU,IAAI,SAAS;CACtD,IAAI;CACJ,IAAI,IAAI,YAAY,UAAU,IAAI,WAAW,GAAG;MAC3C,IAAI,WAAW,UAAU,eAAe,OAAO,aAAa,GAAG;MAC/D,UAAU,gBAAgB,KAAK;CAEpC,MAAM,eAAe,IAAI,eAAe,IAAI;CAC5C,MAAM,SAAS,IAAI,iBAAiB;CAEpC,OACE,oBAAC,OAAD;EACE,WAAW,GACT,4CACA,yEACA,2BACA,SAAS,qBAAqB,gBAC9B,IAAI,UAAU,YAAY,kBAC1B,IAAI,UAAU,WAAW,eACzB,gBAAgB,gBAClB;EACA,OAAO,EAAE,OAAO,kBAAkB,IAAI,GAAG,eAAe;EACxD,eAAa,IAAI;EACjB,MAAK;EACL,SAAS,IAAI,eAAe,MAAM;GAChC,EAAE,gBAAgB;GAClB,IAAI,YAAa,KAAK,CAAC;EACzB,IAAI,KAAA;EACJ,eAAe,IAAI,qBAAqB,MAAM;GAC5C,EAAE,gBAAgB;GAClB,IAAI,kBAAmB,KAAK,CAAC;EAC/B,IAAI,KAAA;YAEJ,oBAAC,OAAD;GAAK,WAAW,GAAG,WAAW,SAAS,WAAW,UAAU;aAAI;EAAa,CAAA;CAC1E,CAAA;AAET;AAEA,SAAS,gBAAgB,OAAiC;CACxD,IAAI,SAAS,MAAM,OAAO,oBAAC,QAAD;EAAM,WAAU;YAA2B;CAAO,CAAA;CAC5E,IAAI,OAAO,UAAU,WACnB,OACE,oBAAC,QAAD;EAAM,WAAW,GACf,yEACA,QACI,6DACA,4CACN;YACG,QAAQ,QAAQ;CACb,CAAA;CAGV,IAAI,iBAAiB,MACnB,OAAO,oBAAC,QAAD;EAAM,WAAU;YAAsC,MAAM,mBAAmB;CAAQ,CAAA;CAEhG,OAAO,oBAAC,QAAD;EAAM,WAAU;YAAY,OAAO,KAAK;CAAQ,CAAA;AACzD;AAEA,SAAS,eACP,OACA,aACA,KACiB;CACjB,MAAM,EAAE,SAAS,YAAY,eAAe,OAAO,aAAa;EAC9D,YAAY,IAAI;EAChB,YAAY,IAAI;CAClB,CAAC;CACD,IAAI,WAAW,MAAM,OAAO,oBAAC,QAAD;EAAM,WAAU;YAA2B;CAAO,CAAA;CAC9E,OACE,oBAAC,QAAD;EAAM,WAAU;EAA0D,OAAO,WAAW,KAAA;YACzF;CACG,CAAA;AAEV;AAIA,SAAS,gBAAgB,OAAuB;CAC9C,IAAI,OAAO;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,QAAS,QAAQ,KAAK,OAAO,MAAM,WAAW,CAAC,IAAK;CAC3F,OAAO,KAAK,IAAI,IAAI;AACtB;AAEA,SAAS,YAAY,EACnB,SACA,QACA,gBAKC;CACD,OACE,qBAAC,OAAD;EAAK,WAAU;EAAO,OAAO,EAAE,OAAO;EAAG,MAAK;YAA9C,CACG,gBACC,oBAAC,OAAD;GAAK,WAAU;GAAyF,OAAO,EAAE,OAAO,GAAG;aACzH,oBAAC,gBAAD,EAAgB,WAAU,kBAAmB,CAAA;EAC1C,CAAA,GAEN,QAAQ,KAAK,QACZ,oBAAC,OAAD;GAEE,WAAU;GACV,OAAO,EAAE,OAAO,kBAAkB,IAAI,GAAG,eAAe;aAExD,oBAAC,gBAAD;IAAgB,WAAU;IAAmB,OAAO,EAAE,OAAO,GAAG,KAAM,gBAAgB,IAAI,EAAE,IAAI,GAAI,GAAG;GAAI,CAAA;EACxG,GALE,IAAI,EAKN,CACN,CACE;;AAET;AAIA,SAAS,kBAAkB,EACzB,SACA,eACA,UACA,WACA,SAOC;CACD,MAAM,OAAO,gBAAgB,cAAc,UAAU,cAAc;CACnE,OACE,oBAAC,UAAD;EACE,WAAW,GACT,kDACA,4DACA,WAAW,gBACP,qCACA,yDACN;EACA,UAAU,MAAM;GACd,EAAE,gBAAgB;GAClB,SAAS,CAAC;EACZ;EACA,cAAY;EACZ,OAAO,SAAS;EAChB,MAAK;EACL,gBAAc,gBAAgB,UAAU;YAExC,oBAAC,MAAD;GAAM,WAAU;GAAU,QAAQ,WAAW,gBAAgB,SAAS;EAAY,CAAA;CAC5E,CAAA;AAEZ;AAIA,MAAM,aAAa,CAAC;AAEpB,SAAS,uBAAuB,EAC9B,aACA,WACA,SACA,WAMC;CACD,MAAM,MAAM,OAAuB,IAAI;CAUvC,MAAM,iBAAiB,OAAO,WAAW;CACzC,eAAe,UAAU;CACzB,gBAAgB;EACd,MAAM,KAAK,IAAI;EACf,IAAI,CAAC,IAAI;EACT,MAAM,WAAW,IAAI,sBAClB,YAAY;GAAE,IAAI,QAAQ,EAAE,EAAE,gBAAgB,eAAe,QAAQ;EAAG,GACzE;GAAE,MAAM,SAAS,WAAW;GAAM,YAAY;EAAQ,CACxD;EACA,SAAS,QAAQ,EAAE;EACnB,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,OAAO,CAAC;CACZ,OACE,oBAAC,OAAD;EAAU;EAAK,WAAU;YACtB,aACC,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD,EAAK,WAAU,iFAAkF,CAAA,GAChG,QAAQ,WACN;;CAEJ,CAAA;AAET;AAIA,SAAS,cAAoB,EAC3B,KACA,YACA,YAKC;CACD,MAAM,EAAE,OAAO,eAAe,iBAAiB,kBAAkB,YAAY;CAC7E,MAAM,aAAa,iBAAiB,OAChC,KAAK,IAAI,GAAG,KAAK,KAAK,gBAAgB,MAAM,WAAW,QAAQ,CAAC,IAChE,KAAA;CAEJ,MAAM,WAAW,cACf,UAAU,OAAO;EAAE,GAAG;EAAG,YAAY;GAAE,GAAG,EAAE;GAAY;EAAU;CAAE,EAAE;CACxE,MAAM,eAAe,aACnB,UAAU,OAAO;EAAE,GAAG;EAAG,YAAY;GAAE,GAAG,EAAE;GAAY;GAAU,WAAW;EAAE;CAAE,EAAE;CAErF,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACG,mBAAmB,KAClB,oBAAC,QAAD;IAAM,WAAU;cAA+B,QAAQ,aAAa,gBAAgB;GAAQ,CAAA,GAE7F,iBAAiB,QAAQ,qBAAC,QAAD,EAAA,UAAA;IAAO;IAAgB;IAAK;IAAc;GAAW,EAAA,CAAA,CAC5E;MAEJ,eAAe,cAAc,cAAc,QAC1C,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,QAAD,EAAA,UAAO,QAAQ,YAAkB,CAAA,GACjC,oBAAC,UAAD;KACE,WAAW,GACT,6EACA,yFACA,uFACA,sHACF;KACA,OAAO,MAAM,WAAW;KACxB,WAAW,MAAM,YAAY,OAAO,EAAE,OAAO,KAAK,CAAC;eAElD;MAAC;MAAI;MAAI;MAAI;KAAG,CAAC,CAAC,KAAK,SAAS,oBAAC,UAAD;MAAmB,OAAO;gBAAO;KAAa,GAAjC,IAAiC,CAAC;IAC1E,CAAA,CACL;OACL,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,UAAD;MACE,WAAW,GACT,uDACA,8EACA,+BACF;MACA,eAAe,QAAQ,MAAM,WAAW,YAAY,CAAC;MACrD,UAAU,MAAM,WAAW,cAAc;MACzC,cAAW;gBAEX,oBAAC,SAAD;OAAS,WAAU;OAAyB,QAAO;MAAQ,CAAA;KACrD,CAAA;KACR,oBAAC,QAAD;MAAM,WAAU;gBACb,QAAQ,OAAO,MAAM,WAAW,YAAY,GAAG,UAAU;KACtD,CAAA;KACN,oBAAC,UAAD;MACE,WAAW,GACT,uDACA,8EACA,+BACF;MACA,eAAe,QAAQ,MAAM,WAAW,YAAY,CAAC;MACrD,UAAU,MAAM,WAAW,aAAa,aAAa;MACrD,cAAW;gBAEX,oBAAC,WAAD;OAAW,WAAU;OAAyB,QAAO;MAAQ,CAAA;KACvD,CAAA;IACL;KACF;IAEJ;;AAET;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,SAAe,OAA4B;CACzD,MAAM,EACJ,SAAS,YACT,MACA,UACA,eACA,YAAY,OACZ,eAAe,OACf,UAAU,OACV,gBAAgB,OAChB,YACA,OACA,UACA,iBAAiB,aACjB,gBAAgB,QAChB,YAAY,MACZ,WAAW,gBAAgB,IAC3B,oBAAoB,wBACpB,eAAe,IACf,WAAW,GACX,WACA,aAAa,MACb,WACA,SACA,cACA,YACA,cACA,QACA,aACA,iBAAiB,UACjB,eACA,SAAS,iBACT,WACA,YACA,kBACA,mBACA,cACA,gBACA,6BACE;CAEJ,MAAM,qBAAqB,kBAAkB;CAC7C,MAAM,iBAAiB,qBAAqB,KAAA,IAAY;CACxD,MAAM,qBAAqB,0BAA2B,kBAAkB;CAExE,MAAM,UAAU,cAAc,uBAAuB,eAAe,GAAG,CAAC,eAAe,CAAC;CAGxF,MAAM,eAAe,cAEjB,WAAW,KAAK,SAAS;EACvB,IAAI,IAAI;EACR,aAAa,QAAQ,mBAAmB,KAAK,GAAG;EAChD,QAAQ,OAAO,IAAI,WAAW,WAAW,IAAI,SAAS,IAAI;EAC1D,MAAM,IAAI,SAAS;EACnB,SAAS,qBAAqB,GAAG;EACjC,SAAS,qBAAqB,GAAG;EACjC,eAAe,IAAI,aAAa;EAChC,cAAc,IAAI,aAAa;EAC/B,gBAAgB,IAAI,cAAc;EAClC,iBAAiB;CACnB,EAAE,GACJ,CAAC,UAAU,CACb;CAGA,MAAM,kBAAkB,cAAc,kBAAkB,MAAM,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC;CACvF,MAAM,uBAAuB,cACrB,uBAAuB,MAAM,UAAU,WAAW,GACxD,CAAC,MAAM,UAAU,WAAW,CAC9B;CAEA,MAAM,wBAAwB,eACrB;EAAE,MAAM,CAAC,GAAG,MAAM,cAAc,IAAI;EAAG,OAAO,CAAC,GAAG,MAAM,cAAc,KAAK;CAAE,IACpF,CAAC,MAAM,aAAa,CACtB;CACA,MAAM,sBAAsB,cACpB,CAAC,GAAG,MAAM,WAAW,GAC3B,CAAC,MAAM,WAAW,CACpB;CAEA,MAAM,gBAAgB,OAAO,UAAU;CACvC,cAAc,UAAU;CAExB,MAAM,sBAAsB,aACzB,YAAmC;EAElC,MAAM,OAA2B,oBADpB,eAAe,SAAS,kBAAkB,MAAM,OAAO,CACZ,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,GAAG,EAAE,EAAE;EAIhF,UAAU,OAAO;GACf,GAAG;GACH,SAAS;GACT,YAAY;IAAE,GAAG,EAAE;IAAY,WAAW;GAAE;EAC9C,EAAE;EACF,eAAe,IAAI;CACrB,GACA;EAAC;EAAU;EAAc,MAAM;CAAO,CACxC;CAEA,MAAM,2BAA2B,aAC9B,YAAwC;EACvC,MAAM,OAAO,eAAe,SAAS,MAAM,YAAY;EAEvD,MAAM,UAAkC,CAAC;EACzC,KAAK,MAAM,CAAC,IAAI,MAAM,OAAO,QAAQ,IAAI,GAAG;GAC1C,MAAM,MAAM,cAAc,QAAQ,MAAM,MAAM,EAAE,OAAO,EAAE;GACzD,QAAQ,MAAM,MAAM,iBAAiB,KAAK,CAAC,IAAI;EACjD;EACA,UAAU,OAAO;GAAE,GAAG;GAAG,cAAc;EAAQ,EAAE;EAEjD,IAAI;QACG,MAAM,CAAC,IAAI,MAAM,OAAO,QAAQ,OAAO,GAC1C,IAAI,MAAM,aAAa,QAAQ,GAAG,eAAe,IAAI,CAAC;EAAA;CAG5D,GACA;EAAC;EAAU;EAAgB,MAAM;CAAY,CAC/C;CAEA,MAAM,yBAAyB,aAC5B,YAAsC;EACrC,MAAM,OAAO,eAAe,SAAS,MAAM,gBAAgB;EAC3D,UAAU,OAAO;GAAE,GAAG;GAAG,kBAAkB;EAAK,EAAE;EAClD,2BAA2B,IAAI;CACjC,GACA;EAAC;EAAU;EAA0B,MAAM;CAAgB,CAC7D;CAEA,MAAM,0BAA0B,aAC7B,YAAuC;EACtC,MAAM,OAAO,eAAe,SAAS,CAAC,GAAG,MAAM,WAAW,CAAC;EAC3D,UAAU,OAAO;GAAE,GAAG;GAAG,aAAa;EAAK,EAAE;CAC/C,GACA,CAAC,UAAU,MAAM,WAAW,CAC9B;CAEA,MAAM,4BAA4B,aAC/B,YAAyC;EAKxC,MAAM,OAAO,eAAe,SAAS;GAHnC,MAAM,CAAC,GAAG,MAAM,cAAc,IAAI;GAClC,OAAO,CAAC,GAAG,MAAM,cAAc,KAAK;EAEK,CAAC;EAC5C,UAAU,OAAO;GACf,GAAG;GACH,eAAe;IAAE,MAAM,KAAK,QAAQ,CAAC;IAAG,OAAO,KAAK,SAAS,CAAC;GAAE;EAClE,EAAE;CACJ,GACA,CAAC,UAAU,MAAM,aAAa,CAChC;CAGA,MAAM,QAAQ,cAAoB;EAChC,MAAM;EACN,SAAS;EACT,WAAW,QAAQ,SAAS,GAAG;EAC/B,iBAAiB,gBAAgB;EACjC,OAAO;GACL,SAAS;GACT,kBAAkB,MAAM;GACxB,cAAc,MAAM;GACpB,aAAa;GACb,eAAe;GACf,cAAc;EAChB;EACA,iBAAiB;EACjB,sBAAsB;EACtB,0BAA0B;EAC1B,qBAAqB;EACrB,uBAAuB;EACvB,kBAAkB;EAClB,oBAAoB,kBAAkB;EACtC,yBAAyB,kBAAkB;EAC3C,sBAAsB;EACtB,eAAe;EACf,kBAAkB;EAClB,iBAAiB;CACnB,CAAC;CAGD,MAAM,iBAAiB,cAAc;EACnC,MAAM,SAAS,IAAI,IAAI,WAAW,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;EACvD,OAAO,MACJ,sBAAsB,CAAC,CACvB,KAAK,MAAM,OAAO,IAAI,EAAE,EAAE,CAAC,CAAC,CAC5B,OAAO,OAAO;CACnB,GAAG;EAAC;EAAY;EAAO,MAAM;EAAa,MAAM;CAAgB,CAAC;CAGjE,MAAM,SAAS,cAAc,KAAK,IAAI,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC;CAMjE,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,CAAC;CACtD,sBAAsB;EACpB,MAAM,OAAO,QAAQ;EACrB,MAAM,WAAW,mBAAmB;EACpC,IAAI,CAAC,MAAM;EACX,MAAM,UAAU,YAAoC;GAClD,IAAI,WAAW;GACf,IAAI,WAAW,MACb,KAAK,MAAM,SAAS,SAClB,WAAW,KAAK,IAAI,UAAU,MAAM,YAAY,KAAK;GAGzD,IAAI,YAAY,GAAG;IACjB,MAAM,gBAAgB,UAAU,eAAe;IAC/C,MAAM,YAAY,KAAK;IACvB,WAAW,gBAAgB,IAAI,gBAAgB;GACjD;GACA,IAAI,WAAW,GAAG,kBAAkB,QAAQ;EAC9C;EACA,OAAO;EACP,MAAM,WAAW,IAAI,gBAAgB,YAAY,OAAO,OAAO,CAAC;EAChE,SAAS,QAAQ,IAAI;EACrB,IAAI,UAAU,SAAS,QAAQ,QAAQ;EACvC,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,CAAC;CAIL,MAAM,mBAAmB,MAAM,SAAS,CAAC,CAAC;CAC1C,MAAM,cAAc,cAAsC;EACxD,MAAM,QAAgC,CAAC;EACvC,IAAI,YAAY,kBAAkB,SAAS,KAAK;EAChD,MAAM,aAAa,iBAAiB,oBAAoB;EACxD,MAAM,cAAc,iBAAiB,eAAe;EACpD,KAAK,MAAM,OAAO,gBAAgB;GAEhC,MAAM,WADQ,MAAM,UAAU,IAAI,EACb,CAAC,EAAE,QAAQ,KAAK,IAAI,SAAS;GAClD,MAAM,WAAW,eAAe,IAAI,KAChC,iBAAiB,KAAK,WAAW,WAAW,IAC5C;GACJ,MAAM,IAAI,MAAM;GAChB,aAAa;EACf;EACA,qBAAqB,OAAO,gBAAgB,iBAAiB,SAAS;EACtE,OAAO;CACT,GAAG;EAAC;EAAgB;EAAO;EAAkB,MAAM;EAAc;EAAgB;CAAa,CAAC;CAE/F,MAAM,oBAAoB,cAAc;EACtC,IAAI,QAAQ,kBAAkB,SAAS,KAAK;EAC5C,KAAK,MAAM,OAAO,gBAAgB,SAAS,YAAY,IAAI,OAAO;EAClE,OAAO;CACT,GAAG;EAAC;EAAgB;EAAa;CAAa,CAAC;CAE/C,MAAM,UAAU,cAA6B;EAC3C,MAAM,OAAwC,EAAE,kBAAkB,GAAG,kBAAkB,IAAI;EAC3F,KAAK,MAAM,OAAO,gBAChB,KAAK,SAAS,IAAI,GAAG,UAAU,YAAY,IAAI;EAEjD,OAAO;CACT,GAAG;EAAC;EAAgB;EAAa;CAAiB,CAAC;CAGnD,MAAM,gBAAgB,aACnB,SAAiC;EAChC,UAAU,OAAO;GAAE,GAAG;GAAG,WAAW;EAAK,EAAE;EAC3C,IAAI,mBAAmB;GACrB,MAAM,QAAQ,KAAK;GAEnB,kBAAkB,OADG,KAAK,QAAQ,MAAM,MAAM,IAAI,SAAS,CAAC,CAAC,CACzB,CAAC;EACvC;CACF,GACA;EAAC;EAAU;EAAmB;EAAM;CAAQ,CAC9C;CAEA,MAAM,iBAAiB,aACpB,KAAW,OAAc,UAA4B;EACpD,IAAI,kBAAkB,QAQpB,cAPa,cAAc;GACzB,SAAS,MAAM;GACf;GACA,MAAM;GACN,WAAW;IAAE,OAAO,MAAM;IAAU,MAAM,MAAM,WAAW,MAAM;GAAQ;GACzE,WAAW;EACb,CACiB,CAAC;EAEpB,aAAa,KAAK,OAAO,KAAK;CAChC,GACA;EAAC;EAAe,MAAM;EAAW;EAAQ;EAAe;CAAU,CACpE;CAEA,MAAM,kBAAkB,kBAAkB;EAExC,cADuB,OAAO,SAAS,KAAK,OAAO,OAAO,OAAO,MAAM,UAAU,YAAY,IAAI,EAAE,CAAC,IAG9F;GAAE,6BAAa,IAAI,IAAI;GAAG,UAAU;EAAK,IACzC;GAAE,aAAa,IAAI,IAAI,MAAM;GAAG,UAAU;EAAK,CACrD;CACF,GAAG;EAAC;EAAQ,MAAM,UAAU;EAAa;CAAa,CAAC;CAGvD,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,KAAK;CAC9D,MAAM,kBAAkB,kBAAkB;EACxC,oBAAoB,IAAI;CAC1B,GAAG,CAAC,CAAC;CAGL,MAAM,qBAAqB,OAAuB,IAAI;CACtD,MAAM,kBAAkB,OAAuB,IAAI;CACnD,MAAM,kBAAkB,OAAuB,IAAI;CACnD,MAAM,cAAc,OAAuB,IAAI;CAC/C,MAAM,UAAU,OAAuB,IAAI;CAC3C,MAAM,mBAAmB,aAAa,OAAgB,GAAG,sBAAsB,CAAC,CAAC,QAAQ,CAAC,CAAC;CAE3F,MAAM,iBAAiB,eAAe;EACpC,OAAO,KAAK;EACZ,wBAAwB,mBAAmB;EAC3C,oBAAoB;EACpB;EACA,aAAa,UAAU;GACrB,MAAM,MAAM,KAAK;GACjB,OAAO,OAAO,OAAO,OAAO,SAAS,GAAG,CAAC,IAAI;EAC/C;EACA,GAAI,qBAAqB,EAAE,gBAAgB,iBAAiB,IAAI,CAAC;CACnE,CAAC;CAGD,sBAAsB;EACpB,MAAM,SAAS,QAAQ;EACvB,MAAM,WAAW,gBAAgB;EACjC,MAAM,SAAS,mBAAmB;EAClC,MAAM,SAAS,YAAY;EAC3B,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,UAAU,CAAC,QAAQ;EAEhD,MAAM,mBAAmB;GACvB,MAAM,aAAa,SAAS,sBAAsB;GAClD,MAAM,WAAW,OAAO,sBAAsB;GAC9C,MAAM,UAAU,KAAK,IAAI,GAAG,WAAW,SAAS,SAAS,GAAG;GAC5D,OAAO,MAAM,YAAY,8BAA8B,GAAG,QAAQ,GAAG;EACvE;EACA,WAAW;EACX,OAAO,iBAAiB,UAAU,UAAU;EAC5C,OAAO,iBAAiB,UAAU,YAAY,IAAI;EAClD,OAAO,iBAAiB,UAAU,UAAU;EAC5C,MAAM,WAAW,IAAI,eAAe,UAAU;EAC9C,SAAS,QAAQ,MAAM;EACvB,SAAS,QAAQ,QAAQ;EACzB,SAAS,QAAQ,MAAM;EACvB,aAAa;GACX,OAAO,oBAAoB,UAAU,UAAU;GAC/C,OAAO,oBAAoB,UAAU,YAAY,IAAI;GACrD,OAAO,oBAAoB,UAAU,UAAU;GAC/C,SAAS,WAAW;EACtB;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,mBAAmB,kBAAkB;EACzC,MAAM,OAAO,mBAAmB;EAChC,MAAM,SAAS,gBAAgB;EAC/B,IAAI,QAAQ,QAAQ,OAAO,aAAa,KAAK;CAC/C,GAAG,CAAC,CAAC;CAGL,MAAM,aAA2C,eACxC;EACL;EACA;EACA,SAAS;EACT;EACA;EACA,kBAAkB,MAAM,UAAU,YAAY;EAC9C;EACA,WAAW;CACb,IACA;EAAC;EAAO;EAAU;EAAY;EAAgB;EAAe;EAAS;CAAe,CACvF;CACA,MAAM,YAAyC,eACtC;EACL;EACA;EACA,iBAAiB,KAAK;EACtB,kBAAkB,MAAM,UAAU,YAAY;EAC9C;EACA;CACF,IACA;EAAC;EAAO;EAAe,KAAK;EAAQ;EAAgB;CAAO,CAC7D;CAEA,MAAM,cAAc,OAAO,SAAS,KAAK,OAAO,OAAO,OAAO,MAAM,UAAU,YAAY,IAAI,EAAE,CAAC;CACjG,MAAM,eAAe,CAAC,eAAe,OAAO,MAAM,OAAO,MAAM,UAAU,YAAY,IAAI,EAAE,CAAC;CAQ5F,MAAM,qBACJ,cAAc,mBAAmB,cAAc,CAAC,aAAa,8BAA8B,KAAA;CAE7F,MAAM,wBACJ,mBAAmB,eAAe,cAAc,sBAAsB,QAClE,qBACA,KAAA;CAGN,MAAM,UAAmC,cAErC,MACG,gBAAgB,CAAC,CAAC,EAAE,EAAE,QACtB,QAAQ,MAAM,eAAe,MAAM,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,GACzE,CAAC,OAAO,cAAc,CACxB;CACA,MAAM,gBAAgB,cAAc;EAClC,MAAM,oBAAI,IAAI,IAAmC;EACjD,KAAK,MAAM,KAAK,SAAS,EAAE,IAAI,EAAE,OAAO,IAAI,CAAC;EAC7C,OAAO;CACT,GAAG,CAAC,OAAO,CAAC;CAEZ,MAAM,YAAY,cAAc,sBAAsB;CAEtD,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,sBAAD;EACE,MAAM;EACN,cAAc;EACR;EACN,SAAS;EACO;EACD;CAChB,CAAA,GACD,qBAAC,OAAD;EACE,KAAK;EACL,WAAW,GACT,kGACA,aAAa,mBAAmB,kBAChC,aAAa,mBACb,SACF;EACA,OAAO,sBAAsB,OAAO;GAAE,GAAG;GAAS,WAAW;EAAmB,IAAI;EACpF,MAAK;EACL,iBAAe,iBAAiB,KAAK;EACrC,iBAAe,eAAe;YAXhC;GAaE,qBAAC,OAAD;IACE,KAAK;IACL,WAAU;IACV,OAAO,EAAE,KAAK,cAAc,sBAAsB,OAAO,IAAI,oCAAoC;cAHnG,CAKG,YAAY,SACX,oBAAC,OAAD;KAAK,WAAU;eACZ,UACG,QAAQ,UAAU,IAElB,oBAAC,iBAAD;MACE,KAAK;MACL,OAAO,OAAO,iBAAiB,aAAa,aAAa,UAAU,IAAI;KACxE,CAAA;IAEF,CAAA,GAGP,qBAAC,OAAD;KAAK,WAAU;eAAf,CACG,gBACC,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,OAAD,EAAK,WAAU,yDAA0D,CAAA;KACtE,CAAA,GAEP,oBAAC,OAAD;MACE,KAAK;MACL,WAAU;gBAEV,qBAAC,OAAD;OACE,WAAU;OACV,OAAO;QAAE,QAAQ;QAAc,UAAU;OAAkB;OAC3D,MAAK;iBAHP,CAKG,kBAAkB,UACjB,oBAAC,OAAD;QACE,WAAU;QACV,OAAO,EAAE,OAAO,GAAG;kBAElB,kBAAkB,cACjB,oBAAC,mBAAD;SACE,SAAS;SACT,eAAe;SACf,UAAU;SACV,WAAU;SACV,OAAM;QACP,CAAA;OAEA,CAAA,GAEN,eAAe,KAAK,QAAQ;QAC3B,MAAM,SAAS,cAAc,IAAI,IAAI,EAAE;QACvC,IAAI,CAAC,QAAQ,OAAO;QACpB,OAAO,oBAAC,YAAD;SAAiC;SAAa;SAAgB;QAAY,GAAzD,IAAI,EAAqD;OACnF,CAAC,CACE;;KACF,CAAA,CACF;MACF;;GAEL,oBAAC,OAAD;IACE,KAAK;IACL,WAAW,GACX,4DACA,YAAY,mBAAmB,aAC/B,6DACA,+CACA,+FACA,yDACF;IACE,UAAU;cAEV,qBAAC,OAAD;KACE,KAAK;KACL,4BAAyB;KACzB,WAAU;KACV,OAAO;MACL,UAAU;MACV,UAAU;KACZ;eAPF;MASG,aACC,oBAAC,OAAD;OAAK,OAAO,EAAE,UAAU,kBAAkB;iBACvC,gBAAgB,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,MACjD,oBAAC,aAAD;QAEE,SAAS;QACT,QAAQ;QACR,cAAc,kBAAkB;OACjC,GAJM,CAIN,CACF;MACE,CAAA;MAGN,CAAC,aAAa,KAAK,WAAW,KAC7B,oBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,UAAU,kBAAkB;iBAEpC,cAAc,QAAQ;MACpB,CAAA;MAGN,CAAC,aAAa,KAAK,SAAS,KAC3B,oBAAC,OAAD;OACE,OAAO;QACL,QAAQ,eAAe,aAAa;QACpC,OAAO;QACP,UAAU;QACV,UAAU;OACZ;iBAEC,eAAe,gBAAgB,CAAC,CAAC,KAAK,eAA4B;QACjE,MAAM,MAAM,KAAK,WAAW,UAAU,SACtC,mCAAmC,WAAW,MAAM,6BAA6B,KAAK,OAAO,EAC/F;QACE,MAAM,QAAQ,SAAS,GAAG;QAC1B,MAAM,aAAa,MAAM,UAAU,YAAY,IAAI,KAAK;QACxD,MAAM,WAAW,WAAW,QAAQ,MAAM;QAC1C,OACE,qBAAC,OAAD;SAEE,KAAK,qBAAqB,eAAe,iBAAiB,KAAA;SAC1D,cAAY,WAAW;SACvB,WAAW,GACX,+BACA,yDACA,iCACA,aACI,qGACA,WACE,8GACA,gEACL,kBAAkB,UAAU,eAAe,gBAC9C;SACE,OAAO;UACL,GAAI,qBACA,EAAE,WAAW,mBAAmB,IAChC,EAAE,QAAQ,eAAe;UAC7B,WAAW,cAAc,WAAW,MAAM;SAC5C;SACA,UAAU,MAAM;UAAE,IAAI,CAAC,qBAAqB,CAAC,GAAG,eAAe,KAAK,OAAO,CAAC;SAAG;SAC/E,gBAAgB,MAAM;UAAE,IAAI,CAAC,qBAAqB,CAAC,GAAG,mBAAmB,KAAK,OAAO,CAAC;SAAG;SACzF,MAAK;SACL,iBAAe,WAAW,QAAQ;SAClC,iBAAe;SACf,eAAa;SACb,cAAY,aAAa,aAAa,KAAA;mBA3BxC,CA6BG,kBAAkB,UACjB,oBAAC,OAAD;UACE,WAAU;UACV,OAAO,EAAE,OAAO,GAAG;oBAEnB,oBAAC,mBAAD;WACE,SAAS;WACT,WAAW,UAAU,eAAe,KAAK,OAAO,KAAK;WACrD,WAAW,cAAc;UAC1B,CAAA;SACE,CAAA,GAEN,eAAe,KAAK,QACnB,oBAAC,UAAD;UAEO;UACA;UACE;UACP,UAAU,WAAW;UACT;UACZ,aAAa,MAAM;SACpB,GAPM,IAAI,EAOV,CACF,CACE;WAnDE,KAmDF;OAET,CAAC;MACE,CAAA;MAGN,mBAAmB,cAAc,WAAW,CAAC,aAC5C,oBAAC,wBAAD;OACE,aAAa,cAAc;OAC3B,WAAW;OACX,SAAS;OACA;MACV,CAAA;KAEA;;GACF,CAAA;GAEJ,WAAW,SACV,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,SAAS,OAAO,SAAS,IAAI,oBAAC,eAAD;KAAe,KAAK;KAAW,YAAY;KAA0B;IAAW,CAAA,GAC7G,gBAAgB,OAAO,gBAAgB,aAAa,YAAY,SAAS,IAAI,YAC3E;;EAEJ;GACL,EAAA,CAAA;AAEN"}
@@ -112,6 +112,24 @@ function DataGridHarness(props) {
112
112
  })
113
113
  });
114
114
  }
115
+ function PaginatedDataGridHarness() {
116
+ const [state, setState] = useState(() => createDefaultDataGridState(columns));
117
+ return /* @__PURE__ */ jsx("div", {
118
+ style: { height: 400 },
119
+ children: /* @__PURE__ */ jsx(DataGrid, {
120
+ columns,
121
+ rows: [{
122
+ id: "row-1",
123
+ name: "Row 1"
124
+ }],
125
+ getRowId: (row) => row.id,
126
+ state,
127
+ onChange: setState,
128
+ paginationMode: "paginated",
129
+ fillHeight: false
130
+ })
131
+ });
132
+ }
115
133
  function InteractiveDataGridHarness(props) {
116
134
  const [state, setState] = useState(() => createDefaultDataGridState(columns));
117
135
  return /* @__PURE__ */ jsx(DataGrid, {
@@ -192,12 +210,27 @@ describe("DataGrid infinite scroll observer", () => {
192
210
  const scrollContainer = grid?.children.item(1);
193
211
  expect(intersectionObserverRecords.at(-1)?.options?.root).toBe(scrollContainer);
194
212
  });
195
- it("falls back to the viewport when the page owns vertical scrolling", async () => {
196
- render(/* @__PURE__ */ jsx(DataGridHarness, { fillHeight: false }));
213
+ it("bounds an unbounded infinite grid and observes against its own scroll container", async () => {
214
+ const { container } = render(/* @__PURE__ */ jsx(DataGridHarness, { fillHeight: false }));
197
215
  await waitFor(() => {
198
216
  expect(intersectionObserverRecords.length).toBeGreaterThan(0);
199
217
  });
200
- expect(intersectionObserverRecords.at(-1)?.options?.root ?? null).toBeNull();
218
+ const grid = container.querySelector("[role=\"grid\"]");
219
+ expect(grid).not.toBeNull();
220
+ const scrollContainer = grid?.children.item(1);
221
+ expect(intersectionObserverRecords.at(-1)?.options?.root).toBe(scrollContainer);
222
+ });
223
+ it("applies a default maxHeight to an otherwise-unbounded infinite grid", () => {
224
+ const { container } = render(/* @__PURE__ */ jsx(DataGridHarness, { fillHeight: false }));
225
+ const grid = container.querySelector("[role=\"grid\"]");
226
+ expect(grid).not.toBeNull();
227
+ expect(grid?.style.maxHeight).toBe("calc(100dvh - 16rem)");
228
+ });
229
+ it("does not force a maxHeight onto a paginated grid", () => {
230
+ const { container } = render(/* @__PURE__ */ jsx(PaginatedDataGridHarness, {}));
231
+ const grid = container.querySelector("[role=\"grid\"]");
232
+ expect(grid).not.toBeNull();
233
+ expect(grid?.style.maxHeight).toBe("");
201
234
  });
202
235
  });
203
236
  function InfiniteScrollLoadMoreHarness({ onFetch }) {
@@ -1 +1 @@
1
- {"version":3,"file":"data-grid.test.js","names":[],"sources":["../../../../src/components/data-grid/data-grid.test.tsx"],"sourcesContent":["// @vitest-environment jsdom\n\nimport { act, cleanup, fireEvent, render, waitFor } from \"@testing-library/react\";\nimport { useMemo, useState } from \"react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n createDefaultDataGridState,\n DataGrid,\n isDataGridInteractiveRowClickTarget,\n useDataSource,\n type DataGridColumnDef,\n type DataGridDataSource,\n type DataGridProps,\n} from \"./index\";\n\ntype Row = {\n id: string,\n name: string,\n};\n\nconst columns: DataGridColumnDef<Row>[] = [\n {\n id: \"name\",\n header: \"Name\",\n accessor: (row) => row.name,\n width: 160,\n minWidth: 80,\n sortable: true,\n type: \"string\",\n },\n];\n\nconst wideColumns: DataGridColumnDef<Row>[] = [\n {\n id: \"name\",\n header: \"Name\",\n accessor: (row) => row.name,\n width: 320,\n minWidth: 80,\n type: \"string\",\n },\n {\n id: \"email\",\n header: \"Email\",\n accessor: (row) => `${row.name.toLowerCase().replaceAll(\" \", \".\")}@example.com`,\n width: 420,\n minWidth: 80,\n type: \"string\",\n },\n];\n\ntype ObserverRecord = {\n options?: IntersectionObserverInit,\n};\n\nlet intersectionObserverRecords: ObserverRecord[] = [];\nlet intersectionObserverInstances: MockIntersectionObserver[] = [];\n\nclass MockIntersectionObserver implements IntersectionObserver {\n readonly root: Element | Document | null;\n readonly rootMargin: string;\n readonly scrollMargin: string;\n readonly thresholds: ReadonlyArray<number>;\n private readonly callback: IntersectionObserverCallback;\n private readonly record: ObserverRecord;\n\n constructor(\n callback: IntersectionObserverCallback,\n options?: IntersectionObserverInit,\n ) {\n this.callback = callback;\n this.root = options?.root ?? null;\n this.rootMargin = options?.rootMargin ?? \"\";\n this.scrollMargin = \"\";\n this.thresholds = Array.isArray(options?.threshold)\n ? options.threshold\n : [options?.threshold ?? 0];\n this.record = { options };\n intersectionObserverRecords.push(this.record);\n intersectionObserverInstances.push(this);\n }\n\n disconnect() {}\n observe() {}\n takeRecords(): IntersectionObserverEntry[] {\n return [];\n }\n unobserve() {}\n\n trigger(entry: Partial<IntersectionObserverEntry> = {}) {\n this.callback(\n [\n {\n boundingClientRect: {} as DOMRectReadOnly,\n intersectionRatio: 1,\n intersectionRect: {} as DOMRectReadOnly,\n isIntersecting: true,\n rootBounds: null,\n target: document.createElement(\"div\"),\n time: 0,\n ...entry,\n },\n ],\n this,\n );\n }\n}\n\nclass MockResizeObserver implements ResizeObserver {\n private readonly callback: ResizeObserverCallback;\n\n constructor(callback: ResizeObserverCallback) {\n this.callback = callback;\n }\n\n disconnect() {}\n observe(target: Element) {\n const el = target instanceof HTMLElement ? target : null;\n const parentWidth = el?.parentElement instanceof HTMLElement ? el.parentElement.clientWidth : 0;\n const width = (el?.clientWidth ?? 0) > 0 ? (el?.clientWidth ?? 320) : parentWidth > 0 ? parentWidth : 320;\n const height = (el?.clientHeight ?? 0) > 0 ? (el?.clientHeight ?? 400) : 400;\n this.callback(\n [\n {\n target,\n contentRect: {\n x: 0,\n y: 0,\n width,\n height,\n top: 0,\n left: 0,\n right: width,\n bottom: height,\n toJSON() {\n return this;\n },\n } as DOMRectReadOnly,\n borderBoxSize: [],\n contentBoxSize: [],\n devicePixelContentBoxSize: [],\n },\n ],\n this,\n );\n }\n unobserve() {}\n}\n\nfunction DataGridHarness(props: { fillHeight?: boolean }) {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n\n return (\n <div style={{ height: 400 }}>\n <DataGrid<Row>\n columns={columns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n paginationMode=\"infinite\"\n hasMore\n fillHeight={props.fillHeight}\n />\n </div>\n );\n}\n\nfunction InteractiveDataGridHarness(props: {\n onSortChange?: DataGridProps<Row>[\"onSortChange\"],\n onSelectionChange?: DataGridProps<Row>[\"onSelectionChange\"],\n}) {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n\n return (\n <DataGrid<Row>\n columns={columns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n selectionMode=\"multiple\"\n onSortChange={props.onSortChange}\n onSelectionChange={props.onSelectionChange}\n />\n );\n}\n\nfunction WideDataGridHarness() {\n const [state, setState] = useState(() => createDefaultDataGridState(wideColumns));\n\n return (\n <div style={{ width: 320 }}>\n <DataGrid<Row>\n columns={wideColumns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n />\n </div>\n );\n}\n\ndescribe(\"DataGrid infinite scroll observer\", () => {\n beforeEach(() => {\n intersectionObserverRecords = [];\n\n vi.stubGlobal(\"IntersectionObserver\", MockIntersectionObserver);\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n it(\"observes against the grid body when the grid owns vertical scrolling\", async () => {\n const { container } = render(<DataGridHarness fillHeight />);\n\n await waitFor(() => {\n expect(intersectionObserverRecords.length).toBeGreaterThan(0);\n });\n\n const grid = container.querySelector('[role=\"grid\"]');\n expect(grid).not.toBeNull();\n const scrollContainer = grid?.children.item(1);\n\n expect(intersectionObserverRecords.at(-1)?.options?.root).toBe(scrollContainer);\n });\n\n it(\"falls back to the viewport when the page owns vertical scrolling\", async () => {\n render(<DataGridHarness fillHeight={false} />);\n\n await waitFor(() => {\n expect(intersectionObserverRecords.length).toBeGreaterThan(0);\n });\n\n expect(intersectionObserverRecords.at(-1)?.options?.root ?? null).toBeNull();\n });\n});\n\n// Drives a real `useDataSource` infinite-scroll grid whose data source\n// always reports `hasMore: true`, mirroring a project with a long\n// transaction / customer history (e.g. the transactions table and customers\n// tab). Used to prove the sentinel doesn't thrash its IntersectionObserver.\nfunction InfiniteScrollLoadMoreHarness({ onFetch }: { onFetch: () => void }) {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n const dataSource = useMemo<DataGridDataSource<Row>>(\n () => {\n let page = 0;\n return async function* () {\n onFetch();\n const current = page++;\n yield {\n rows: [{ id: `row-${current}`, name: `Row ${current}` }],\n hasMore: true,\n nextCursor: `cursor-${current}`,\n };\n };\n },\n [onFetch],\n );\n\n const gridData = useDataSource<Row>({\n dataSource,\n columns,\n getRowId: (row) => row.id,\n sorting: state.sorting,\n quickSearch: state.quickSearch,\n pagination: state.pagination,\n paginationMode: \"infinite\",\n });\n\n return (\n <div style={{ height: 400 }}>\n <DataGrid<Row>\n columns={columns}\n rows={gridData.rows}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n paginationMode=\"infinite\"\n hasMore={gridData.hasMore}\n isLoading={gridData.isLoading}\n isLoadingMore={gridData.isLoadingMore}\n onLoadMore={gridData.loadMore}\n />\n </div>\n );\n}\n\ndescribe(\"DataGrid infinite scroll observer stability\", () => {\n beforeEach(() => {\n intersectionObserverRecords = [];\n intersectionObserverInstances = [];\n\n vi.stubGlobal(\"IntersectionObserver\", MockIntersectionObserver);\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n // Regression: the sentinel used to re-create its IntersectionObserver every\n // time the `onLoadMore` callback changed identity (which happens on every\n // `isLoadingMore` / `hasMore` toggle). A freshly-created observer re-reports\n // the sentinel's current intersection state, so a sentinel that stays in\n // view fires `onLoadMore` again after every page — auto-loading the entire\n // history back-to-back and OOM-crashing the tab (\"Aw snap\") on large\n // datasets. The observer must stay stable across load-more cycles.\n it(\"does not re-create the observer on load-more cycles\", async () => {\n const onFetch = vi.fn();\n render(<InfiniteScrollLoadMoreHarness onFetch={onFetch} />);\n\n // Initial page load, after which the sentinel (and its observer) mounts.\n await waitFor(() => expect(onFetch).toHaveBeenCalledTimes(1));\n await waitFor(() => expect(intersectionObserverInstances.length).toBeGreaterThan(0));\n\n const observersBeforeLoadMore = intersectionObserverInstances.length;\n\n // Simulate the sentinel scrolling into view exactly once.\n await act(async () => {\n intersectionObserverInstances.at(-1)?.trigger();\n await Promise.resolve();\n });\n\n await waitFor(() => expect(onFetch).toHaveBeenCalledTimes(2));\n\n // A single scroll-in must trigger a single fetch, without spawning new\n // observers — otherwise each new observer would re-fire and runaway.\n expect(intersectionObserverInstances.length).toBe(observersBeforeLoadMore);\n });\n});\n\ndescribe(\"DataGrid controlled callbacks\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n it(\"fires onSortChange from the current controlled sort state\", () => {\n const onSortChange = vi.fn();\n const { getByRole } = render(<InteractiveDataGridHarness onSortChange={onSortChange} />);\n\n fireEvent.click(getByRole(\"columnheader\", { name: /name/i }));\n\n expect(onSortChange).toHaveBeenCalledTimes(1);\n expect(onSortChange).toHaveBeenCalledWith([{ columnId: \"name\", direction: \"asc\" }]);\n });\n\n it(\"fires onSelectionChange when selecting all rows\", () => {\n const onSelectionChange = vi.fn();\n const { getByRole } = render(<InteractiveDataGridHarness onSelectionChange={onSelectionChange} />);\n\n fireEvent.click(getByRole(\"checkbox\", { name: /select all rows/i }));\n\n expect(onSelectionChange).toHaveBeenCalledTimes(1);\n const [selectedIds, selectedRows] = onSelectionChange.mock.calls[0];\n expect([...selectedIds]).toEqual([\"row-1\"]);\n expect(selectedRows).toEqual([{ id: \"row-1\", name: \"Row 1\" }]);\n });\n\n it(\"identifies nested interactive controls as row-click blockers\", () => {\n const cell = document.createElement(\"div\");\n const button = document.createElement(\"button\");\n const label = document.createElement(\"span\");\n label.textContent = \"Open menu\";\n button.append(label);\n cell.append(button);\n\n expect(isDataGridInteractiveRowClickTarget(label.firstChild)).toBe(true);\n expect(isDataGridInteractiveRowClickTarget(cell)).toBe(false);\n });\n});\n\ndescribe(\"DataGrid horizontal scrolling\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n Object.defineProperty(HTMLElement.prototype, \"clientWidth\", {\n configurable: true,\n get() {\n return 320;\n },\n });\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n it(\"sizes the sticky clipping layer to the full row width\", () => {\n const { container } = render(<WideDataGridHarness />);\n\n const rowsClip = container.querySelector(\"[data-data-grid-rows-clip]\");\n\n expect(rowsClip).toBeInstanceOf(HTMLElement);\n expect((rowsClip as HTMLElement).style.minWidth).toBe(\"740px\");\n });\n\n it(\"lets the columns popover escape the sticky toolbar bounds\", () => {\n const { container, getByTitle } = render(<WideDataGridHarness />);\n\n fireEvent.click(getByTitle(\"Columns\"));\n\n const stickyChrome = container.querySelector('[role=\"grid\"]')?.firstElementChild;\n expect(stickyChrome).toBeInstanceOf(HTMLElement);\n expect((stickyChrome as HTMLElement).className).toContain(\"overflow-visible\");\n expect(container.textContent).toContain(\"Email\");\n });\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"data-grid.test.js","names":[],"sources":["../../../../src/components/data-grid/data-grid.test.tsx"],"sourcesContent":["// @vitest-environment jsdom\n\nimport { act, cleanup, fireEvent, render, waitFor } from \"@testing-library/react\";\nimport { useMemo, useState } from \"react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n createDefaultDataGridState,\n DataGrid,\n isDataGridInteractiveRowClickTarget,\n useDataSource,\n type DataGridColumnDef,\n type DataGridDataSource,\n type DataGridProps,\n} from \"./index\";\n\ntype Row = {\n id: string,\n name: string,\n};\n\nconst columns: DataGridColumnDef<Row>[] = [\n {\n id: \"name\",\n header: \"Name\",\n accessor: (row) => row.name,\n width: 160,\n minWidth: 80,\n sortable: true,\n type: \"string\",\n },\n];\n\nconst wideColumns: DataGridColumnDef<Row>[] = [\n {\n id: \"name\",\n header: \"Name\",\n accessor: (row) => row.name,\n width: 320,\n minWidth: 80,\n type: \"string\",\n },\n {\n id: \"email\",\n header: \"Email\",\n accessor: (row) => `${row.name.toLowerCase().replaceAll(\" \", \".\")}@example.com`,\n width: 420,\n minWidth: 80,\n type: \"string\",\n },\n];\n\ntype ObserverRecord = {\n options?: IntersectionObserverInit,\n};\n\nlet intersectionObserverRecords: ObserverRecord[] = [];\nlet intersectionObserverInstances: MockIntersectionObserver[] = [];\n\nclass MockIntersectionObserver implements IntersectionObserver {\n readonly root: Element | Document | null;\n readonly rootMargin: string;\n readonly scrollMargin: string;\n readonly thresholds: ReadonlyArray<number>;\n private readonly callback: IntersectionObserverCallback;\n private readonly record: ObserverRecord;\n\n constructor(\n callback: IntersectionObserverCallback,\n options?: IntersectionObserverInit,\n ) {\n this.callback = callback;\n this.root = options?.root ?? null;\n this.rootMargin = options?.rootMargin ?? \"\";\n this.scrollMargin = \"\";\n this.thresholds = Array.isArray(options?.threshold)\n ? options.threshold\n : [options?.threshold ?? 0];\n this.record = { options };\n intersectionObserverRecords.push(this.record);\n intersectionObserverInstances.push(this);\n }\n\n disconnect() {}\n observe() {}\n takeRecords(): IntersectionObserverEntry[] {\n return [];\n }\n unobserve() {}\n\n trigger(entry: Partial<IntersectionObserverEntry> = {}) {\n this.callback(\n [\n {\n boundingClientRect: {} as DOMRectReadOnly,\n intersectionRatio: 1,\n intersectionRect: {} as DOMRectReadOnly,\n isIntersecting: true,\n rootBounds: null,\n target: document.createElement(\"div\"),\n time: 0,\n ...entry,\n },\n ],\n this,\n );\n }\n}\n\nclass MockResizeObserver implements ResizeObserver {\n private readonly callback: ResizeObserverCallback;\n\n constructor(callback: ResizeObserverCallback) {\n this.callback = callback;\n }\n\n disconnect() {}\n observe(target: Element) {\n const el = target instanceof HTMLElement ? target : null;\n const parentWidth = el?.parentElement instanceof HTMLElement ? el.parentElement.clientWidth : 0;\n const width = (el?.clientWidth ?? 0) > 0 ? (el?.clientWidth ?? 320) : parentWidth > 0 ? parentWidth : 320;\n const height = (el?.clientHeight ?? 0) > 0 ? (el?.clientHeight ?? 400) : 400;\n this.callback(\n [\n {\n target,\n contentRect: {\n x: 0,\n y: 0,\n width,\n height,\n top: 0,\n left: 0,\n right: width,\n bottom: height,\n toJSON() {\n return this;\n },\n } as DOMRectReadOnly,\n borderBoxSize: [],\n contentBoxSize: [],\n devicePixelContentBoxSize: [],\n },\n ],\n this,\n );\n }\n unobserve() {}\n}\n\nfunction DataGridHarness(props: { fillHeight?: boolean }) {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n\n return (\n <div style={{ height: 400 }}>\n <DataGrid<Row>\n columns={columns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n paginationMode=\"infinite\"\n hasMore\n fillHeight={props.fillHeight}\n />\n </div>\n );\n}\n\nfunction PaginatedDataGridHarness() {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n\n return (\n <div style={{ height: 400 }}>\n <DataGrid<Row>\n columns={columns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n paginationMode=\"paginated\"\n fillHeight={false}\n />\n </div>\n );\n}\n\nfunction InteractiveDataGridHarness(props: {\n onSortChange?: DataGridProps<Row>[\"onSortChange\"],\n onSelectionChange?: DataGridProps<Row>[\"onSelectionChange\"],\n}) {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n\n return (\n <DataGrid<Row>\n columns={columns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n selectionMode=\"multiple\"\n onSortChange={props.onSortChange}\n onSelectionChange={props.onSelectionChange}\n />\n );\n}\n\nfunction WideDataGridHarness() {\n const [state, setState] = useState(() => createDefaultDataGridState(wideColumns));\n\n return (\n <div style={{ width: 320 }}>\n <DataGrid<Row>\n columns={wideColumns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n />\n </div>\n );\n}\n\ndescribe(\"DataGrid infinite scroll observer\", () => {\n beforeEach(() => {\n intersectionObserverRecords = [];\n\n vi.stubGlobal(\"IntersectionObserver\", MockIntersectionObserver);\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n it(\"observes against the grid body when the grid owns vertical scrolling\", async () => {\n const { container } = render(<DataGridHarness fillHeight />);\n\n await waitFor(() => {\n expect(intersectionObserverRecords.length).toBeGreaterThan(0);\n });\n\n const grid = container.querySelector('[role=\"grid\"]');\n expect(grid).not.toBeNull();\n const scrollContainer = grid?.children.item(1);\n\n expect(intersectionObserverRecords.at(-1)?.options?.root).toBe(scrollContainer);\n });\n\n // Regression: an infinite grid left unbounded (`fillHeight={false}`, no `maxHeight`) used to\n // grow its scroll container to fit every loaded row, which defeats virtualization (the\n // virtualizer measures the container as fully visible and mounts every row) and OOMs the tab on\n // large datasets. Such grids now fall back to a default `maxHeight`, so the grid owns its own\n // bounded scroll container and observes against it rather than the viewport.\n it(\"bounds an unbounded infinite grid and observes against its own scroll container\", async () => {\n const { container } = render(<DataGridHarness fillHeight={false} />);\n\n await waitFor(() => {\n expect(intersectionObserverRecords.length).toBeGreaterThan(0);\n });\n\n const grid = container.querySelector('[role=\"grid\"]');\n expect(grid).not.toBeNull();\n const scrollContainer = grid?.children.item(1);\n\n expect(intersectionObserverRecords.at(-1)?.options?.root).toBe(scrollContainer);\n });\n\n it(\"applies a default maxHeight to an otherwise-unbounded infinite grid\", () => {\n const { container } = render(<DataGridHarness fillHeight={false} />);\n\n const grid = container.querySelector<HTMLElement>('[role=\"grid\"]');\n expect(grid).not.toBeNull();\n expect(grid?.style.maxHeight).toBe(\"calc(100dvh - 16rem)\");\n });\n\n it(\"does not force a maxHeight onto a paginated grid\", () => {\n const { container } = render(<PaginatedDataGridHarness />);\n\n const grid = container.querySelector<HTMLElement>('[role=\"grid\"]');\n expect(grid).not.toBeNull();\n expect(grid?.style.maxHeight).toBe(\"\");\n });\n});\n\n// Drives a real `useDataSource` infinite-scroll grid whose data source\n// always reports `hasMore: true`, mirroring a project with a long\n// transaction / customer history (e.g. the transactions table and customers\n// tab). Used to prove the sentinel doesn't thrash its IntersectionObserver.\nfunction InfiniteScrollLoadMoreHarness({ onFetch }: { onFetch: () => void }) {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n const dataSource = useMemo<DataGridDataSource<Row>>(\n () => {\n let page = 0;\n return async function* () {\n onFetch();\n const current = page++;\n yield {\n rows: [{ id: `row-${current}`, name: `Row ${current}` }],\n hasMore: true,\n nextCursor: `cursor-${current}`,\n };\n };\n },\n [onFetch],\n );\n\n const gridData = useDataSource<Row>({\n dataSource,\n columns,\n getRowId: (row) => row.id,\n sorting: state.sorting,\n quickSearch: state.quickSearch,\n pagination: state.pagination,\n paginationMode: \"infinite\",\n });\n\n return (\n <div style={{ height: 400 }}>\n <DataGrid<Row>\n columns={columns}\n rows={gridData.rows}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n paginationMode=\"infinite\"\n hasMore={gridData.hasMore}\n isLoading={gridData.isLoading}\n isLoadingMore={gridData.isLoadingMore}\n onLoadMore={gridData.loadMore}\n />\n </div>\n );\n}\n\ndescribe(\"DataGrid infinite scroll observer stability\", () => {\n beforeEach(() => {\n intersectionObserverRecords = [];\n intersectionObserverInstances = [];\n\n vi.stubGlobal(\"IntersectionObserver\", MockIntersectionObserver);\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n // Regression: the sentinel used to re-create its IntersectionObserver every\n // time the `onLoadMore` callback changed identity (which happens on every\n // `isLoadingMore` / `hasMore` toggle). A freshly-created observer re-reports\n // the sentinel's current intersection state, so a sentinel that stays in\n // view fires `onLoadMore` again after every page — auto-loading the entire\n // history back-to-back and OOM-crashing the tab (\"Aw snap\") on large\n // datasets. The observer must stay stable across load-more cycles.\n it(\"does not re-create the observer on load-more cycles\", async () => {\n const onFetch = vi.fn();\n render(<InfiniteScrollLoadMoreHarness onFetch={onFetch} />);\n\n // Initial page load, after which the sentinel (and its observer) mounts.\n await waitFor(() => expect(onFetch).toHaveBeenCalledTimes(1));\n await waitFor(() => expect(intersectionObserverInstances.length).toBeGreaterThan(0));\n\n const observersBeforeLoadMore = intersectionObserverInstances.length;\n\n // Simulate the sentinel scrolling into view exactly once.\n await act(async () => {\n intersectionObserverInstances.at(-1)?.trigger();\n await Promise.resolve();\n });\n\n await waitFor(() => expect(onFetch).toHaveBeenCalledTimes(2));\n\n // A single scroll-in must trigger a single fetch, without spawning new\n // observers — otherwise each new observer would re-fire and runaway.\n expect(intersectionObserverInstances.length).toBe(observersBeforeLoadMore);\n });\n});\n\ndescribe(\"DataGrid controlled callbacks\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n it(\"fires onSortChange from the current controlled sort state\", () => {\n const onSortChange = vi.fn();\n const { getByRole } = render(<InteractiveDataGridHarness onSortChange={onSortChange} />);\n\n fireEvent.click(getByRole(\"columnheader\", { name: /name/i }));\n\n expect(onSortChange).toHaveBeenCalledTimes(1);\n expect(onSortChange).toHaveBeenCalledWith([{ columnId: \"name\", direction: \"asc\" }]);\n });\n\n it(\"fires onSelectionChange when selecting all rows\", () => {\n const onSelectionChange = vi.fn();\n const { getByRole } = render(<InteractiveDataGridHarness onSelectionChange={onSelectionChange} />);\n\n fireEvent.click(getByRole(\"checkbox\", { name: /select all rows/i }));\n\n expect(onSelectionChange).toHaveBeenCalledTimes(1);\n const [selectedIds, selectedRows] = onSelectionChange.mock.calls[0];\n expect([...selectedIds]).toEqual([\"row-1\"]);\n expect(selectedRows).toEqual([{ id: \"row-1\", name: \"Row 1\" }]);\n });\n\n it(\"identifies nested interactive controls as row-click blockers\", () => {\n const cell = document.createElement(\"div\");\n const button = document.createElement(\"button\");\n const label = document.createElement(\"span\");\n label.textContent = \"Open menu\";\n button.append(label);\n cell.append(button);\n\n expect(isDataGridInteractiveRowClickTarget(label.firstChild)).toBe(true);\n expect(isDataGridInteractiveRowClickTarget(cell)).toBe(false);\n });\n});\n\ndescribe(\"DataGrid horizontal scrolling\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n Object.defineProperty(HTMLElement.prototype, \"clientWidth\", {\n configurable: true,\n get() {\n return 320;\n },\n });\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n it(\"sizes the sticky clipping layer to the full row width\", () => {\n const { container } = render(<WideDataGridHarness />);\n\n const rowsClip = container.querySelector(\"[data-data-grid-rows-clip]\");\n\n expect(rowsClip).toBeInstanceOf(HTMLElement);\n expect((rowsClip as HTMLElement).style.minWidth).toBe(\"740px\");\n });\n\n it(\"lets the columns popover escape the sticky toolbar bounds\", () => {\n const { container, getByTitle } = render(<WideDataGridHarness />);\n\n fireEvent.click(getByTitle(\"Columns\"));\n\n const stickyChrome = container.querySelector('[role=\"grid\"]')?.firstElementChild;\n expect(stickyChrome).toBeInstanceOf(HTMLElement);\n expect((stickyChrome as HTMLElement).className).toContain(\"overflow-visible\");\n expect(container.textContent).toContain(\"Email\");\n });\n});\n"],"mappings":"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"}