@hexclave/dashboard-ui-components 1.0.0 β 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/alert.js +4 -4
- package/dist/components/alert.js.map +1 -1
- package/dist/components/analytics-chart/analytics-chart-pie.js +33 -11
- package/dist/components/analytics-chart/analytics-chart-pie.js.map +1 -1
- package/dist/components/analytics-chart/analytics-chart.js +3 -3
- package/dist/components/analytics-chart/analytics-chart.js.map +1 -1
- package/dist/components/analytics-chart/default-analytics-chart-tooltip.js +4 -4
- package/dist/components/analytics-chart/default-analytics-chart-tooltip.js.map +1 -1
- package/dist/components/analytics-chart/types.d.ts +1 -0
- package/dist/components/analytics-chart/types.d.ts.map +1 -1
- package/dist/components/analytics-chart/types.js.map +1 -1
- package/dist/components/badge.js +2 -2
- package/dist/components/badge.js.map +1 -1
- package/dist/components/button.d.ts +4 -4
- package/dist/components/button.js +11 -11
- package/dist/components/button.js.map +1 -1
- package/dist/components/card.js +7 -7
- package/dist/components/card.js.map +1 -1
- package/dist/components/chart-card.js +3 -3
- package/dist/components/chart-card.js.map +1 -1
- package/dist/components/chart-container.js +2 -2
- package/dist/components/chart-container.js.map +1 -1
- package/dist/components/chart-legend.js +3 -3
- package/dist/components/chart-legend.js.map +1 -1
- package/dist/components/chart-tooltip.js +7 -7
- package/dist/components/chart-tooltip.js.map +1 -1
- package/dist/components/data-grid/data-grid-toolbar.js +7 -7
- package/dist/components/data-grid/data-grid-toolbar.js.map +1 -1
- package/dist/components/data-grid/data-grid.js +16 -16
- package/dist/components/data-grid/data-grid.js.map +1 -1
- package/dist/components/data-grid/state.js +2 -2
- package/dist/components/data-grid/state.js.map +1 -1
- package/dist/components/dialog.js +22 -22
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/empty-state.js +2 -2
- package/dist/components/empty-state.js.map +1 -1
- package/dist/components/input.js +8 -8
- package/dist/components/input.js.map +1 -1
- package/dist/components/metric-card.js +5 -5
- package/dist/components/metric-card.js.map +1 -1
- package/dist/components/pill-toggle.js +11 -10
- package/dist/components/pill-toggle.js.map +1 -1
- package/dist/components/progress-bar.js +4 -4
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/separator.js +2 -2
- package/dist/components/separator.js.map +1 -1
- package/dist/components/skeleton.js +2 -2
- package/dist/components/skeleton.js.map +1 -1
- package/dist/components/table.js +14 -14
- package/dist/components/table.js.map +1 -1
- package/dist/components/tabs.js +10 -10
- package/dist/components/tabs.js.map +1 -1
- package/dist/dashboard-ui-components.global.js +1720 -1678
- package/dist/dashboard-ui-components.global.js.map +4 -4
- package/dist/esm/components/alert.js.map +1 -1
- package/dist/esm/components/analytics-chart/analytics-chart-pie.js +33 -11
- package/dist/esm/components/analytics-chart/analytics-chart-pie.js.map +1 -1
- package/dist/esm/components/analytics-chart/analytics-chart.js.map +1 -1
- package/dist/esm/components/analytics-chart/default-analytics-chart-tooltip.js.map +1 -1
- package/dist/esm/components/analytics-chart/types.d.ts +1 -0
- package/dist/esm/components/analytics-chart/types.d.ts.map +1 -1
- package/dist/esm/components/analytics-chart/types.js.map +1 -1
- package/dist/esm/components/badge.js.map +1 -1
- package/dist/esm/components/button.d.ts +4 -4
- package/dist/esm/components/button.js.map +1 -1
- package/dist/esm/components/card.js.map +1 -1
- package/dist/esm/components/chart-card.js.map +1 -1
- package/dist/esm/components/chart-container.js.map +1 -1
- package/dist/esm/components/chart-legend.js.map +1 -1
- package/dist/esm/components/chart-tooltip.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid-toolbar.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid.js.map +1 -1
- package/dist/esm/components/data-grid/state.js.map +1 -1
- package/dist/esm/components/dialog.js.map +1 -1
- package/dist/esm/components/empty-state.js.map +1 -1
- package/dist/esm/components/input.js.map +1 -1
- package/dist/esm/components/metric-card.js.map +1 -1
- package/dist/esm/components/pill-toggle.js +1 -0
- package/dist/esm/components/pill-toggle.js.map +1 -1
- package/dist/esm/components/progress-bar.js.map +1 -1
- package/dist/esm/components/separator.js.map +1 -1
- package/dist/esm/components/skeleton.js.map +1 -1
- package/dist/esm/components/table.js.map +1 -1
- package/dist/esm/components/tabs.js +1 -1
- package/dist/esm/components/tabs.js.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-grid-toolbar.js","names":["MagnifyingGlass","X","Eye","EyeSlash","Check","DownloadSimple"],"sources":["../../../src/components/data-grid/data-grid-toolbar.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@stackframe/stack-ui\";\nimport {\n Check,\n DownloadSimple,\n Eye,\n EyeSlash,\n MagnifyingGlass,\n X,\n} from \"@phosphor-icons/react\";\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport type {\n DataGridColumnDef,\n DataGridDateDisplay,\n DataGridStrings,\n DataGridToolbarContext,\n} from \"./types\";\n\n// βββ Popover primitive βββββββββββββββββββββββββββββββββββββββββββββββ\n\nfunction usePopover() {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [open]);\n\n React.useEffect(() => {\n if (!open) return;\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [open]);\n\n return { open, setOpen, ref };\n}\n\nfunction PopoverPanel({\n children,\n className,\n popoverRef,\n}: {\n children: React.ReactNode;\n className?: string;\n popoverRef: React.Ref<HTMLDivElement>;\n}) {\n return (\n <div\n ref={popoverRef}\n className={cn(\n \"absolute top-full left-0 mt-1 z-50\",\n \"bg-popover text-popover-foreground rounded-xl shadow-lg\",\n \"ring-1 ring-black/[0.08] dark:ring-white/[0.1]\",\n \"backdrop-blur-xl\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\n// βββ Quick search ββββββββββββββββββββββββββββββββββββββββββββββββββββ\n\nfunction QuickSearch({\n value,\n onChange,\n placeholder,\n}: {\n value: string;\n onChange: (value: string) => void;\n placeholder: string;\n}) {\n return (\n <div className=\"relative flex min-w-0 flex-1 items-center sm:flex-initial\">\n <MagnifyingGlass className=\"absolute left-2.5 h-3.5 w-3.5 text-muted-foreground/50 pointer-events-none\" />\n <input\n type=\"text\"\n className={cn(\n \"h-8 w-full sm:w-52 pl-8 pr-7 rounded-xl text-xs\",\n \"bg-background\",\n \"border border-black/[0.08] dark:border-white/[0.08]\",\n \"placeholder:text-muted-foreground/40\",\n \"focus:outline-none focus:ring-1 focus:ring-foreground/[0.1]\",\n \"transition-all duration-150\",\n )}\n placeholder={placeholder}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n />\n {value && (\n <button\n className=\"absolute right-2 text-muted-foreground/40 hover:text-muted-foreground\"\n onClick={() => onChange(\"\")}\n aria-label=\"Clear search\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n );\n}\n\n// βββ Toolbar button ββββββββββββββββββββββββββββββββββββββββββββββββββ\n\nfunction ToolbarButton({\n children,\n onClick,\n active,\n title,\n className: extraClassName,\n}: {\n children: React.ReactNode;\n onClick?: () => void;\n active?: boolean;\n title?: string;\n className?: string;\n}) {\n return (\n <button\n className={cn(\n \"relative flex items-center justify-center rounded-lg text-xs font-medium\",\n \"h-7 w-7\",\n \"transition-colors duration-75\",\n active\n ? \"bg-foreground/[0.06] text-foreground\"\n : \"text-muted-foreground hover:text-foreground hover:bg-foreground/[0.04]\",\n extraClassName,\n )}\n onClick={onClick}\n title={title}\n >\n {children}\n </button>\n );\n}\n\n// βββ Column manager ββββββββββββββββββββββββββββββββββββββββββββββββββ\n\nfunction ColumnManager<TRow>({\n columns,\n visibility,\n onChange,\n strings,\n dateDisplay,\n onDateDisplayChange,\n hasDateColumns,\n}: {\n columns: readonly DataGridColumnDef<TRow>[];\n visibility: Record<string, boolean>;\n onChange: (visibility: Record<string, boolean>) => void;\n strings: DataGridStrings;\n dateDisplay: DataGridDateDisplay;\n onDateDisplayChange: (mode: DataGridDateDisplay) => void;\n hasDateColumns: boolean;\n}) {\n const hideableColumns = useMemo(\n () => columns.filter((c) => c.hideable !== false),\n [columns],\n );\n\n const toggleColumn = (id: string) => {\n const current = visibility[id] !== false;\n onChange({ ...visibility, [id]: !current });\n };\n\n const showAll = () => {\n const next = { ...visibility };\n for (const col of hideableColumns) next[col.id] = true;\n onChange(next);\n };\n\n const hideAll = () => {\n const next = { ...visibility };\n for (const col of hideableColumns) next[col.id] = false;\n onChange(next);\n };\n\n return (\n <div className=\"p-2 min-w-[240px] max-w-[300px]\">\n <div className=\"max-h-[280px] overflow-y-auto space-y-0.5\">\n {hideableColumns.map((col) => {\n const visible = visibility[col.id] !== false;\n return (\n <button\n key={col.id}\n className={cn(\n \"flex items-center gap-2 w-full px-2.5 py-1.5 rounded-lg text-xs\",\n \"hover:bg-foreground/[0.06] transition-colors duration-75\",\n visible ? \"text-foreground\" : \"text-muted-foreground/50\",\n )}\n onClick={() => toggleColumn(col.id)}\n >\n {visible ? (\n <Eye className=\"h-3.5 w-3.5 flex-shrink-0 text-blue-500\" />\n ) : (\n <EyeSlash className=\"h-3.5 w-3.5 flex-shrink-0\" />\n )}\n <span className=\"truncate text-left\">\n {typeof col.header === \"string\" ? col.header : col.id}\n </span>\n {visible && <Check className=\"h-3 w-3 ml-auto flex-shrink-0 text-blue-500\" />}\n </button>\n );\n })}\n </div>\n <div className=\"flex items-center gap-2 mt-2 pt-2 border-t border-foreground/[0.06]\">\n <button className=\"text-[10px] text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors duration-75\" onClick={showAll}>\n {strings.showAll}\n </button>\n <span className=\"text-muted-foreground/20\">|</span>\n <button className=\"text-[10px] text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors duration-75\" onClick={hideAll}>\n {strings.hideAll}\n </button>\n </div>\n\n {/* Date format toggle β only rendered when at least one column\n uses `type: \"date\"` or `\"dateTime\"`. Toggling writes to\n `state.dateDisplay` and the grid re-renders every date cell. */}\n {hasDateColumns && (\n <div className=\"mt-2 pt-2 border-t border-foreground/[0.06]\">\n <div className=\"flex items-center justify-between gap-2 px-1\">\n <span className=\"text-[10px] font-medium uppercase tracking-wider text-muted-foreground\">\n {strings.dateFormat}\n </span>\n <div className=\"inline-flex items-center gap-0.5 rounded-lg bg-foreground/[0.04] p-0.5\">\n <button\n className={cn(\n \"px-2 py-0.5 rounded-md text-[11px] font-medium transition-colors duration-75\",\n dateDisplay === \"relative\"\n ? \"bg-background text-foreground shadow-sm ring-1 ring-foreground/[0.06]\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n onClick={() => onDateDisplayChange(\"relative\")}\n >\n {strings.dateFormatRelative}\n </button>\n <button\n className={cn(\n \"px-2 py-0.5 rounded-md text-[11px] font-medium transition-colors duration-75\",\n dateDisplay === \"absolute\"\n ? \"bg-background text-foreground shadow-sm ring-1 ring-foreground/[0.06]\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n onClick={() => onDateDisplayChange(\"absolute\")}\n >\n {strings.dateFormatAbsolute}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// βββ Main toolbar ββββββββββββββββββββββββββββββββββββββββββββββββββββ\n\nexport function DataGridToolbar<TRow>({\n ctx,\n extra,\n extraLeading,\n hideQuickSearch,\n}: {\n ctx: DataGridToolbarContext<TRow>;\n /** Extra content rendered inside the toolbar row, to the left of the\n * built-in columns / export actions. Use this to add table-specific\n * affordances (refresh, custom toggles, row counts) without giving up\n * the default actions. */\n extra?: React.ReactNode;\n /** Extra content rendered at the START of the toolbar row β occupies\n * the same position as the built-in quick search (after it, if the\n * quick search is visible). Use this together with `hideQuickSearch`\n * to fully replace the quick search with a custom input, e.g. an\n * AI-powered search bar. */\n extraLeading?: React.ReactNode;\n /** Whether to hide the built-in quick-search input. When `true`,\n * callers are expected to provide their own search UI via\n * `extraLeading`. */\n hideQuickSearch?: boolean;\n}) {\n const { state, onChange, columns, strings, exportCsv } = ctx;\n\n const columnPopover = usePopover();\n\n const updateVisibility = useCallback(\n (visibility: Record<string, boolean>) => {\n onChange((s) => ({ ...s, columnVisibility: visibility }));\n },\n [onChange],\n );\n\n const updateDateDisplay = useCallback(\n (mode: DataGridDateDisplay) => {\n onChange((s) => ({ ...s, dateDisplay: mode }));\n },\n [onChange],\n );\n\n const updateQuickSearch = useCallback(\n (value: string) => {\n onChange((s) => ({\n ...s,\n quickSearch: value,\n // Reset to first page whenever the search text changes,\n // otherwise you can end up on a page index that no longer\n // exists in the filtered / refetched result set.\n pagination: { ...s.pagination, pageIndex: 0 },\n }));\n },\n [onChange],\n );\n\n const hasDateColumns = useMemo(\n () => columns.some((c) => c.type === \"date\" || c.type === \"dateTime\"),\n [columns],\n );\n\n return (\n <div className=\"flex w-full min-w-0 flex-col gap-2 px-2.5 py-2.5 border-b border-foreground/[0.06] sm:flex-row sm:items-center sm:gap-2\">\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\">\n {!hideQuickSearch && (\n <QuickSearch\n value={state.quickSearch}\n onChange={updateQuickSearch}\n placeholder={strings.searchPlaceholder}\n />\n )}\n {extraLeading}\n {extra}\n </div>\n <div className=\"flex shrink-0 items-center justify-end gap-2\">\n <div className=\"relative shrink-0\" ref={columnPopover.ref}>\n <ToolbarButton\n onClick={() => columnPopover.setOpen(!columnPopover.open)}\n active={columnPopover.open}\n title={strings.columns}\n >\n <Eye className=\"h-3.5 w-3.5\" />\n </ToolbarButton>\n {columnPopover.open && (\n <PopoverPanel popoverRef={columnPopover.ref} className=\"right-0 left-auto\">\n <ColumnManager\n columns={columns}\n visibility={state.columnVisibility}\n onChange={updateVisibility}\n strings={strings}\n dateDisplay={state.dateDisplay}\n onDateDisplayChange={updateDateDisplay}\n hasDateColumns={hasDateColumns}\n />\n </PopoverPanel>\n )}\n </div>\n\n <ToolbarButton onClick={exportCsv} title={strings.export}>\n <DownloadSimple className=\"h-3.5 w-3.5\" />\n </ToolbarButton>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data-grid-toolbar.js","names":["MagnifyingGlass","X","Eye","EyeSlash","Check","DownloadSimple"],"sources":["../../../src/components/data-grid/data-grid-toolbar.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@hexclave/ui\";\nimport {\n Check,\n DownloadSimple,\n Eye,\n EyeSlash,\n MagnifyingGlass,\n X,\n} from \"@phosphor-icons/react\";\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport type {\n DataGridColumnDef,\n DataGridDateDisplay,\n DataGridStrings,\n DataGridToolbarContext,\n} from \"./types\";\n\n// βββ Popover primitive βββββββββββββββββββββββββββββββββββββββββββββββ\n\nfunction usePopover() {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [open]);\n\n React.useEffect(() => {\n if (!open) return;\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [open]);\n\n return { open, setOpen, ref };\n}\n\nfunction PopoverPanel({\n children,\n className,\n popoverRef,\n}: {\n children: React.ReactNode;\n className?: string;\n popoverRef: React.Ref<HTMLDivElement>;\n}) {\n return (\n <div\n ref={popoverRef}\n className={cn(\n \"absolute top-full left-0 mt-1 z-50\",\n \"bg-popover text-popover-foreground rounded-xl shadow-lg\",\n \"ring-1 ring-black/[0.08] dark:ring-white/[0.1]\",\n \"backdrop-blur-xl\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\n// βββ Quick search ββββββββββββββββββββββββββββββββββββββββββββββββββββ\n\nfunction QuickSearch({\n value,\n onChange,\n placeholder,\n}: {\n value: string;\n onChange: (value: string) => void;\n placeholder: string;\n}) {\n return (\n <div className=\"relative flex min-w-0 flex-1 items-center sm:flex-initial\">\n <MagnifyingGlass className=\"absolute left-2.5 h-3.5 w-3.5 text-muted-foreground/50 pointer-events-none\" />\n <input\n type=\"text\"\n className={cn(\n \"h-8 w-full sm:w-52 pl-8 pr-7 rounded-xl text-xs\",\n \"bg-background\",\n \"border border-black/[0.08] dark:border-white/[0.08]\",\n \"placeholder:text-muted-foreground/40\",\n \"focus:outline-none focus:ring-1 focus:ring-foreground/[0.1]\",\n \"transition-all duration-150\",\n )}\n placeholder={placeholder}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n />\n {value && (\n <button\n className=\"absolute right-2 text-muted-foreground/40 hover:text-muted-foreground\"\n onClick={() => onChange(\"\")}\n aria-label=\"Clear search\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n );\n}\n\n// βββ Toolbar button ββββββββββββββββββββββββββββββββββββββββββββββββββ\n\nfunction ToolbarButton({\n children,\n onClick,\n active,\n title,\n className: extraClassName,\n}: {\n children: React.ReactNode;\n onClick?: () => void;\n active?: boolean;\n title?: string;\n className?: string;\n}) {\n return (\n <button\n className={cn(\n \"relative flex items-center justify-center rounded-lg text-xs font-medium\",\n \"h-7 w-7\",\n \"transition-colors duration-75\",\n active\n ? \"bg-foreground/[0.06] text-foreground\"\n : \"text-muted-foreground hover:text-foreground hover:bg-foreground/[0.04]\",\n extraClassName,\n )}\n onClick={onClick}\n title={title}\n >\n {children}\n </button>\n );\n}\n\n// βββ Column manager ββββββββββββββββββββββββββββββββββββββββββββββββββ\n\nfunction ColumnManager<TRow>({\n columns,\n visibility,\n onChange,\n strings,\n dateDisplay,\n onDateDisplayChange,\n hasDateColumns,\n}: {\n columns: readonly DataGridColumnDef<TRow>[];\n visibility: Record<string, boolean>;\n onChange: (visibility: Record<string, boolean>) => void;\n strings: DataGridStrings;\n dateDisplay: DataGridDateDisplay;\n onDateDisplayChange: (mode: DataGridDateDisplay) => void;\n hasDateColumns: boolean;\n}) {\n const hideableColumns = useMemo(\n () => columns.filter((c) => c.hideable !== false),\n [columns],\n );\n\n const toggleColumn = (id: string) => {\n const current = visibility[id] !== false;\n onChange({ ...visibility, [id]: !current });\n };\n\n const showAll = () => {\n const next = { ...visibility };\n for (const col of hideableColumns) next[col.id] = true;\n onChange(next);\n };\n\n const hideAll = () => {\n const next = { ...visibility };\n for (const col of hideableColumns) next[col.id] = false;\n onChange(next);\n };\n\n return (\n <div className=\"p-2 min-w-[240px] max-w-[300px]\">\n <div className=\"max-h-[280px] overflow-y-auto space-y-0.5\">\n {hideableColumns.map((col) => {\n const visible = visibility[col.id] !== false;\n return (\n <button\n key={col.id}\n className={cn(\n \"flex items-center gap-2 w-full px-2.5 py-1.5 rounded-lg text-xs\",\n \"hover:bg-foreground/[0.06] transition-colors duration-75\",\n visible ? \"text-foreground\" : \"text-muted-foreground/50\",\n )}\n onClick={() => toggleColumn(col.id)}\n >\n {visible ? (\n <Eye className=\"h-3.5 w-3.5 flex-shrink-0 text-blue-500\" />\n ) : (\n <EyeSlash className=\"h-3.5 w-3.5 flex-shrink-0\" />\n )}\n <span className=\"truncate text-left\">\n {typeof col.header === \"string\" ? col.header : col.id}\n </span>\n {visible && <Check className=\"h-3 w-3 ml-auto flex-shrink-0 text-blue-500\" />}\n </button>\n );\n })}\n </div>\n <div className=\"flex items-center gap-2 mt-2 pt-2 border-t border-foreground/[0.06]\">\n <button className=\"text-[10px] text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors duration-75\" onClick={showAll}>\n {strings.showAll}\n </button>\n <span className=\"text-muted-foreground/20\">|</span>\n <button className=\"text-[10px] text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors duration-75\" onClick={hideAll}>\n {strings.hideAll}\n </button>\n </div>\n\n {/* Date format toggle β only rendered when at least one column\n uses `type: \"date\"` or `\"dateTime\"`. Toggling writes to\n `state.dateDisplay` and the grid re-renders every date cell. */}\n {hasDateColumns && (\n <div className=\"mt-2 pt-2 border-t border-foreground/[0.06]\">\n <div className=\"flex items-center justify-between gap-2 px-1\">\n <span className=\"text-[10px] font-medium uppercase tracking-wider text-muted-foreground\">\n {strings.dateFormat}\n </span>\n <div className=\"inline-flex items-center gap-0.5 rounded-lg bg-foreground/[0.04] p-0.5\">\n <button\n className={cn(\n \"px-2 py-0.5 rounded-md text-[11px] font-medium transition-colors duration-75\",\n dateDisplay === \"relative\"\n ? \"bg-background text-foreground shadow-sm ring-1 ring-foreground/[0.06]\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n onClick={() => onDateDisplayChange(\"relative\")}\n >\n {strings.dateFormatRelative}\n </button>\n <button\n className={cn(\n \"px-2 py-0.5 rounded-md text-[11px] font-medium transition-colors duration-75\",\n dateDisplay === \"absolute\"\n ? \"bg-background text-foreground shadow-sm ring-1 ring-foreground/[0.06]\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n onClick={() => onDateDisplayChange(\"absolute\")}\n >\n {strings.dateFormatAbsolute}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// βββ Main toolbar ββββββββββββββββββββββββββββββββββββββββββββββββββββ\n\nexport function DataGridToolbar<TRow>({\n ctx,\n extra,\n extraLeading,\n hideQuickSearch,\n}: {\n ctx: DataGridToolbarContext<TRow>;\n /** Extra content rendered inside the toolbar row, to the left of the\n * built-in columns / export actions. Use this to add table-specific\n * affordances (refresh, custom toggles, row counts) without giving up\n * the default actions. */\n extra?: React.ReactNode;\n /** Extra content rendered at the START of the toolbar row β occupies\n * the same position as the built-in quick search (after it, if the\n * quick search is visible). Use this together with `hideQuickSearch`\n * to fully replace the quick search with a custom input, e.g. an\n * AI-powered search bar. */\n extraLeading?: React.ReactNode;\n /** Whether to hide the built-in quick-search input. When `true`,\n * callers are expected to provide their own search UI via\n * `extraLeading`. */\n hideQuickSearch?: boolean;\n}) {\n const { state, onChange, columns, strings, exportCsv } = ctx;\n\n const columnPopover = usePopover();\n\n const updateVisibility = useCallback(\n (visibility: Record<string, boolean>) => {\n onChange((s) => ({ ...s, columnVisibility: visibility }));\n },\n [onChange],\n );\n\n const updateDateDisplay = useCallback(\n (mode: DataGridDateDisplay) => {\n onChange((s) => ({ ...s, dateDisplay: mode }));\n },\n [onChange],\n );\n\n const updateQuickSearch = useCallback(\n (value: string) => {\n onChange((s) => ({\n ...s,\n quickSearch: value,\n // Reset to first page whenever the search text changes,\n // otherwise you can end up on a page index that no longer\n // exists in the filtered / refetched result set.\n pagination: { ...s.pagination, pageIndex: 0 },\n }));\n },\n [onChange],\n );\n\n const hasDateColumns = useMemo(\n () => columns.some((c) => c.type === \"date\" || c.type === \"dateTime\"),\n [columns],\n );\n\n return (\n <div className=\"flex w-full min-w-0 flex-col gap-2 px-2.5 py-2.5 border-b border-foreground/[0.06] sm:flex-row sm:items-center sm:gap-2\">\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\">\n {!hideQuickSearch && (\n <QuickSearch\n value={state.quickSearch}\n onChange={updateQuickSearch}\n placeholder={strings.searchPlaceholder}\n />\n )}\n {extraLeading}\n {extra}\n </div>\n <div className=\"flex shrink-0 items-center justify-end gap-2\">\n <div className=\"relative shrink-0\" ref={columnPopover.ref}>\n <ToolbarButton\n onClick={() => columnPopover.setOpen(!columnPopover.open)}\n active={columnPopover.open}\n title={strings.columns}\n >\n <Eye className=\"h-3.5 w-3.5\" />\n </ToolbarButton>\n {columnPopover.open && (\n <PopoverPanel popoverRef={columnPopover.ref} className=\"right-0 left-auto\">\n <ColumnManager\n columns={columns}\n visibility={state.columnVisibility}\n onChange={updateVisibility}\n strings={strings}\n dateDisplay={state.dateDisplay}\n onDateDisplayChange={updateDateDisplay}\n hasDateColumns={hasDateColumns}\n />\n </PopoverPanel>\n )}\n </div>\n\n <ToolbarButton onClick={exportCsv} title={strings.export}>\n <DownloadSimple className=\"h-3.5 w-3.5\" />\n </ToolbarButton>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
4
|
const require_chunk = require('../../chunk-BE-pF4vm.js');
|
|
5
5
|
let _phosphor_icons_react = require("@phosphor-icons/react");
|
|
6
|
-
let
|
|
6
|
+
let _hexclave_ui = require("@hexclave/ui");
|
|
7
7
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
8
|
let react = require("react");
|
|
9
9
|
react = require_chunk.__toESM(react);
|
|
10
10
|
let __state_js = require("./state.js");
|
|
11
11
|
let __strings_js = require("./strings.js");
|
|
12
|
-
let
|
|
12
|
+
let _hexclave_shared_dist_utils_errors = require("@hexclave/shared/dist/utils/errors");
|
|
13
13
|
let _tanstack_react_table = require("@tanstack/react-table");
|
|
14
14
|
let _tanstack_react_virtual = require("@tanstack/react-virtual");
|
|
15
15
|
let ___skeleton_js = require("../skeleton.js");
|
|
@@ -129,7 +129,7 @@ function HeaderCell({ header, col, resizable }) {
|
|
|
129
129
|
const canResize = resizable && header.column.getCanResize();
|
|
130
130
|
const isResizing = header.column.getIsResizing();
|
|
131
131
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
132
|
-
className: (0,
|
|
132
|
+
className: (0, _hexclave_ui.cn)("group/header relative flex items-center gap-1.5 px-3 select-none bg-transparent overflow-hidden", "border-r border-black/[0.04] dark:border-white/[0.04] last:border-r-0", sortable && "cursor-pointer"),
|
|
133
133
|
style: { width: `calc(var(--col-${col.id}-size) * 1px)` },
|
|
134
134
|
"data-col-id": col.id,
|
|
135
135
|
onClick: sortable ? header.column.getToggleSortingHandler() : void 0,
|
|
@@ -137,7 +137,7 @@ function HeaderCell({ header, col, resizable }) {
|
|
|
137
137
|
"aria-sort": sorted === "asc" ? "ascending" : sorted === "desc" ? "descending" : "none",
|
|
138
138
|
children: [
|
|
139
139
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
140
|
-
className: (0,
|
|
140
|
+
className: (0, _hexclave_ui.cn)("flex-1 min-w-0 truncate text-xs font-semibold uppercase tracking-wider text-muted-foreground", col.align === "center" && "text-center", col.align === "right" && "text-right"),
|
|
141
141
|
children: label
|
|
142
142
|
}),
|
|
143
143
|
sorted && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
@@ -170,7 +170,7 @@ function HeaderCell({ header, col, resizable }) {
|
|
|
170
170
|
e.preventDefault();
|
|
171
171
|
e.stopPropagation();
|
|
172
172
|
},
|
|
173
|
-
className: (0,
|
|
173
|
+
className: (0, _hexclave_ui.cn)("absolute right-0 top-0 bottom-0 z-10 w-[5px] cursor-col-resize touch-none", "group-hover/header:bg-foreground/[0.06] hover:!bg-blue-500/30", "transition-colors duration-100", isResizing && "bg-blue-500/40")
|
|
174
174
|
})
|
|
175
175
|
]
|
|
176
176
|
});
|
|
@@ -194,7 +194,7 @@ function DataCell({ col, row, rowId, rowIndex, isSelected, dateDisplay }) {
|
|
|
194
194
|
const hasCellClick = col.onCellClick || col.onCellDoubleClick;
|
|
195
195
|
const isWrap = col.cellOverflow === "wrap";
|
|
196
196
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
197
|
-
className: (0,
|
|
197
|
+
className: (0, _hexclave_ui.cn)("flex px-3 bg-transparent overflow-hidden", "border-r border-black/[0.04] dark:border-white/[0.04] last:border-r-0", "text-sm text-foreground", isWrap ? "items-start py-2" : "items-center", col.align === "center" && "justify-center", col.align === "right" && "justify-end", hasCellClick && "cursor-pointer"),
|
|
198
198
|
style: { width: `calc(var(--col-${col.id}-size) * 1px)` },
|
|
199
199
|
"data-col-id": col.id,
|
|
200
200
|
role: "gridcell",
|
|
@@ -207,7 +207,7 @@ function DataCell({ col, row, rowId, rowIndex, isSelected, dateDisplay }) {
|
|
|
207
207
|
col.onCellDoubleClick(ctx, e);
|
|
208
208
|
} : void 0,
|
|
209
209
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
210
|
-
className: (0,
|
|
210
|
+
className: (0, _hexclave_ui.cn)("min-w-0", isWrap ? "flex-1" : "truncate"),
|
|
211
211
|
children: content
|
|
212
212
|
})
|
|
213
213
|
});
|
|
@@ -218,7 +218,7 @@ function formatCellValue(value) {
|
|
|
218
218
|
children: "-"
|
|
219
219
|
});
|
|
220
220
|
if (typeof value === "boolean") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
221
|
-
className: (0,
|
|
221
|
+
className: (0, _hexclave_ui.cn)("inline-flex items-center px-1.5 py-0.5 rounded-md text-xs font-medium", value ? "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400" : "bg-foreground/[0.04] text-muted-foreground"),
|
|
222
222
|
children: value ? "Yes" : "No"
|
|
223
223
|
});
|
|
224
224
|
if (value instanceof Date) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -272,7 +272,7 @@ function SkeletonRow({ columns, height, showCheckbox }) {
|
|
|
272
272
|
function SelectionCheckbox({ checked, indeterminate, onChange, ariaLabel, title }) {
|
|
273
273
|
const Icon = indeterminate ? _phosphor_icons_react.MinusSquare : checked ? _phosphor_icons_react.CheckSquare : _phosphor_icons_react.Square;
|
|
274
274
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
275
|
-
className: (0,
|
|
275
|
+
className: (0, _hexclave_ui.cn)("flex items-center justify-center w-full h-full", "hover:bg-foreground/[0.04] transition-colors duration-75", checked || indeterminate ? "text-blue-600 dark:text-blue-400" : "text-muted-foreground/40 hover:text-muted-foreground/60"),
|
|
276
276
|
onClick: (e) => {
|
|
277
277
|
e.stopPropagation();
|
|
278
278
|
onChange(e);
|
|
@@ -347,7 +347,7 @@ function DefaultFooter({ ctx, pagination, onChange }) {
|
|
|
347
347
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
348
348
|
className: "flex items-center gap-1.5",
|
|
349
349
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: strings.rowsPerPage }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
350
|
-
className: (0,
|
|
350
|
+
className: (0, _hexclave_ui.cn)("h-7 rounded-lg border border-black/[0.08] dark:border-white/[0.08] bg-background px-1.5", "text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-foreground/[0.1]", "cursor-pointer"),
|
|
351
351
|
value: state.pagination.pageSize,
|
|
352
352
|
onChange: (e) => setPageSize(Number(e.target.value)),
|
|
353
353
|
children: [
|
|
@@ -364,7 +364,7 @@ function DefaultFooter({ ctx, pagination, onChange }) {
|
|
|
364
364
|
className: "flex items-center gap-1",
|
|
365
365
|
children: [
|
|
366
366
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
367
|
-
className: (0,
|
|
367
|
+
className: (0, _hexclave_ui.cn)("h-7 w-7 flex items-center justify-center rounded-lg", "hover:bg-foreground/[0.04] disabled:opacity-30 disabled:cursor-not-allowed", "transition-colors duration-75"),
|
|
368
368
|
onClick: () => setPage(state.pagination.pageIndex - 1),
|
|
369
369
|
disabled: state.pagination.pageIndex === 0,
|
|
370
370
|
"aria-label": "Previous page",
|
|
@@ -378,7 +378,7 @@ function DefaultFooter({ ctx, pagination, onChange }) {
|
|
|
378
378
|
children: strings.pageOf(state.pagination.pageIndex + 1, totalPages)
|
|
379
379
|
}),
|
|
380
380
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
381
|
-
className: (0,
|
|
381
|
+
className: (0, _hexclave_ui.cn)("h-7 w-7 flex items-center justify-center rounded-lg", "hover:bg-foreground/[0.04] disabled:opacity-30 disabled:cursor-not-allowed", "transition-colors duration-75"),
|
|
382
382
|
onClick: () => setPage(state.pagination.pageIndex + 1),
|
|
383
383
|
disabled: state.pagination.pageIndex >= totalPages - 1,
|
|
384
384
|
"aria-label": "Next page",
|
|
@@ -767,7 +767,7 @@ function DataGrid(props) {
|
|
|
767
767
|
const isBounded = fillHeight || maxHeight != null;
|
|
768
768
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
769
769
|
ref: gridRef,
|
|
770
|
-
className: (0,
|
|
770
|
+
className: (0, _hexclave_ui.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),
|
|
771
771
|
style: maxHeight != null ? {
|
|
772
772
|
...cssVars,
|
|
773
773
|
maxHeight
|
|
@@ -826,7 +826,7 @@ function DataGrid(props) {
|
|
|
826
826
|
}),
|
|
827
827
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
828
828
|
ref: scrollContainerRef,
|
|
829
|
-
className: (0,
|
|
829
|
+
className: (0, _hexclave_ui.cn)("relative z-0 w-full min-w-0 overflow-auto bg-transparent", isBounded ? "min-h-0 flex-1" : "flex-none", "[&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar]:h-1.5", "[&::-webkit-scrollbar-track]:bg-transparent", "[&::-webkit-scrollbar-thumb]:bg-foreground/[0.08] [&::-webkit-scrollbar-thumb]:rounded-full", "[&::-webkit-scrollbar-thumb]:hover:bg-foreground/[0.15]"),
|
|
830
830
|
onScroll: handleBodyScroll,
|
|
831
831
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
832
832
|
ref: rowsClipRef,
|
|
@@ -858,14 +858,14 @@ function DataGrid(props) {
|
|
|
858
858
|
position: "relative"
|
|
859
859
|
},
|
|
860
860
|
children: rowVirtualizer.getVirtualItems().map((virtualRow) => {
|
|
861
|
-
const row = rows[virtualRow.index] ?? (0,
|
|
861
|
+
const row = rows[virtualRow.index] ?? (0, _hexclave_shared_dist_utils_errors.throwErr)(`DataGrid: virtualized row index ${virtualRow.index} out of range (rows.length=${rows.length})`);
|
|
862
862
|
const rowId = getRowId(row);
|
|
863
863
|
const isSelected = state.selection.selectedIds.has(rowId);
|
|
864
864
|
const isOddRow = virtualRow.index % 2 === 1;
|
|
865
865
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
866
866
|
ref: isDynamicRowHeight ? rowVirtualizer.measureElement : void 0,
|
|
867
867
|
"data-index": virtualRow.index,
|
|
868
|
-
className: (0,
|
|
868
|
+
className: (0, _hexclave_ui.cn)("absolute left-0 w-full flex", "border-b border-black/[0.03] dark:border-white/[0.03]", "transition-colors duration-75", isSelected ? "bg-blue-500/[0.06] dark:bg-blue-400/[0.08] hover:bg-blue-500/[0.08] dark:hover:bg-blue-400/[0.1]" : isOddRow ? "bg-foreground/[0.02] dark:bg-foreground/[0.03] hover:bg-foreground/[0.04] dark:hover:bg-foreground/[0.06]" : "hover:bg-foreground/[0.025] dark:hover:bg-foreground/[0.04]", (selectionMode !== "none" || onRowClick) && "cursor-pointer"),
|
|
869
869
|
style: {
|
|
870
870
|
...isDynamicRowHeight ? { minHeight: estimatedRowHeight } : { height: fixedRowHeight },
|
|
871
871
|
transform: `translateY(${virtualRow.start}px)`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-grid.js","names":["ArrowUp","ArrowDown","CaretUp","CaretDown","DesignSkeleton","MinusSquare","CheckSquare","Square","DEFAULT_COL_WIDTH","DataGridToolbar"],"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 \"@stackframe/stack-shared/dist/utils/errors\";\nimport { cn } from \"@stackframe/stack-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 { DataGridToolbar } from \"./data-grid-toolbar\";\nimport { exportToCsv, 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 useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const observer = new IntersectionObserver(\n (entries) => { if (entries[0]?.isIntersecting) onIntersect(); },\n { root: rootRef?.current ?? null, rootMargin: \"200px\" },\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [onIntersect, 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.08] bg-background px-1.5\",\n \"text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-foreground/[0.1]\",\n \"cursor-pointer\",\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 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 = () => {\n const w = scroller?.clientWidth ?? grid.clientWidth;\n if (w > 0) setContainerWidth(w);\n };\n update();\n const observer = new ResizeObserver(update);\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 // ββ CSV export βββββββββββββββββββββββββββββββββββββββββββββββ\n // The grid only knows about rows currently in memory (the visible page in\n // paginated mode, or the loaded prefix in infinite mode). To avoid users\n // assuming \"Export CSV\" means \"everything that exists on the server\", we\n // confirm with the loaded-row count before downloading. Consumers that\n // want true full-dataset export can override this via a parent toolbar.\n const handleExportCsv = useCallback(() => {\n if (typeof window !== \"undefined\" && rows.length > 0) {\n const totalSuffix = totalRowCount != null && totalRowCount > rows.length\n ? ` of ${totalRowCount} total β load more rows first to include them`\n : \"\";\n const confirmed = window.confirm(\n `Export ${rows.length.toLocaleString()} loaded row${rows.length === 1 ? \"\" : \"s\"}${totalSuffix}?`,\n );\n if (!confirmed) return;\n }\n exportToCsv(rows, visibleColumns, exportFilename);\n }, [rows, visibleColumns, exportFilename, totalRowCount]);\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 <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/60 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/60 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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data-grid.js","names":["ArrowUp","ArrowDown","CaretUp","CaretDown","DesignSkeleton","MinusSquare","CheckSquare","Square","DEFAULT_COL_WIDTH","DataGridToolbar"],"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 { DataGridToolbar } from \"./data-grid-toolbar\";\nimport { exportToCsv, 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 useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const observer = new IntersectionObserver(\n (entries) => { if (entries[0]?.isIntersecting) onIntersect(); },\n { root: rootRef?.current ?? null, rootMargin: \"200px\" },\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [onIntersect, 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.08] bg-background px-1.5\",\n \"text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-foreground/[0.1]\",\n \"cursor-pointer\",\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 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 = () => {\n const w = scroller?.clientWidth ?? grid.clientWidth;\n if (w > 0) setContainerWidth(w);\n };\n update();\n const observer = new ResizeObserver(update);\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 // ββ CSV export βββββββββββββββββββββββββββββββββββββββββββββββ\n // The grid only knows about rows currently in memory (the visible page in\n // paginated mode, or the loaded prefix in infinite mode). To avoid users\n // assuming \"Export CSV\" means \"everything that exists on the server\", we\n // confirm with the loaded-row count before downloading. Consumers that\n // want true full-dataset export can override this via a parent toolbar.\n const handleExportCsv = useCallback(() => {\n if (typeof window !== \"undefined\" && rows.length > 0) {\n const totalSuffix = totalRowCount != null && totalRowCount > rows.length\n ? ` of ${totalRowCount} total β load more rows first to include them`\n : \"\";\n const confirmed = window.confirm(\n `Export ${rows.length.toLocaleString()} loaded row${rows.length === 1 ? \"\" : \"s\"}${totalSuffix}?`,\n );\n if (!confirmed) return;\n }\n exportToCsv(rows, visibleColumns, exportFilename);\n }, [rows, visibleColumns, exportFilename, totalRowCount]);\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 <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/60 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/60 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"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_chunk = require('../../chunk-BE-pF4vm.js');
|
|
3
3
|
let __data_grid_sizing_js = require("./data-grid-sizing.js");
|
|
4
|
-
let
|
|
4
|
+
let _hexclave_shared_dist_utils_strings = require("@hexclave/shared/dist/utils/strings");
|
|
5
5
|
|
|
6
6
|
//#region src/components/data-grid/state.ts
|
|
7
7
|
/**
|
|
@@ -52,7 +52,7 @@ function defaultComparator(a, b) {
|
|
|
52
52
|
if (b == null) return 1;
|
|
53
53
|
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
54
54
|
if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
|
|
55
|
-
return (0,
|
|
55
|
+
return (0, _hexclave_shared_dist_utils_strings.stringCompare)(String(a), String(b));
|
|
56
56
|
}
|
|
57
57
|
function buildRowComparator(sortModel, columns) {
|
|
58
58
|
if (sortModel.length === 0) return null;
|