@neasg/design-system 0.4.24 → 0.4.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -133,7 +133,7 @@ export { useTableSort } from "./use-table-sort";
133
133
  export type { UseTableSortOptions, UseTableSortReturn, } from "./use-table-sort";
134
134
  export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableRowHeader, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
135
135
  export type { TableColumn, TableColumnWidths, TableProps, TableResizeMode, TableRowExpansionProps, TableRowTone, TableSortDirection, TableSortingProps, TableSkeletonConfig, TableRowSkeletonProps, } from "./table";
136
- export type { TableColumnFilter, TableColumnFilterOption, TableDateColumnFilter, TableOptionsColumnFilter, TableTextColumnFilter, } from "./table-column-filter";
136
+ export type { TableColumnFilter, TableColumnFilterOption, TableDateColumnFilter, TableDateRangeColumnFilter, TableOptionsColumnFilter, TableTextColumnFilter, } from "./table-column-filter";
137
137
  export { Tabs, SubTabs, TabsRoot, TabWithDropdown, type TabsItem, type TabsItemLabel, type TabsItemLabelProps, type TabsProps, type SubTabsItem, type SubTabsProps, TabsList, TabsTrigger, TabsContent, type TabWithDropdownProps, useTabsContext, type TabDropdownSection, } from "./tabs";
138
138
  export { Tooltip, TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider, type TooltipProps, } from "./tooltip";
139
139
  export { Toaster, toast } from "./toaster";
@@ -136,6 +136,13 @@ function MultiSelect({ label, options, value, onValueChange, placeholder = "Sele
136
136
  closeAndFocusTrigger();
137
137
  return;
138
138
  }
139
+ if (event.key === "Enter" || event.key === " ") {
140
+ event.preventDefault();
141
+ if (currentIndex >= 0) {
142
+ enabledOptions[currentIndex].click();
143
+ }
144
+ return;
145
+ }
139
146
  if (event.key === "Home" || event.key === "End") {
140
147
  event.preventDefault();
141
148
  focusBoundaryOption(event.key === "Home" ? "first" : "last");
@@ -1,4 +1,5 @@
1
1
  import * as React from "react";
2
+ import { type DateRangeInputValue } from "./date-input";
2
3
  interface TableColumnFilterBase {
3
4
  /** Overrides the column header text in accessible filter labels. */
4
5
  label?: string;
@@ -33,7 +34,14 @@ export interface TableDateColumnFilter extends TableColumnFilterBase {
33
34
  minDate?: Date;
34
35
  maxDate?: Date;
35
36
  }
36
- export type TableColumnFilter = TableTextColumnFilter | TableOptionsColumnFilter | TableDateColumnFilter;
37
+ export interface TableDateRangeColumnFilter extends TableColumnFilterBase {
38
+ type: "dateRange";
39
+ value: DateRangeInputValue;
40
+ onValueChange: (value: DateRangeInputValue) => void;
41
+ minDate?: Date;
42
+ maxDate?: Date;
43
+ }
44
+ export type TableColumnFilter = TableTextColumnFilter | TableOptionsColumnFilter | TableDateColumnFilter | TableDateRangeColumnFilter;
37
45
  interface TableColumnFilterControlProps {
38
46
  filter: TableColumnFilter;
39
47
  label: string;
@@ -9,9 +9,15 @@ import { cn } from "./lib/utils";
9
9
  import { Popover } from "./popover";
10
10
  import { PopoverMenuFooter, PopoverMenuFooterAction, PopoverMenuSearch, } from "./popover-menu";
11
11
  function isTableColumnFilterActive(filter) {
12
- return filter.type === "options"
13
- ? filter.values.length > 0
14
- : filter.value.trim().length > 0;
12
+ switch (filter.type) {
13
+ case "options":
14
+ return filter.values.length > 0;
15
+ case "dateRange":
16
+ return Boolean(filter.value.from || filter.value.to);
17
+ case "text":
18
+ case "date":
19
+ return filter.value.trim().length > 0;
20
+ }
15
21
  }
16
22
  function getOptionsFilterSummary(filter) {
17
23
  var _a, _b, _c;
@@ -68,6 +74,13 @@ function DateColumnFilter({ filter, label, }) {
68
74
  return (_jsx(DateInput, { label: `Filter by ${accessibleLabel}${active ? ", active" : ""}`, hideLabel: true, value: filter.value, onValueChange: filter.onValueChange, placeholder: (_b = filter.placeholder) !== null && _b !== void 0 ? _b : "Pick a date", disabled: filter.disabled, minDate: filter.minDate, maxDate: filter.maxDate, clearable: true, clearLabel: `Clear ${accessibleLabel} filter`, className: "gap-0", triggerClassName: cn(filterToggleVariants({ selected: active }), "h-9 w-full min-w-0 justify-start text-sm font-normal shadow-none", active ? "pl-2 pr-16" : "pl-2 pr-9", !active &&
69
75
  "border-0 bg-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground") }));
70
76
  }
77
+ function DateRangeColumnFilter({ filter, label, }) {
78
+ var _a, _b;
79
+ const active = isTableColumnFilterActive(filter);
80
+ const accessibleLabel = (_a = filter.label) !== null && _a !== void 0 ? _a : label;
81
+ return (_jsx(DateInput, { mode: "range", label: `Filter by ${accessibleLabel}${active ? ", active" : ""}`, hideLabel: true, value: filter.value, onValueChange: filter.onValueChange, placeholder: (_b = filter.placeholder) !== null && _b !== void 0 ? _b : "Pick date range", disabled: filter.disabled, minDate: filter.minDate, maxDate: filter.maxDate, clearable: true, clearLabel: `Clear ${accessibleLabel} filter`, className: "gap-0", triggerClassName: cn(filterToggleVariants({ selected: active }), "h-9 w-full min-w-0 justify-start text-sm font-normal shadow-none", active ? "pl-2 pr-16" : "pl-2 pr-9", !active &&
82
+ "border-0 bg-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground") }));
83
+ }
71
84
  function TableColumnFilterControl({ filter, label, }) {
72
85
  if (filter.type === "text") {
73
86
  return _jsx(TextColumnFilter, { filter: filter, label: label });
@@ -75,6 +88,9 @@ function TableColumnFilterControl({ filter, label, }) {
75
88
  if (filter.type === "options") {
76
89
  return _jsx(OptionsColumnFilter, { filter: filter, label: label });
77
90
  }
91
+ if (filter.type === "dateRange") {
92
+ return _jsx(DateRangeColumnFilter, { filter: filter, label: label });
93
+ }
78
94
  return _jsx(DateColumnFilter, { filter: filter, label: label });
79
95
  }
80
96
  export { TableColumnFilterControl };
package/dist/table.d.ts CHANGED
@@ -124,12 +124,14 @@ export interface TableRowExpansionProps<Row> {
124
124
  getToggleLabel?: (row: Row, rowIndex: number, expanded: boolean) => string;
125
125
  }
126
126
  interface SortableTableHeadProps<T extends string> {
127
+ ref?: React.Ref<HTMLTableCellElement>;
127
128
  field: T;
128
129
  children: React.ReactNode;
129
130
  currentSortField: T | null;
130
131
  currentSortDirection: SortDirection;
131
132
  onSort: (field: T) => void;
132
133
  className?: string;
134
+ style?: React.CSSProperties;
133
135
  allowWrap?: boolean;
134
136
  width?: string;
135
137
  minWidth?: string;
@@ -139,8 +141,10 @@ interface SortableTableHeadProps<T extends string> {
139
141
  resizeHandle?: React.ReactNode;
140
142
  treatWidthAsMinWidth?: boolean;
141
143
  containOverflow?: boolean;
144
+ gripIcon?: React.ReactNode;
145
+ [key: string]: unknown;
142
146
  }
143
- declare function SortableTableHead<T extends string>({ field, children, currentSortField, currentSortDirection, onSort, className, allowWrap, width, minWidth, maxWidth, align, sortLabel, resizeHandle, treatWidthAsMinWidth, containOverflow, }: SortableTableHeadProps<T>): import("react/jsx-runtime").JSX.Element;
147
+ declare function SortableTableHead<T extends string>({ ref, field, children, currentSortField, currentSortDirection, onSort, className, style, allowWrap, width, minWidth, maxWidth, align, sortLabel, resizeHandle, treatWidthAsMinWidth, containOverflow, gripIcon, ...rest }: SortableTableHeadProps<T>): import("react/jsx-runtime").JSX.Element;
144
148
  export interface TableColumnResizeHandleRenderProps<Row> {
145
149
  column: TableColumn<Row>;
146
150
  nextColumn: TableColumn<Row>;
@@ -194,6 +198,10 @@ export interface TableProps<Row> extends Omit<React.HTMLAttributes<HTMLDivElemen
194
198
  striped?: boolean;
195
199
  /** Adds a disclosure column and full-width expandable content for nested tables or row details. */
196
200
  rowExpansion?: TableRowExpansionProps<Row>;
201
+ /** When true, non-sticky header cells become draggable for column reordering. */
202
+ reorderableColumns?: boolean;
203
+ /** Called with the new ordered column key array after a drag-and-drop reorder. */
204
+ onColumnOrderChange?: (columnKeys: string[]) => void;
197
205
  }
198
- declare function Table<Row>({ accessibleLabel, columns, rows, getRowKey, emptyState, toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, minHeight, sorting, pagination, loading, loadingLabel, loadingRows, visibleColumnKeys, resizableColumns, columnResizeMode, columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState, emptyStateMinHeight, striped, rowExpansion, onScroll, style, ...props }: TableProps<Row>): import("react/jsx-runtime").JSX.Element;
206
+ declare function Table<Row>({ accessibleLabel, columns, rows, getRowKey, emptyState, toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, minHeight, sorting, pagination, loading, loadingLabel, loadingRows, visibleColumnKeys, resizableColumns, columnResizeMode, columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState, emptyStateMinHeight, striped, rowExpansion, reorderableColumns, onColumnOrderChange, onScroll, style, ...props }: TableProps<Row>): import("react/jsx-runtime").JSX.Element;
199
207
  export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableRowHeader, TableCaption, SortableTableHead, TableRowSkeleton, };
package/dist/table.js CHANGED
@@ -1,5 +1,8 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
+ import { DndContext, KeyboardSensor, PointerSensor, closestCenter, useSensor, useSensors, } from "@dnd-kit/core";
4
+ import { SortableContext, arrayMove, horizontalListSortingStrategy, sortableKeyboardCoordinates, useSortable, } from "@dnd-kit/sortable";
5
+ import { CSS } from "@dnd-kit/utilities";
3
6
  import { ArrowUpDown, ChevronRight } from "lucide-react";
4
7
  import { ArrowDownIcon } from "./animated-icons/arrow-down";
5
8
  import { ArrowUpIcon } from "./animated-icons/arrow-up";
@@ -148,7 +151,7 @@ function getColumnHeaderAriaLabel(column) {
148
151
  }
149
152
  return undefined;
150
153
  }
151
- const TableHeader = React.forwardRef(({ className, ...props }, ref) => (_jsx("thead", { ref: ref, className: cn("sticky top-0 z-10 bg-[hsl(var(--table-header-background))] [&_tr]:border-b [&_tr]:border-[hsl(var(--table-border))] [&>tr]:bg-inherit", className), ...props })));
154
+ const TableHeader = React.forwardRef(({ className, ...props }, ref) => (_jsx("thead", { ref: ref, className: cn("sticky top-0 z-10 overflow-visible bg-[hsl(var(--table-header-background))] [&_tr]:border-b [&_tr]:border-[hsl(var(--table-border))] [&>tr]:bg-inherit", className), ...props })));
152
155
  TableHeader.displayName = "TableHeader";
153
156
  const TableBody = React.forwardRef(({ className, ...props }, ref) => (_jsx("tbody", { ref: ref, className: cn("[&_tr:last-child]:border-0", className), ...props })));
154
157
  TableBody.displayName = "TableBody";
@@ -262,19 +265,42 @@ export const TABLE_SKELETON_PRESETS = {
262
265
  })),
263
266
  }),
264
267
  };
265
- function SortableTableHead({ field, children, currentSortField, currentSortDirection, onSort, className, allowWrap = false, width, minWidth, maxWidth, align, sortLabel, resizeHandle, treatWidthAsMinWidth, containOverflow, }) {
268
+ function SortableTableHead({ ref, field, children, currentSortField, currentSortDirection, onSort, className, style, allowWrap = false, width, minWidth, maxWidth, align, sortLabel, resizeHandle, treatWidthAsMinWidth, containOverflow, gripIcon, ...rest }) {
266
269
  const isSorted = currentSortField === field;
267
270
  const resolvedSortLabel = sortLabel !== null && sortLabel !== void 0 ? sortLabel : (typeof children === "string" || typeof children === "number"
268
271
  ? String(children)
269
272
  : field);
270
- return (_jsxs(TableHead, { "data-slot": "table-column-head", scope: "col", "aria-sort": isSorted
273
+ return (_jsxs(TableHead, { ref: ref, "data-slot": "table-column-head", scope: "col", "aria-sort": isSorted
271
274
  ? currentSortDirection === "asc"
272
275
  ? "ascending"
273
276
  : "descending"
274
- : undefined, className: cn(resizeHandle && "relative", alignClassName(align), className), wrap: allowWrap, width: width, minWidth: minWidth, maxWidth: maxWidth, treatWidthAsMinWidth: treatWidthAsMinWidth, containOverflow: containOverflow, children: [_jsxs("button", { type: "button", onClick: () => onSort(field), className: cn("-ml-1.5 flex h-7 cursor-pointer items-center gap-1 rounded px-1.5 py-0 font-medium transition-colors hover:text-foreground", containOverflow && "max-w-full overflow-hidden", allowWrap
277
+ : undefined, className: cn(resizeHandle && "relative", alignClassName(align), className), style: style, wrap: allowWrap, width: width, minWidth: minWidth, maxWidth: maxWidth, treatWidthAsMinWidth: treatWidthAsMinWidth, containOverflow: containOverflow, ...rest, children: [gripIcon, _jsxs("button", { type: "button", onClick: () => onSort(field), className: cn("-ml-1.5 flex h-7 cursor-pointer items-center gap-1 rounded px-1.5 py-0 font-medium transition-colors hover:text-foreground", containOverflow && "max-w-full overflow-hidden", allowWrap
275
278
  ? "max-w-full whitespace-normal text-left"
276
279
  : "whitespace-nowrap", align === "right" && "ml-auto justify-end", align === "center" && "mx-auto justify-center"), style: { font: "inherit", color: "inherit", fontWeight: 500 }, "aria-label": `Sort by ${resolvedSortLabel}`, children: [_jsx("span", { className: cn("min-w-0", containOverflow && !allowWrap && "truncate", containOverflow && allowWrap && "break-words [overflow-wrap:anywhere]"), children: children }), _jsx("span", { "aria-hidden": "true", className: "inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center", children: isSorted ? (currentSortDirection === "asc" ? (_jsx(ArrowUpIcon, { className: "shrink-0", size: 14 })) : (_jsx(ArrowDownIcon, { className: "shrink-0", size: 14 }))) : (_jsx(ArrowUpDown, { className: "h-3.5 w-3.5 shrink-0 opacity-50" })) })] }), resizeHandle] }));
277
280
  }
281
+ const DragGripIcon = (_jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute bottom-0 left-1/2 z-20 -translate-x-1/2 translate-y-1/2 rounded border border-border bg-background px-1.5 py-0.5 text-muted-foreground opacity-0 shadow-sm transition-opacity group-hover/drag-col:opacity-100", children: _jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { transform: "rotate(90deg)" }, children: [_jsx("circle", { cx: "9", cy: "5", r: "1" }), _jsx("circle", { cx: "15", cy: "5", r: "1" }), _jsx("circle", { cx: "9", cy: "12", r: "1" }), _jsx("circle", { cx: "15", cy: "12", r: "1" }), _jsx("circle", { cx: "9", cy: "19", r: "1" }), _jsx("circle", { cx: "15", cy: "19", r: "1" })] }) }));
282
+ function DraggableColumnHead({ columnKey, disabled, hasResizeHandle, prevHasResizeHandle, isFirst, isLast, children, }) {
283
+ const { attributes, listeners, setNodeRef, transform, transition, isDragging, } = useSortable({ id: columnKey, disabled });
284
+ return children({
285
+ ref: setNodeRef,
286
+ style: {
287
+ transform: CSS.Translate.toString(transform),
288
+ transition,
289
+ zIndex: isDragging ? 30 : undefined,
290
+ },
291
+ className: cn(!disabled &&
292
+ "group/drag-col relative !overflow-visible cursor-grab active:cursor-grabbing", !disabled &&
293
+ !hasResizeHandle &&
294
+ !isLast &&
295
+ "after:pointer-events-none after:absolute after:right-0 after:top-1/2 after:z-[1] after:h-6 after:-translate-y-1/2 after:w-px after:rounded-full after:bg-transparent after:transition-colors hover:after:bg-[hsl(var(--table-border))]", !disabled &&
296
+ !hasResizeHandle &&
297
+ !prevHasResizeHandle &&
298
+ !isFirst &&
299
+ "before:pointer-events-none before:absolute before:left-0 before:top-1/2 before:z-[1] before:h-6 before:-translate-y-1/2 before:w-px before:rounded-full before:bg-transparent before:transition-colors hover:before:bg-[hsl(var(--table-border))]", isDragging && "z-10 opacity-90 shadow-lg"),
300
+ gripIcon: disabled ? null : DragGripIcon,
301
+ dragHandleProps: disabled ? {} : { ...attributes, ...listeners },
302
+ });
303
+ }
278
304
  const TableColumnResizeHandle = React.forwardRef(function TableColumnResizeHandle({ column, nextColumn, currentWidth, minWidth, maxWidth, onResizeStart, onResizeByKeyboard, className, onClick, ...props }, ref) {
279
305
  const label = getColumnResizeLabel(column);
280
306
  return (_jsx("div", { ...props, ref: ref, role: "separator", tabIndex: 0, "aria-orientation": "vertical", "aria-label": `Resize ${label} column`, title: `Resize ${label} column`, "aria-valuenow": currentWidth, "aria-valuemin": minWidth, "aria-valuemax": maxWidth, "aria-valuetext": currentWidth === undefined ? undefined : `${currentWidth} pixels`, onPointerDown: (event) => onResizeStart(column, nextColumn, event), onClick: (event) => {
@@ -365,7 +391,7 @@ function getColumnPairResizeRange(column, nextColumn, columnWidths) {
365
391
  maxWidth: Math.round(currentWidth + maxDelta),
366
392
  };
367
393
  }
368
- function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(EmptyState, { message: "No data available", description: "There are no rows to display in this table yet.", className: "border-0 bg-transparent px-0 py-6" })), toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, minHeight, sorting, pagination, loading = false, loadingLabel = "Loading table data", loadingRows = 5, visibleColumnKeys, resizableColumns = false, columnResizeMode = "pair", columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState = false, emptyStateMinHeight = DEFAULT_CENTERED_EMPTY_STATE_MIN_HEIGHT, striped = false, rowExpansion, onScroll, style, ...props }) {
394
+ function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(EmptyState, { message: "No data available", description: "There are no rows to display in this table yet.", className: "border-0 bg-transparent px-0 py-6" })), toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, minHeight, sorting, pagination, loading = false, loadingLabel = "Loading table data", loadingRows = 5, visibleColumnKeys, resizableColumns = false, columnResizeMode = "pair", columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState = false, emptyStateMinHeight = DEFAULT_CENTERED_EMPTY_STATE_MIN_HEIGHT, striped = false, rowExpansion, reorderableColumns = false, onColumnOrderChange, onScroll, style, ...props }) {
369
395
  const visibleColumns = getVisibleColumns(columns, visibleColumnKeys);
370
396
  const hasExpansionColumn = Boolean(rowExpansion);
371
397
  const hasColumnFilters = visibleColumns.some((column) => column.filter);
@@ -433,6 +459,24 @@ function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(E
433
459
  var _a;
434
460
  (_a = resizeCleanupRef.current) === null || _a === void 0 ? void 0 : _a.call(resizeCleanupRef);
435
461
  }, []);
462
+ const columnReorderSensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 8 } }), useSensor(KeyboardSensor, {
463
+ coordinateGetter: sortableKeyboardCoordinates,
464
+ }));
465
+ const handleColumnDragEnd = React.useCallback((event) => {
466
+ const { active, over } = event;
467
+ if (!over || active.id === over.id || !onColumnOrderChange) {
468
+ return;
469
+ }
470
+ const currentKeys = visibleColumns.map((col) => col.key);
471
+ const oldIndex = currentKeys.indexOf(String(active.id));
472
+ const newIndex = currentKeys.indexOf(String(over.id));
473
+ if (oldIndex >= 0 && newIndex >= 0) {
474
+ onColumnOrderChange(arrayMove(currentKeys, oldIndex, newIndex));
475
+ }
476
+ }, [visibleColumns, onColumnOrderChange]);
477
+ const reorderableColumnIds = React.useMemo(() => reorderableColumns
478
+ ? visibleColumns.filter((col) => !col.sticky).map((col) => col.key)
479
+ : [], [reorderableColumns, visibleColumns]);
436
480
  const commitColumnWidths = React.useCallback((updater) => {
437
481
  const nextColumnWidths = updater(columnWidthsRef.current);
438
482
  columnWidthsRef.current = nextColumnWidths;
@@ -584,6 +628,34 @@ function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(E
584
628
  }
585
629
  (_a = rowExpansion === null || rowExpansion === void 0 ? void 0 : rowExpansion.onExpandedRowKeysChange) === null || _a === void 0 ? void 0 : _a.call(rowExpansion, Array.from(nextExpandedRowKeys));
586
630
  }, [controlledExpandedRowKeys, rowExpansion, uncontrolledExpandedRowKeys]);
631
+ function renderColumnHead(column, columnIndex, dragProps) {
632
+ var _a;
633
+ const sortField = (_a = column.sortKey) !== null && _a !== void 0 ? _a : column.key;
634
+ const isSortable = column.sortable && sorting;
635
+ const columnWidth = getRenderedColumnWidth({
636
+ column,
637
+ columnWidths: resolvedColumnWidths,
638
+ resizing: isColumnResizingEnabled,
639
+ });
640
+ const resizeHandle = renderResizeHandle(column, columnIndex);
641
+ if (isSortable) {
642
+ return (_jsx(SortableTableHead, { ref: dragProps === null || dragProps === void 0 ? void 0 : dragProps.ref, field: sortField, currentSortField: sorting.field, currentSortDirection: sorting.direction, onSort: sorting.onSort, className: cn(stickyClassName(column.sticky, "head", getStickyShadowVisibility(column.sticky, stickyScrollState)), column.headerClassName, dragProps === null || dragProps === void 0 ? void 0 : dragProps.className), style: dragProps === null || dragProps === void 0 ? void 0 : dragProps.style, allowWrap: column.wrap, width: columnWidth, minWidth: getRenderedColumnMinWidth(column, isColumnResizingEnabled), maxWidth: getRenderedColumnMaxWidth(column, isColumnResizingEnabled), align: column.align, sortLabel: column.sortLabel, resizeHandle: resizeHandle, gripIcon: dragProps === null || dragProps === void 0 ? void 0 : dragProps.gripIcon, treatWidthAsMinWidth: !isColumnResizingEnabled, containOverflow: isColumnResizingEnabled, ...dragProps === null || dragProps === void 0 ? void 0 : dragProps.dragHandleProps, children: column.header }, column.key));
643
+ }
644
+ return (_jsxs(TableHead, { ref: dragProps === null || dragProps === void 0 ? void 0 : dragProps.ref, "data-slot": "table-column-head", "aria-label": getColumnHeaderAriaLabel(column), scope: "col", width: columnWidth, minWidth: getRenderedColumnMinWidth(column, isColumnResizingEnabled), maxWidth: getRenderedColumnMaxWidth(column, isColumnResizingEnabled), wrap: column.wrap, treatWidthAsMinWidth: !isColumnResizingEnabled, containOverflow: isColumnResizingEnabled, className: cn(resizeHandle && "relative", alignClassName(column.align), stickyClassName(column.sticky, "head", getStickyShadowVisibility(column.sticky, stickyScrollState)), column.headerClassName, dragProps === null || dragProps === void 0 ? void 0 : dragProps.className), style: dragProps === null || dragProps === void 0 ? void 0 : dragProps.style, ...dragProps === null || dragProps === void 0 ? void 0 : dragProps.dragHandleProps, children: [dragProps === null || dragProps === void 0 ? void 0 : dragProps.gripIcon, column.header, resizeHandle] }, column.key));
645
+ }
646
+ function renderColumnHeaders(cols) {
647
+ const headers = cols.map((column, columnIndex) => {
648
+ if (!reorderableColumns) {
649
+ return renderColumnHead(column, columnIndex);
650
+ }
651
+ const prevColumn = columnIndex > 0 ? cols[columnIndex - 1] : undefined;
652
+ return (_jsx(DraggableColumnHead, { columnKey: column.key, disabled: Boolean(column.sticky), hasResizeHandle: Boolean(renderResizeHandle(column, columnIndex)), prevHasResizeHandle: Boolean(prevColumn && renderResizeHandle(prevColumn, columnIndex - 1)), isFirst: columnIndex === 0, isLast: columnIndex === cols.length - 1, children: (dragProps) => renderColumnHead(column, columnIndex, dragProps) }, column.key));
653
+ });
654
+ if (!reorderableColumns) {
655
+ return headers;
656
+ }
657
+ return (_jsx(DndContext, { sensors: columnReorderSensors, collisionDetection: closestCenter, onDragEnd: handleColumnDragEnd, children: _jsx(SortableContext, { items: reorderableColumnIds, strategy: horizontalListSortingStrategy, children: headers }) }));
658
+ }
587
659
  const resolvedEmptyState = centerEmptyState ? (_jsx("div", { "data-slot": "table-empty-state", className: "flex w-full min-w-0 items-center justify-center whitespace-normal text-center [&>*]:mx-auto", style: { minHeight: emptyStateMinHeight }, children: emptyState })) : (emptyState);
588
660
  const container = (_jsxs(TableContainer, { ref: tableContainerRef, role: stickyScrollState.scrollable ? "region" : undefined, "aria-label": stickyScrollState.scrollable
589
661
  ? `${accessibleLabel} scroll area`
@@ -610,18 +682,7 @@ function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(E
610
682
  minWidth: getRenderedColumnMinWidth(column, isColumnResizingEnabled),
611
683
  maxWidth: getRenderedColumnMaxWidth(column, isColumnResizingEnabled),
612
684
  treatWidthAsMinWidth: !isColumnResizingEnabled,
613
- }) }, column.key)))] }), _jsxs(TableHeader, { children: [_jsxs(TableRow, { children: [hasExpansionColumn ? (_jsx(TableHead, { "data-slot": "table-expansion-head", "aria-label": "Expand rows", scope: "col", className: "w-12 px-2" })) : null, visibleColumns.map((column, columnIndex) => {
614
- var _a;
615
- const sortField = (_a = column.sortKey) !== null && _a !== void 0 ? _a : column.key;
616
- const isSortable = column.sortable && sorting;
617
- const columnWidth = getRenderedColumnWidth({
618
- column,
619
- columnWidths: resolvedColumnWidths,
620
- resizing: isColumnResizingEnabled,
621
- });
622
- const resizeHandle = renderResizeHandle(column, columnIndex);
623
- return (isSortable ? (_jsx(SortableTableHead, { field: sortField, currentSortField: sorting.field, currentSortDirection: sorting.direction, onSort: sorting.onSort, className: cn(stickyClassName(column.sticky, "head", getStickyShadowVisibility(column.sticky, stickyScrollState)), column.headerClassName), allowWrap: column.wrap, width: columnWidth, minWidth: getRenderedColumnMinWidth(column, isColumnResizingEnabled), maxWidth: getRenderedColumnMaxWidth(column, isColumnResizingEnabled), align: column.align, sortLabel: column.sortLabel, resizeHandle: resizeHandle, treatWidthAsMinWidth: !isColumnResizingEnabled, containOverflow: isColumnResizingEnabled, children: column.header }, column.key)) : (_jsxs(TableHead, { "data-slot": "table-column-head", "aria-label": getColumnHeaderAriaLabel(column), scope: "col", width: columnWidth, minWidth: getRenderedColumnMinWidth(column, isColumnResizingEnabled), maxWidth: getRenderedColumnMaxWidth(column, isColumnResizingEnabled), wrap: column.wrap, treatWidthAsMinWidth: !isColumnResizingEnabled, containOverflow: isColumnResizingEnabled, className: cn(resizeHandle && "relative", alignClassName(column.align), stickyClassName(column.sticky, "head", getStickyShadowVisibility(column.sticky, stickyScrollState)), column.headerClassName), children: [column.header, resizeHandle] }, column.key)));
624
- })] }), hasColumnFilters ? (_jsxs(TableRow, { "data-slot": "table-filter-row", className: "!bg-card", children: [hasExpansionColumn ? (_jsx(TableCell, { "data-slot": "table-expansion-filter-cell", "aria-hidden": "true", className: "w-12 px-2" })) : null, visibleColumns.map((column) => {
685
+ }) }, column.key)))] }), _jsxs(TableHeader, { children: [_jsxs(TableRow, { children: [hasExpansionColumn ? (_jsx(TableHead, { "data-slot": "table-expansion-head", "aria-label": "Expand rows", scope: "col", className: "w-12 px-2" })) : null, renderColumnHeaders(visibleColumns)] }), hasColumnFilters ? (_jsxs(TableRow, { "data-slot": "table-filter-row", className: "!bg-card", children: [hasExpansionColumn ? (_jsx(TableCell, { "data-slot": "table-expansion-filter-cell", "aria-hidden": "true", className: "w-12 px-2" })) : null, visibleColumns.map((column) => {
625
686
  const columnWidth = getRenderedColumnWidth({
626
687
  column,
627
688
  columnWidths: resolvedColumnWidths,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neasg/design-system",
3
- "version": "0.4.24",
3
+ "version": "0.4.26",
4
4
  "description": "NEA shared design system primitives, theme tokens, and Storybook docs.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",