@vritti/quantum-ui 0.3.20 → 0.3.22

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.
@@ -21830,6 +21830,13 @@ function DataTable({
21830
21830
  }) {
21831
21831
  const [filtersOpen, setFiltersOpen] = useState(false);
21832
21832
  const importDialog = useDialog();
21833
+ const headerScrollRef = useRef(null);
21834
+ const bodyScrollRef = useRef(null);
21835
+ const syncHeaderScroll = () => {
21836
+ if (headerScrollRef.current && bodyScrollRef.current) {
21837
+ headerScrollRef.current.scrollLeft = bodyScrollRef.current.scrollLeft;
21838
+ }
21839
+ };
21833
21840
  const tableGate = usePermission(permission);
21834
21841
  const importGate = usePermission(importExport?.importPermission);
21835
21842
  const exportGate = usePermission(importExport?.exportPermission);
@@ -22002,134 +22009,158 @@ function DataTable({
22002
22009
  },
22003
22010
  "filters"
22004
22011
  ) : null }),
22005
- /* @__PURE__ */ jsxs("div", { className: "relative flex w-full flex-col overflow-auto overscroll-auto flex-1", children: [
22006
- /* @__PURE__ */ jsxs("table", { className: "w-full caption-bottom text-sm table-fixed", style: { minWidth: table.getCenterTotalSize() }, children: [
22007
- /* @__PURE__ */ jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(TableRow, { children: headerGroup.headers.map((header) => {
22008
- const isActions = header.column.id === "actions";
22009
- const headerAlignClass = isActions ? "justify-end" : "justify-center";
22010
- return /* @__PURE__ */ jsxs(
22011
- TableHead,
22012
- {
22013
- colSpan: header.colSpan,
22014
- style: isActions ? { width: "70px" } : { width: header.getSize(), minWidth: header.getSize(), maxWidth: header.getSize() },
22015
- className: cn(
22016
- "relative group/resize",
22017
- isActions ? "text-right sticky right-0 z-20" : "text-center"
22018
- ),
22019
- "aria-sort": header.column.getCanSort() ? header.column.getIsSorted() === "asc" ? "ascending" : header.column.getIsSorted() === "desc" ? "descending" : "none" : void 0,
22020
- children: [
22021
- isActions && /* @__PURE__ */ jsx(
22022
- "div",
22023
- {
22024
- "aria-hidden": true,
22025
- className: "pointer-events-none absolute inset-x-0 top-0 bottom-px bg-muted/40 backdrop-blur-sm"
22026
- }
22012
+ /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col flex-1 min-h-0", children: [
22013
+ /* @__PURE__ */ jsx("div", { ref: headerScrollRef, className: "shrink-0 overflow-hidden", children: /* @__PURE__ */ jsx(
22014
+ "table",
22015
+ {
22016
+ className: "w-full caption-bottom text-sm table-fixed",
22017
+ style: { minWidth: table.getCenterTotalSize() },
22018
+ children: /* @__PURE__ */ jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(TableRow, { children: headerGroup.headers.map((header) => {
22019
+ const isActions = header.column.id === "actions";
22020
+ const headerAlignClass = isActions ? "justify-end" : "justify-center";
22021
+ return /* @__PURE__ */ jsxs(
22022
+ TableHead,
22023
+ {
22024
+ colSpan: header.colSpan,
22025
+ style: isActions ? { width: "70px" } : { width: header.getSize(), minWidth: header.getSize(), maxWidth: header.getSize() },
22026
+ className: cn(
22027
+ "relative group/resize",
22028
+ // actions header stays pinned on horizontal scroll; z-20 keeps it above the
22029
+ // regular header cells that scroll underneath it.
22030
+ isActions ? "text-right sticky right-0 z-20" : "text-center"
22027
22031
  ),
22028
- /* @__PURE__ */ jsx("div", { className: cn(isActions ? "relative" : void 0), children: header.isPlaceholder ? null : typeof header.column.columnDef.header === "string" ? /* @__PURE__ */ jsx("div", { className: cn("flex", headerAlignClass), children: /* @__PURE__ */ jsx(DataTableColumnHeader, { column: header.column, title: header.column.columnDef.header }) }) : flexRender(header.column.columnDef.header, header.getContext()) }),
22029
- !meta?.lockedColumnSizing && header.column.getCanResize() && /* @__PURE__ */ jsx(
22030
- "div",
22031
- {
22032
- onPointerDown: header.getResizeHandler(),
22033
- onTouchStart: header.getResizeHandler(),
22034
- className: cn(
22035
- "absolute top-0 right-0 w-1 h-full cursor-col-resize select-none touch-none z-10",
22036
- "opacity-0 group-hover/resize:opacity-100 hover:bg-primary/50",
22037
- header.column.getIsResizing() && "opacity-100 bg-primary"
22038
- )
22039
- }
22040
- )
22041
- ]
22042
- },
22043
- header.id
22044
- );
22045
- }) }, headerGroup.id)) }),
22046
- !locked && (isLoading || table.getRowModel().rows.length > 0) && /* @__PURE__ */ jsx(TableBody, { children: isLoading ? Array.from(
22047
- { length: table.getState().pagination?.pageSize ?? 20 },
22048
- (_, i) => `skeleton-row-${i}`
22049
- ).map((rowKey) => /* @__PURE__ */ jsx(TableRow, { children: Array.from({ length: columnCount }, (_, i) => `${rowKey}-cell-${i}`).map((cellKey) => /* @__PURE__ */ jsx(TableCell, { className: densityClasses[density], children: /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-full" }) }, cellKey)) }, rowKey)) : table.getRowModel().rows.map((row, index) => {
22050
- const externallySelected = selectedRowId != null && row.id === selectedRowId;
22051
- const isSelected = row.getIsSelected() || externallySelected;
22052
- return /* @__PURE__ */ jsx(
22053
- TableRow,
22054
- {
22055
- "data-state": isSelected ? "selected" : void 0,
22056
- className: "group animate-in fade-in duration-300",
22057
- style: { animationDelay: `${Math.min(index, 12) * 25}ms`, animationFillMode: "both" },
22058
- children: row.getVisibleCells().map((cell) => {
22059
- const isActionsCell = cell.column.id === "actions";
22060
- return /* @__PURE__ */ jsxs(
22061
- TableCell,
22062
- {
22063
- className: cn(
22064
- densityClasses[density],
22065
- isActionsCell ? "px-2 sticky right-0 z-10" : void 0,
22066
- onRowClick && !isActionsCell ? "cursor-pointer" : void 0
22067
- ),
22068
- onClick: onRowClick && !isActionsCell ? () => onRowClick(row.original) : void 0,
22069
- style: isActionsCell ? { width: "70px" } : {
22070
- width: cell.column.getSize(),
22071
- minWidth: cell.column.getSize(),
22072
- maxWidth: cell.column.getSize()
22073
- },
22074
- children: [
22075
- isActionsCell && /* @__PURE__ */ jsx(
22076
- "div",
22077
- {
22078
- "aria-hidden": true,
22079
- className: "pointer-events-none absolute inset-x-0 top-0 bottom-px bg-background/40 backdrop-blur-sm group-hover:bg-muted/30 group-data-[state=selected]:bg-muted/40"
22080
- }
22081
- ),
22082
- /* @__PURE__ */ jsx(
22083
- "div",
22084
- {
22085
- className: cn(
22086
- isActionsCell ? "relative flex items-center justify-end" : "overflow-hidden text-center"
22087
- ),
22088
- children: flexRender(cell.column.columnDef.cell, cell.getContext())
22089
- }
22032
+ "aria-sort": header.column.getCanSort() ? header.column.getIsSorted() === "asc" ? "ascending" : header.column.getIsSorted() === "desc" ? "descending" : "none" : void 0,
22033
+ children: [
22034
+ isActions && /* @__PURE__ */ jsx(
22035
+ "div",
22036
+ {
22037
+ "aria-hidden": true,
22038
+ className: "pointer-events-none absolute inset-x-0 top-0 bottom-px bg-muted backdrop-blur-sm"
22039
+ }
22040
+ ),
22041
+ /* @__PURE__ */ jsx("div", { className: cn(isActions ? "relative" : void 0), children: header.isPlaceholder ? null : typeof header.column.columnDef.header === "string" ? /* @__PURE__ */ jsx("div", { className: cn("flex", headerAlignClass), children: /* @__PURE__ */ jsx(DataTableColumnHeader, { column: header.column, title: header.column.columnDef.header }) }) : flexRender(header.column.columnDef.header, header.getContext()) }),
22042
+ !meta?.lockedColumnSizing && header.column.getCanResize() && /* @__PURE__ */ jsx(
22043
+ "div",
22044
+ {
22045
+ onPointerDown: header.getResizeHandler(),
22046
+ onTouchStart: header.getResizeHandler(),
22047
+ className: cn(
22048
+ "absolute top-0 right-0 w-1 h-full cursor-col-resize select-none touch-none z-10",
22049
+ "opacity-0 group-hover/resize:opacity-100 hover:bg-primary/50",
22050
+ header.column.getIsResizing() && "opacity-100 bg-primary"
22090
22051
  )
22091
- ]
22092
- },
22093
- cell.id
22094
- );
22095
- })
22096
- },
22097
- row.id
22098
- );
22099
- }) })
22100
- ] }),
22101
- (locked || !isLoading && table.getRowModel().rows.length === 0) && /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center", children: locked ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-2 text-center", children: [
22102
- /* @__PURE__ */ jsx(PermissionLockIcon, { reason: tableGate.reason, className: "size-6" }),
22103
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: lockedTip(tableGate) })
22104
- ] }) : isFiltered ? /* @__PURE__ */ jsx(
22105
- DataTableEmpty,
22052
+ }
22053
+ )
22054
+ ]
22055
+ },
22056
+ header.id
22057
+ );
22058
+ }) }, headerGroup.id)) })
22059
+ }
22060
+ ) }),
22061
+ /* @__PURE__ */ jsxs(
22062
+ "div",
22106
22063
  {
22107
- icon: emptyStateConfig?.icon,
22108
- title: "No results found",
22109
- description: buildNoResultsDescription({ hasActiveSearch, hasActiveFilters, hasActiveView }),
22110
- action: /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
22111
- hasActiveSearch && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => meta?.setSearch?.(searchBaseline), children: "Clear Search" }),
22112
- hasActiveFilters && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => meta?.setFilters?.(filtersBaseline), children: "Clear Filters" }),
22113
- hasActiveView && slug && /* @__PURE__ */ jsx(
22114
- Button,
22064
+ ref: bodyScrollRef,
22065
+ onScroll: syncHeaderScroll,
22066
+ className: "relative flex flex-col flex-1 min-h-0 overflow-auto overscroll-auto",
22067
+ children: [
22068
+ !locked && (isLoading || table.getRowModel().rows.length > 0) && /* @__PURE__ */ jsx(
22069
+ "table",
22115
22070
  {
22116
- variant: "outline",
22117
- size: "sm",
22118
- onClick: () => loadViewState(slug, EMPTY_TABLE_STATE, null, false),
22119
- children: "Clear View"
22071
+ className: "w-full caption-bottom text-sm table-fixed",
22072
+ style: { minWidth: table.getCenterTotalSize() },
22073
+ children: /* @__PURE__ */ jsx(TableBody, { children: isLoading ? Array.from(
22074
+ { length: table.getState().pagination?.pageSize ?? 20 },
22075
+ (_, i) => `skeleton-row-${i}`
22076
+ ).map((rowKey) => /* @__PURE__ */ jsx(TableRow, { children: Array.from({ length: columnCount }, (_, i) => `${rowKey}-cell-${i}`).map((cellKey) => /* @__PURE__ */ jsx(TableCell, { className: densityClasses[density], children: /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-full" }) }, cellKey)) }, rowKey)) : table.getRowModel().rows.map((row, index) => {
22077
+ const externallySelected = selectedRowId != null && row.id === selectedRowId;
22078
+ const isSelected = row.getIsSelected() || externallySelected;
22079
+ return /* @__PURE__ */ jsx(
22080
+ TableRow,
22081
+ {
22082
+ "data-state": isSelected ? "selected" : void 0,
22083
+ className: "group animate-in fade-in duration-300",
22084
+ style: { animationDelay: `${Math.min(index, 12) * 25}ms`, animationFillMode: "both" },
22085
+ children: row.getVisibleCells().map((cell) => {
22086
+ const isActionsCell = cell.column.id === "actions";
22087
+ return /* @__PURE__ */ jsxs(
22088
+ TableCell,
22089
+ {
22090
+ className: cn(
22091
+ densityClasses[density],
22092
+ isActionsCell ? "px-2 sticky right-0 z-10" : void 0,
22093
+ onRowClick && !isActionsCell ? "cursor-pointer" : void 0
22094
+ ),
22095
+ onClick: onRowClick && !isActionsCell ? () => onRowClick(row.original) : void 0,
22096
+ style: isActionsCell ? { width: "70px" } : {
22097
+ width: cell.column.getSize(),
22098
+ minWidth: cell.column.getSize(),
22099
+ maxWidth: cell.column.getSize()
22100
+ },
22101
+ children: [
22102
+ isActionsCell && /* @__PURE__ */ jsx(
22103
+ "div",
22104
+ {
22105
+ "aria-hidden": true,
22106
+ className: "pointer-events-none absolute inset-x-0 top-0 bottom-px bg-background/40 backdrop-blur-sm group-hover:bg-muted/30 group-data-[state=selected]:bg-muted/40"
22107
+ }
22108
+ ),
22109
+ /* @__PURE__ */ jsx(
22110
+ "div",
22111
+ {
22112
+ className: cn(
22113
+ isActionsCell ? "relative flex items-center justify-end" : "overflow-hidden text-center"
22114
+ ),
22115
+ children: flexRender(cell.column.columnDef.cell, cell.getContext())
22116
+ }
22117
+ )
22118
+ ]
22119
+ },
22120
+ cell.id
22121
+ );
22122
+ })
22123
+ },
22124
+ row.id
22125
+ );
22126
+ }) })
22120
22127
  }
22121
- )
22122
- ] })
22123
- }
22124
- ) : /* @__PURE__ */ jsx(
22125
- DataTableEmpty,
22126
- {
22127
- icon: emptyStateConfig?.icon,
22128
- title: emptyStateConfig?.title,
22129
- description: emptyStateConfig?.description,
22130
- action: emptyStateConfig?.action
22128
+ ),
22129
+ (locked || !isLoading && table.getRowModel().rows.length === 0) && /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center", children: locked ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-2 text-center", children: [
22130
+ /* @__PURE__ */ jsx(PermissionLockIcon, { reason: tableGate.reason, className: "size-6" }),
22131
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: lockedTip(tableGate) })
22132
+ ] }) : isFiltered ? /* @__PURE__ */ jsx(
22133
+ DataTableEmpty,
22134
+ {
22135
+ icon: emptyStateConfig?.icon,
22136
+ title: "No results found",
22137
+ description: buildNoResultsDescription({ hasActiveSearch, hasActiveFilters, hasActiveView }),
22138
+ action: /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
22139
+ hasActiveSearch && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => meta?.setSearch?.(searchBaseline), children: "Clear Search" }),
22140
+ hasActiveFilters && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => meta?.setFilters?.(filtersBaseline), children: "Clear Filters" }),
22141
+ hasActiveView && slug && /* @__PURE__ */ jsx(
22142
+ Button,
22143
+ {
22144
+ variant: "outline",
22145
+ size: "sm",
22146
+ onClick: () => loadViewState(slug, EMPTY_TABLE_STATE, null, false),
22147
+ children: "Clear View"
22148
+ }
22149
+ )
22150
+ ] })
22151
+ }
22152
+ ) : /* @__PURE__ */ jsx(
22153
+ DataTableEmpty,
22154
+ {
22155
+ icon: emptyStateConfig?.icon,
22156
+ title: emptyStateConfig?.title,
22157
+ description: emptyStateConfig?.description,
22158
+ action: emptyStateConfig?.action
22159
+ }
22160
+ ) })
22161
+ ]
22131
22162
  }
22132
- ) })
22163
+ )
22133
22164
  ] })
22134
22165
  ] }),
22135
22166
  (mode !== "compact" || table.getRowCount() > (table.getState().pagination?.pageSize ?? 20)) && /* @__PURE__ */ jsx(DataTablePagination, { table }),