@dynostack/react-grid 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,7 +1,6 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Column, RowData, ColumnDef, SortingState, ColumnFiltersState, ColumnPinningState, VisibilityState, Table, CellContext, FilterFn } from '@tanstack/react-table';
3
1
  import * as React$1 from 'react';
4
2
  import { CSSProperties } from 'react';
3
+ import { Column, RowData, ColumnDef, SortingState, ColumnFiltersState, ColumnPinningState, VisibilityState, Table, CellContext, FilterFn } from '@tanstack/react-table';
5
4
 
6
5
  type RowActionId = "view" | "edit" | "duplicate" | "delete" | string;
7
6
  type CustomRowAction<TData> = {
@@ -20,7 +19,7 @@ type DataTableRowActionsProps<TData> = {
20
19
  onSaveEdit?: () => void;
21
20
  onCancelEdit?: () => void;
22
21
  };
23
- declare function DataTableRowActions<TData>({ row, actions, customActions, onAction, isEditing, onSaveEdit, onCancelEdit, }: DataTableRowActionsProps<TData>): react_jsx_runtime.JSX.Element;
22
+ declare function DataTableRowActions<TData>({ row, actions, customActions, onAction, isEditing, onSaveEdit, onCancelEdit, }: DataTableRowActionsProps<TData>): React$1.JSX.Element;
24
23
 
25
24
  /**
26
25
  * CSS variable overrides for a single DataTable instance.
@@ -157,7 +156,7 @@ type ViewSheetLabels = {
157
156
  type ViewSheetConfig<TData> = {
158
157
  /** Side of the screen to slide in from. Defaults to "right". */
159
158
  side?: SheetSide;
160
- /** Initial column count. Defaults to "compact" (1 column). */
159
+ /** Initial layout density. Defaults to "compact" (more fields per row). */
161
160
  defaultDensity?: ViewSheetDensity;
162
161
  /** Hide the density tabs entirely if you want a fixed layout. */
163
162
  hideDensityTabs?: boolean;
@@ -357,6 +356,18 @@ type DataTableProps<TData extends {
357
356
  pageSizeOptions?: number[];
358
357
  initialColumnPinning?: ColumnPinningState;
359
358
  initialColumnVisibility?: VisibilityState;
359
+ /** Initial sort order. */
360
+ initialSorting?: SortingState;
361
+ /** Observe selected row objects (loaded rows only in server mode). */
362
+ onSelectionChange?: (rows: TData[]) => void;
363
+ /** Accessible table name. */
364
+ ariaLabel?: string;
365
+ /** Alternating row backgrounds. */
366
+ striped?: boolean;
367
+ /** Keep headers visible inside a vertically constrained table. */
368
+ stickyHeader?: boolean;
369
+ /** Scroll viewport height, e.g. "480px". */
370
+ maxHeight?: React.CSSProperties["maxHeight"];
360
371
  /** Optional controlled global filter (for cross-tab persistence). */
361
372
  globalFilter?: string;
362
373
  onGlobalFilterChange?: (value: string) => void;
@@ -396,7 +407,7 @@ type DataTableProps<TData extends {
396
407
  };
397
408
  declare function DataTable<TData extends {
398
409
  id: string | number;
399
- }>({ data, columns, dataSource, isLoading, isFetching, onRefresh, totalRecords, exportFileName, enableSelection, renderSubRow, getSubRows, rowActions, customRowActions, onRowAction, onCellEdit, onRowSave, onAddRow, onBulkDelete, initialPageSize, pageSizeOptions, initialColumnPinning, initialColumnVisibility, globalFilter: globalFilterProp, onGlobalFilterChange, className, toolbarSlot, features, labels: labelsProp, density, theme, isolate, onView, onDelete, viewSheet, confirmDelete, }: DataTableProps<TData>): react_jsx_runtime.JSX.Element;
410
+ }>({ data, columns, dataSource, isLoading, isFetching, onRefresh, totalRecords, exportFileName, enableSelection, renderSubRow, getSubRows, rowActions, customRowActions, onRowAction, onCellEdit, onRowSave, onAddRow, onBulkDelete, initialPageSize, pageSizeOptions, initialColumnPinning, initialColumnVisibility, initialSorting, onSelectionChange, ariaLabel, striped, stickyHeader, maxHeight, globalFilter: globalFilterProp, onGlobalFilterChange, className, toolbarSlot, features, labels: labelsProp, density, theme, isolate, onView, onDelete, viewSheet, confirmDelete, }: DataTableProps<TData>): React$1.JSX.Element;
400
411
 
401
412
  /**
402
413
  * Shared portal container for every overlay inside a DataTable (popover,
@@ -426,13 +437,13 @@ type Props$2<TData, TValue> = {
426
437
  column: Column<TData, TValue>;
427
438
  title: string;
428
439
  };
429
- declare function DataTableColumnHeader<TData, TValue>({ column, title, }: Props$2<TData, TValue>): react_jsx_runtime.JSX.Element;
440
+ declare function DataTableColumnHeader<TData, TValue>({ column, title, }: Props$2<TData, TValue>): React$1.JSX.Element;
430
441
 
431
442
  type Props$1<TData> = {
432
443
  table: Table<TData>;
433
444
  pageSizeOptions?: number[];
434
445
  };
435
- declare function DataTablePagination<TData>({ table, pageSizeOptions, }: Props$1<TData>): react_jsx_runtime.JSX.Element;
446
+ declare function DataTablePagination<TData>({ table, pageSizeOptions, }: Props$1<TData>): React$1.JSX.Element;
436
447
 
437
448
  type ToolbarFeatureFlags = {
438
449
  search?: boolean;
@@ -468,7 +479,7 @@ type Props<TData> = {
468
479
  features?: ToolbarFeatureFlags;
469
480
  labels?: ToolbarLabels;
470
481
  };
471
- declare function DataTableToolbar<TData>({ table, totalRecords, isFetching, onRefresh, onAddRow, onBulkDelete, exportFileName, globalFilter, onGlobalFilterChange, toolbarSlot, features, labels: labelsProp, }: Props<TData>): react_jsx_runtime.JSX.Element;
482
+ declare function DataTableToolbar<TData>({ table, totalRecords, isFetching, onRefresh, onAddRow, onBulkDelete, exportFileName, globalFilter, onGlobalFilterChange, toolbarSlot, features, labels: labelsProp, }: Props<TData>): React$1.JSX.Element;
472
483
 
473
484
  type EditableCellProps<TData, TValue> = CellContext<TData, TValue> & {
474
485
  isEditing: boolean;
@@ -478,7 +489,7 @@ type EditableCellProps<TData, TValue> = CellContext<TData, TValue> & {
478
489
  onCancel: () => void;
479
490
  onStartEdit: () => void;
480
491
  };
481
- declare function EditableCell<TData, TValue>({ getValue, column, row, isEditing, autoOpen, onCommit, onCancel, onStartEdit, }: EditableCellProps<TData, TValue>): react_jsx_runtime.JSX.Element;
492
+ declare function EditableCell<TData, TValue>({ getValue, column, row, isEditing, autoOpen, onCommit, onCancel, onStartEdit, }: EditableCellProps<TData, TValue>): React$1.JSX.Element;
482
493
 
483
494
  type TextOp = "contains" | "notContains" | "equals" | "notEqual" | "startsWith" | "endsWith" | "blank" | "notBlank";
484
495
  type NumberOp = "equals" | "notEqual" | "lessThan" | "lessThanOrEqual" | "greaterThan" | "greaterThanOrEqual" | "inRange" | "blank" | "notBlank";
@@ -507,9 +518,11 @@ type CommonProps<TData, TValue> = {
507
518
  column: Column<TData, TValue>;
508
519
  onClose: () => void;
509
520
  };
510
- declare function ColumnFilterPanel<TData, TValue>(props: CommonProps<TData, TValue>): react_jsx_runtime.JSX.Element | null;
521
+ declare function ColumnFilterPanel<TData, TValue>(props: CommonProps<TData, TValue>): React$1.JSX.Element | null;
511
522
 
523
+ /** Neutralize spreadsheet formulas in untrusted text; preserve real numbers. */
524
+ declare function sanitizeSpreadsheetValue(value: unknown): string;
512
525
  declare function exportToCsv<TData>(table: Table<TData>, fileName?: string): void;
513
526
  declare function exportToExcel<TData>(table: Table<TData>, fileName?: string): void;
514
527
 
515
- export { type AdvFilter, type CellEditorType, ColumnFilterPanel, type Combine, type Condition, type ConfirmDeleteConfig, type ConfirmDeleteContext, type CustomRowAction, DataTable, type DataTableColumn, DataTableColumnHeader, type DataTableDataSource, type DataTableDataSourceResult, type DataTableDensity, type DataTableErrorContext, type DataTableFeatures, type DataTableFetchParams, type DataTableLabels, type DataTableModedTheme, DataTablePagination, type DataTableProps, DataTableRowActions, type DataTableRowActionsProps, type DataTableTheme, type DataTableThemeName, type DataTableTokens, DataTableToolbar, type DateOp, EditableCell, type FilterType, ISOLATE_DARK_TOKENS, ISOLATE_LIGHT_TOKENS, type NumberOp, PortalContainerContext, type RowAction, type RowActionId, type SelectOption, type SetFilter, type TextOp, type ViewSheetConfig, type ViewSheetDensity, type ViewSheetLabels, booleanFilterFn, buildPreset, dateFilterFn, exportToCsv, exportToExcel, isFilterActive, numberFilterFn, setFilterFn, splitTheme, textFilterFn, themePresets, themeToStyle, tokensToCssBlock, tokensToStyle, usePortalContainer };
528
+ export { type AdvFilter, type CellEditorType, ColumnFilterPanel, type Combine, type Condition, type ConfirmDeleteConfig, type ConfirmDeleteContext, type CustomRowAction, DataTable, type DataTableColumn, DataTableColumnHeader, type DataTableDataSource, type DataTableDataSourceResult, type DataTableDensity, type DataTableErrorContext, type DataTableFeatures, type DataTableFetchParams, type DataTableLabels, type DataTableModedTheme, DataTablePagination, type DataTableProps, DataTableRowActions, type DataTableRowActionsProps, type DataTableTheme, type DataTableThemeName, type DataTableTokens, DataTableToolbar, type DateOp, EditableCell, type FilterType, ISOLATE_DARK_TOKENS, ISOLATE_LIGHT_TOKENS, type NumberOp, PortalContainerContext, type RowAction, type RowActionId, type SelectOption, type SetFilter, type TextOp, type ViewSheetConfig, type ViewSheetDensity, type ViewSheetLabels, booleanFilterFn, buildPreset, dateFilterFn, exportToCsv, exportToExcel, isFilterActive, numberFilterFn, sanitizeSpreadsheetValue, setFilterFn, splitTheme, textFilterFn, themePresets, themeToStyle, tokensToCssBlock, tokensToStyle, usePortalContainer };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Column, RowData, ColumnDef, SortingState, ColumnFiltersState, ColumnPinningState, VisibilityState, Table, CellContext, FilterFn } from '@tanstack/react-table';
3
1
  import * as React$1 from 'react';
4
2
  import { CSSProperties } from 'react';
3
+ import { Column, RowData, ColumnDef, SortingState, ColumnFiltersState, ColumnPinningState, VisibilityState, Table, CellContext, FilterFn } from '@tanstack/react-table';
5
4
 
6
5
  type RowActionId = "view" | "edit" | "duplicate" | "delete" | string;
7
6
  type CustomRowAction<TData> = {
@@ -20,7 +19,7 @@ type DataTableRowActionsProps<TData> = {
20
19
  onSaveEdit?: () => void;
21
20
  onCancelEdit?: () => void;
22
21
  };
23
- declare function DataTableRowActions<TData>({ row, actions, customActions, onAction, isEditing, onSaveEdit, onCancelEdit, }: DataTableRowActionsProps<TData>): react_jsx_runtime.JSX.Element;
22
+ declare function DataTableRowActions<TData>({ row, actions, customActions, onAction, isEditing, onSaveEdit, onCancelEdit, }: DataTableRowActionsProps<TData>): React$1.JSX.Element;
24
23
 
25
24
  /**
26
25
  * CSS variable overrides for a single DataTable instance.
@@ -157,7 +156,7 @@ type ViewSheetLabels = {
157
156
  type ViewSheetConfig<TData> = {
158
157
  /** Side of the screen to slide in from. Defaults to "right". */
159
158
  side?: SheetSide;
160
- /** Initial column count. Defaults to "compact" (1 column). */
159
+ /** Initial layout density. Defaults to "compact" (more fields per row). */
161
160
  defaultDensity?: ViewSheetDensity;
162
161
  /** Hide the density tabs entirely if you want a fixed layout. */
163
162
  hideDensityTabs?: boolean;
@@ -357,6 +356,18 @@ type DataTableProps<TData extends {
357
356
  pageSizeOptions?: number[];
358
357
  initialColumnPinning?: ColumnPinningState;
359
358
  initialColumnVisibility?: VisibilityState;
359
+ /** Initial sort order. */
360
+ initialSorting?: SortingState;
361
+ /** Observe selected row objects (loaded rows only in server mode). */
362
+ onSelectionChange?: (rows: TData[]) => void;
363
+ /** Accessible table name. */
364
+ ariaLabel?: string;
365
+ /** Alternating row backgrounds. */
366
+ striped?: boolean;
367
+ /** Keep headers visible inside a vertically constrained table. */
368
+ stickyHeader?: boolean;
369
+ /** Scroll viewport height, e.g. "480px". */
370
+ maxHeight?: React.CSSProperties["maxHeight"];
360
371
  /** Optional controlled global filter (for cross-tab persistence). */
361
372
  globalFilter?: string;
362
373
  onGlobalFilterChange?: (value: string) => void;
@@ -396,7 +407,7 @@ type DataTableProps<TData extends {
396
407
  };
397
408
  declare function DataTable<TData extends {
398
409
  id: string | number;
399
- }>({ data, columns, dataSource, isLoading, isFetching, onRefresh, totalRecords, exportFileName, enableSelection, renderSubRow, getSubRows, rowActions, customRowActions, onRowAction, onCellEdit, onRowSave, onAddRow, onBulkDelete, initialPageSize, pageSizeOptions, initialColumnPinning, initialColumnVisibility, globalFilter: globalFilterProp, onGlobalFilterChange, className, toolbarSlot, features, labels: labelsProp, density, theme, isolate, onView, onDelete, viewSheet, confirmDelete, }: DataTableProps<TData>): react_jsx_runtime.JSX.Element;
410
+ }>({ data, columns, dataSource, isLoading, isFetching, onRefresh, totalRecords, exportFileName, enableSelection, renderSubRow, getSubRows, rowActions, customRowActions, onRowAction, onCellEdit, onRowSave, onAddRow, onBulkDelete, initialPageSize, pageSizeOptions, initialColumnPinning, initialColumnVisibility, initialSorting, onSelectionChange, ariaLabel, striped, stickyHeader, maxHeight, globalFilter: globalFilterProp, onGlobalFilterChange, className, toolbarSlot, features, labels: labelsProp, density, theme, isolate, onView, onDelete, viewSheet, confirmDelete, }: DataTableProps<TData>): React$1.JSX.Element;
400
411
 
401
412
  /**
402
413
  * Shared portal container for every overlay inside a DataTable (popover,
@@ -426,13 +437,13 @@ type Props$2<TData, TValue> = {
426
437
  column: Column<TData, TValue>;
427
438
  title: string;
428
439
  };
429
- declare function DataTableColumnHeader<TData, TValue>({ column, title, }: Props$2<TData, TValue>): react_jsx_runtime.JSX.Element;
440
+ declare function DataTableColumnHeader<TData, TValue>({ column, title, }: Props$2<TData, TValue>): React$1.JSX.Element;
430
441
 
431
442
  type Props$1<TData> = {
432
443
  table: Table<TData>;
433
444
  pageSizeOptions?: number[];
434
445
  };
435
- declare function DataTablePagination<TData>({ table, pageSizeOptions, }: Props$1<TData>): react_jsx_runtime.JSX.Element;
446
+ declare function DataTablePagination<TData>({ table, pageSizeOptions, }: Props$1<TData>): React$1.JSX.Element;
436
447
 
437
448
  type ToolbarFeatureFlags = {
438
449
  search?: boolean;
@@ -468,7 +479,7 @@ type Props<TData> = {
468
479
  features?: ToolbarFeatureFlags;
469
480
  labels?: ToolbarLabels;
470
481
  };
471
- declare function DataTableToolbar<TData>({ table, totalRecords, isFetching, onRefresh, onAddRow, onBulkDelete, exportFileName, globalFilter, onGlobalFilterChange, toolbarSlot, features, labels: labelsProp, }: Props<TData>): react_jsx_runtime.JSX.Element;
482
+ declare function DataTableToolbar<TData>({ table, totalRecords, isFetching, onRefresh, onAddRow, onBulkDelete, exportFileName, globalFilter, onGlobalFilterChange, toolbarSlot, features, labels: labelsProp, }: Props<TData>): React$1.JSX.Element;
472
483
 
473
484
  type EditableCellProps<TData, TValue> = CellContext<TData, TValue> & {
474
485
  isEditing: boolean;
@@ -478,7 +489,7 @@ type EditableCellProps<TData, TValue> = CellContext<TData, TValue> & {
478
489
  onCancel: () => void;
479
490
  onStartEdit: () => void;
480
491
  };
481
- declare function EditableCell<TData, TValue>({ getValue, column, row, isEditing, autoOpen, onCommit, onCancel, onStartEdit, }: EditableCellProps<TData, TValue>): react_jsx_runtime.JSX.Element;
492
+ declare function EditableCell<TData, TValue>({ getValue, column, row, isEditing, autoOpen, onCommit, onCancel, onStartEdit, }: EditableCellProps<TData, TValue>): React$1.JSX.Element;
482
493
 
483
494
  type TextOp = "contains" | "notContains" | "equals" | "notEqual" | "startsWith" | "endsWith" | "blank" | "notBlank";
484
495
  type NumberOp = "equals" | "notEqual" | "lessThan" | "lessThanOrEqual" | "greaterThan" | "greaterThanOrEqual" | "inRange" | "blank" | "notBlank";
@@ -507,9 +518,11 @@ type CommonProps<TData, TValue> = {
507
518
  column: Column<TData, TValue>;
508
519
  onClose: () => void;
509
520
  };
510
- declare function ColumnFilterPanel<TData, TValue>(props: CommonProps<TData, TValue>): react_jsx_runtime.JSX.Element | null;
521
+ declare function ColumnFilterPanel<TData, TValue>(props: CommonProps<TData, TValue>): React$1.JSX.Element | null;
511
522
 
523
+ /** Neutralize spreadsheet formulas in untrusted text; preserve real numbers. */
524
+ declare function sanitizeSpreadsheetValue(value: unknown): string;
512
525
  declare function exportToCsv<TData>(table: Table<TData>, fileName?: string): void;
513
526
  declare function exportToExcel<TData>(table: Table<TData>, fileName?: string): void;
514
527
 
515
- export { type AdvFilter, type CellEditorType, ColumnFilterPanel, type Combine, type Condition, type ConfirmDeleteConfig, type ConfirmDeleteContext, type CustomRowAction, DataTable, type DataTableColumn, DataTableColumnHeader, type DataTableDataSource, type DataTableDataSourceResult, type DataTableDensity, type DataTableErrorContext, type DataTableFeatures, type DataTableFetchParams, type DataTableLabels, type DataTableModedTheme, DataTablePagination, type DataTableProps, DataTableRowActions, type DataTableRowActionsProps, type DataTableTheme, type DataTableThemeName, type DataTableTokens, DataTableToolbar, type DateOp, EditableCell, type FilterType, ISOLATE_DARK_TOKENS, ISOLATE_LIGHT_TOKENS, type NumberOp, PortalContainerContext, type RowAction, type RowActionId, type SelectOption, type SetFilter, type TextOp, type ViewSheetConfig, type ViewSheetDensity, type ViewSheetLabels, booleanFilterFn, buildPreset, dateFilterFn, exportToCsv, exportToExcel, isFilterActive, numberFilterFn, setFilterFn, splitTheme, textFilterFn, themePresets, themeToStyle, tokensToCssBlock, tokensToStyle, usePortalContainer };
528
+ export { type AdvFilter, type CellEditorType, ColumnFilterPanel, type Combine, type Condition, type ConfirmDeleteConfig, type ConfirmDeleteContext, type CustomRowAction, DataTable, type DataTableColumn, DataTableColumnHeader, type DataTableDataSource, type DataTableDataSourceResult, type DataTableDensity, type DataTableErrorContext, type DataTableFeatures, type DataTableFetchParams, type DataTableLabels, type DataTableModedTheme, DataTablePagination, type DataTableProps, DataTableRowActions, type DataTableRowActionsProps, type DataTableTheme, type DataTableThemeName, type DataTableTokens, DataTableToolbar, type DateOp, EditableCell, type FilterType, ISOLATE_DARK_TOKENS, ISOLATE_LIGHT_TOKENS, type NumberOp, PortalContainerContext, type RowAction, type RowActionId, type SelectOption, type SetFilter, type TextOp, type ViewSheetConfig, type ViewSheetDensity, type ViewSheetLabels, booleanFilterFn, buildPreset, dateFilterFn, exportToCsv, exportToExcel, isFilterActive, numberFilterFn, sanitizeSpreadsheetValue, setFilterFn, splitTheme, textFilterFn, themePresets, themeToStyle, tokensToCssBlock, tokensToStyle, usePortalContainer };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createContext, useContext, useState, useRef, useEffect, useMemo, useLayoutEffect, useId } from 'react';
2
2
  import { useReactTable, getPaginationRowModel, getExpandedRowModel, getSortedRowModel, getFilteredRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
3
- import { Trash2Icon, XIcon, SearchIcon, RefreshCwIcon, ColumnsIcon, DownloadIcon, FileTextIcon, FileSpreadsheetIcon, PlusIcon, ChevronsLeftIcon, ChevronLeftIcon, ChevronRightIcon, ChevronsRightIcon, ArrowDownIcon, ArrowUpIcon, ChevronsUpDownIcon, PinOffIcon, PinIcon, EyeOffIcon, FilterIcon, CheckIcon, MoreHorizontalIcon, ChevronDownIcon, GripVerticalIcon, Loader2Icon, MinusIcon, CopyIcon, PencilIcon, EyeIcon, ChevronUpIcon, LayoutGridIcon, Rows3Icon, ListIcon } from 'lucide-react';
3
+ import { Trash2Icon, XIcon, SearchIcon, RefreshCwIcon, ColumnsIcon, DownloadIcon, FileTextIcon, FileSpreadsheetIcon, PlusIcon, ChevronsLeftIcon, ChevronLeftIcon, ChevronRightIcon, ChevronsRightIcon, ArrowDownIcon, ArrowUpIcon, ChevronsUpDownIcon, PinOffIcon, PinIcon, EyeOffIcon, FilterIcon, CheckIcon, MoreHorizontalIcon, ChevronDownIcon, GripVerticalIcon, Loader2Icon, MinusIcon, CopyIcon, PencilIcon, EyeIcon, ChevronUpIcon, ListIcon, Rows3Icon, LayoutGridIcon } from 'lucide-react';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { Slot, Separator as Separator$1, Popover as Popover$1, Checkbox as Checkbox$1, DropdownMenu as DropdownMenu$1, Select as Select$1, Dialog, AlertDialog as AlertDialog$1 } from 'radix-ui';
@@ -281,15 +281,21 @@ function PopoverContent({
281
281
  }
282
282
 
283
283
  // src/export.ts
284
+ function sanitizeSpreadsheetValue(value) {
285
+ if (value == null) return "";
286
+ const text = String(value);
287
+ if (typeof value === "string" && (/^[\s\u0000-\u001f]*[=+\-@=+-@]/u.test(text) || /^[\t\r\n]/.test(text))) return `'${text}`;
288
+ return text;
289
+ }
284
290
  function escapeCsv(value) {
285
291
  if (value === null || value === void 0) return "";
286
- const s = String(value);
292
+ const s = sanitizeSpreadsheetValue(value);
287
293
  if (/[",\n\r]/.test(s)) return `"${s.replace(/"/g, '""')}"`;
288
294
  return s;
289
295
  }
290
296
  function escapeHtml(value) {
291
297
  if (value === null || value === void 0) return "";
292
- return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
298
+ return sanitizeSpreadsheetValue(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
293
299
  }
294
300
  function getExportRows(table) {
295
301
  const visible = table.getVisibleLeafColumns().filter((c) => {
@@ -1899,7 +1905,7 @@ function EditableCell({
1899
1905
  if (typeof flag === "function") return flag(row.original);
1900
1906
  return flag;
1901
1907
  })();
1902
- if (!isEditing) {
1908
+ if (!isEditing || !isEditable) {
1903
1909
  const display = renderDisplay(initial, editor, meta);
1904
1910
  return /* @__PURE__ */ jsx(
1905
1911
  "div",
@@ -1916,7 +1922,9 @@ function EditableCell({
1916
1922
  }
1917
1923
  );
1918
1924
  }
1919
- const commit = (value) => onCommit(value);
1925
+ const commit = (value) => {
1926
+ if (isEditable) onCommit(value);
1927
+ };
1920
1928
  const handleKey = (e) => {
1921
1929
  if (e.key === "Enter") commit(local);
1922
1930
  else if (e.key === "Escape") onCancel();
@@ -2046,6 +2054,9 @@ var TOKEN_TO_VAR = {
2046
2054
  radius: "--radius",
2047
2055
  fontFamily: "--font-family"
2048
2056
  };
2057
+ function isSafeToken(value) {
2058
+ return typeof value === "string" && !/[;{}<>@\\\u0000-\u001f]/.test(value) && !/\/\*|\*\/|url\s*\(|expression\s*\(/i.test(value);
2059
+ }
2049
2060
  function isModed(theme) {
2050
2061
  if (!theme) return false;
2051
2062
  return "light" in theme || "dark" in theme;
@@ -2054,8 +2065,8 @@ function tokensToStyle(tokens) {
2054
2065
  if (!tokens) return {};
2055
2066
  const out = {};
2056
2067
  for (const [k, v] of Object.entries(tokens)) {
2057
- if (v == null) continue;
2058
- const cssVar = TOKEN_TO_VAR[k];
2068
+ if (!isSafeToken(v)) continue;
2069
+ const cssVar = Object.prototype.hasOwnProperty.call(TOKEN_TO_VAR, k) ? TOKEN_TO_VAR[k] : void 0;
2059
2070
  if (cssVar) out[cssVar] = v;
2060
2071
  }
2061
2072
  return out;
@@ -2129,8 +2140,8 @@ function tokensToCssBlock(tokens) {
2129
2140
  if (!tokens) return "";
2130
2141
  const parts = [];
2131
2142
  for (const [k, v] of Object.entries(tokens)) {
2132
- if (v == null) continue;
2133
- const cssVar = TOKEN_TO_VAR[k];
2143
+ if (!isSafeToken(v)) continue;
2144
+ const cssVar = Object.prototype.hasOwnProperty.call(TOKEN_TO_VAR, k) ? TOKEN_TO_VAR[k] : void 0;
2134
2145
  if (cssVar) parts.push(`${cssVar}:${v}`);
2135
2146
  }
2136
2147
  return parts.join(";");
@@ -2214,8 +2225,8 @@ function SheetOverlay({
2214
2225
  );
2215
2226
  }
2216
2227
  var SIDE_CLASS = {
2217
- right: "right-0 top-0 h-full w-3/4 max-w-md border-l data-closed:slide-out-to-right data-open:slide-in-from-right",
2218
- left: "left-0 top-0 h-full w-3/4 max-w-md border-r data-closed:slide-out-to-left data-open:slide-in-from-left",
2228
+ right: "right-0 top-0 h-full w-full border-l sm:w-[min(48rem,calc(100vw-2rem))] data-closed:slide-out-to-right data-open:slide-in-from-right",
2229
+ left: "left-0 top-0 h-full w-full border-r sm:w-[min(48rem,calc(100vw-2rem))] data-closed:slide-out-to-left data-open:slide-in-from-left",
2219
2230
  top: "left-0 top-0 w-full max-h-[80vh] border-b data-closed:slide-out-to-top data-open:slide-in-from-top",
2220
2231
  bottom: "left-0 bottom-0 w-full max-h-[80vh] border-t data-closed:slide-out-to-bottom data-open:slide-in-from-bottom"
2221
2232
  };
@@ -2290,14 +2301,19 @@ function SheetDescription({
2290
2301
  );
2291
2302
  }
2292
2303
  var COLS_CLASS = {
2293
- compact: "grid-cols-1",
2304
+ compact: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
2294
2305
  relaxed: "grid-cols-1 sm:grid-cols-2",
2295
- comfy: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
2306
+ comfy: "grid-cols-1"
2307
+ };
2308
+ var CARD_CLASS = {
2309
+ compact: "gap-0.5 p-2.5",
2310
+ relaxed: "gap-1 p-3",
2311
+ comfy: "gap-1.5 p-4"
2296
2312
  };
2297
2313
  var DENSITY_ICON = {
2298
- compact: /* @__PURE__ */ jsx(ListIcon, { className: "size-3.5" }),
2314
+ compact: /* @__PURE__ */ jsx(LayoutGridIcon, { className: "size-3.5" }),
2299
2315
  relaxed: /* @__PURE__ */ jsx(Rows3Icon, { className: "size-3.5" }),
2300
- comfy: /* @__PURE__ */ jsx(LayoutGridIcon, { className: "size-3.5" })
2316
+ comfy: /* @__PURE__ */ jsx(ListIcon, { className: "size-3.5" })
2301
2317
  };
2302
2318
  function DataTableViewSheet({
2303
2319
  table,
@@ -2370,10 +2386,13 @@ function DataTableViewSheet({
2370
2386
  return /* @__PURE__ */ jsxs(
2371
2387
  "div",
2372
2388
  {
2373
- className: "flex flex-col gap-0.5 rounded-md border bg-card p-2.5",
2389
+ className: cn(
2390
+ "flex min-w-0 flex-col rounded-md border bg-card",
2391
+ CARD_CLASS[density]
2392
+ ),
2374
2393
  children: [
2375
2394
  /* @__PURE__ */ jsx("span", { className: "text-[11px] uppercase tracking-wide text-muted-foreground", children: headerLabel }),
2376
- /* @__PURE__ */ jsx("span", { className: "text-sm text-foreground break-words", children: rendered })
2395
+ /* @__PURE__ */ jsx("span", { className: "break-words text-sm text-foreground", children: rendered })
2377
2396
  ]
2378
2397
  },
2379
2398
  colId
@@ -2398,11 +2417,15 @@ function AlertDialogContent({
2398
2417
  ...props
2399
2418
  }) {
2400
2419
  const container = usePortalContainer();
2420
+ const positionClass = container ? "absolute" : "fixed";
2401
2421
  return /* @__PURE__ */ jsxs(AlertDialog$1.Portal, { container: container ?? void 0, children: [
2402
2422
  /* @__PURE__ */ jsx(
2403
2423
  AlertDialog$1.Overlay,
2404
2424
  {
2405
- className: "fixed inset-0 z-50 bg-foreground/30 backdrop-blur-sm data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0"
2425
+ className: cn(
2426
+ "inset-0 z-50 bg-foreground/30 backdrop-blur-sm data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
2427
+ positionClass
2428
+ )
2406
2429
  }
2407
2430
  ),
2408
2431
  /* @__PURE__ */ jsx(
@@ -2410,7 +2433,8 @@ function AlertDialogContent({
2410
2433
  {
2411
2434
  "data-slot": "alert-dialog-content",
2412
2435
  className: cn(
2413
- "fixed top-1/2 left-1/2 z-50 grid w-full max-w-md -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg border bg-background p-6 shadow-lg outline-none data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
2436
+ "top-1/2 left-1/2 z-50 grid w-[calc(100%-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg border bg-background p-6 shadow-lg outline-none data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
2437
+ positionClass,
2414
2438
  className
2415
2439
  ),
2416
2440
  ...props,
@@ -2541,6 +2565,10 @@ function useEditingContext() {
2541
2565
  if (!ctx) throw new Error("DataTable editing context missing");
2542
2566
  return ctx;
2543
2567
  }
2568
+ function DefaultCellHost(ctx) {
2569
+ const value = ctx.getValue();
2570
+ return value == null ? null : String(value);
2571
+ }
2544
2572
  function EditableCellHost(ctx) {
2545
2573
  const {
2546
2574
  editingCell,
@@ -2629,6 +2657,7 @@ function ActionsCellHost({ row }) {
2629
2657
  onView?.(row.original);
2630
2658
  } else if (a === "delete") {
2631
2659
  onRequestDelete?.(row.original);
2660
+ return;
2632
2661
  }
2633
2662
  onRowAction?.(a, row.original);
2634
2663
  }
@@ -2661,6 +2690,7 @@ var DENSITY_CLASS = {
2661
2690
  default: "",
2662
2691
  comfortable: "[&_tbody_td]:py-2"
2663
2692
  };
2693
+ var EMPTY_DATA = [];
2664
2694
  function DataTable({
2665
2695
  data,
2666
2696
  columns,
@@ -2684,6 +2714,12 @@ function DataTable({
2684
2714
  pageSizeOptions,
2685
2715
  initialColumnPinning,
2686
2716
  initialColumnVisibility,
2717
+ initialSorting,
2718
+ onSelectionChange,
2719
+ ariaLabel = "Data table",
2720
+ striped = false,
2721
+ stickyHeader = false,
2722
+ maxHeight,
2687
2723
  globalFilter: globalFilterProp,
2688
2724
  onGlobalFilterChange,
2689
2725
  className,
@@ -2760,7 +2796,7 @@ function DataTable({
2760
2796
  }
2761
2797
  setConfirmCtx(null);
2762
2798
  };
2763
- const [sorting, setSorting] = useState([]);
2799
+ const [sorting, setSorting] = useState(initialSorting ?? []);
2764
2800
  const [columnFilters, setColumnFilters] = useState([]);
2765
2801
  const [internalGlobalFilter, setInternalGlobalFilter] = useState("");
2766
2802
  const isControlledFilter = globalFilterProp !== void 0;
@@ -2856,7 +2892,7 @@ function DataTable({
2856
2892
  // eslint-disable-next-line react-hooks/exhaustive-deps
2857
2893
  ...dataSourceDeps
2858
2894
  ]);
2859
- const baseData = dataSourceEnabled ? sourceRows : data ?? [];
2895
+ const baseData = dataSourceEnabled ? sourceRows : data ?? EMPTY_DATA;
2860
2896
  const effectiveIsLoading = dataSourceEnabled ? sourceLoading : isLoading;
2861
2897
  const effectiveIsFetching = dataSourceEnabled ? sourceFetching : isFetching;
2862
2898
  const effectiveOnRefresh = dataSourceEnabled ? () => setSourceRefreshKey((key) => key + 1) : onRefresh;
@@ -2900,7 +2936,7 @@ function DataTable({
2900
2936
  title: headerLabel
2901
2937
  }
2902
2938
  ),
2903
- cell: hasEditor ? EditableCellHost : original
2939
+ cell: hasEditor ? EditableCellHost : original ?? DefaultCellHost
2904
2940
  };
2905
2941
  };
2906
2942
  const built = columns.map(wrap);
@@ -3012,10 +3048,10 @@ function DataTable({
3012
3048
  enableColumnFilters: f.filtering,
3013
3049
  enableColumnResizing: f.resizing,
3014
3050
  columnResizeMode: "onChange",
3015
- enableRowSelection: true,
3051
+ enableRowSelection: enableSelection,
3016
3052
  enableExpanding: !!(renderSubRow || getSubRows),
3017
3053
  enablePinning: f.pinning,
3018
- manualPagination: isServerSideDataSource,
3054
+ manualPagination: isServerSideDataSource || !f.pagination,
3019
3055
  manualSorting: isServerSideDataSource,
3020
3056
  manualFiltering: isServerSideDataSource,
3021
3057
  pageCount: isServerSideDataSource ? Math.max(1, Math.ceil(effectiveTotalRecords / pagination.pageSize)) : void 0,
@@ -3105,6 +3141,11 @@ function DataTable({
3105
3141
  setEditingRowId(tempId);
3106
3142
  } : void 0;
3107
3143
  const rows = table.getRowModel().rows;
3144
+ const selectionCallback = useRef(onSelectionChange);
3145
+ selectionCallback.current = onSelectionChange;
3146
+ useEffect(() => {
3147
+ selectionCallback.current?.(table.getSelectedRowModel().flatRows.map((row) => row.original));
3148
+ }, [rowSelection, mergedData, table]);
3108
3149
  const visibleLeafCount = table.getVisibleLeafColumns().length;
3109
3150
  const editingContextValue = useMemo(
3110
3151
  () => ({
@@ -3182,17 +3223,18 @@ function DataTable({
3182
3223
  labels
3183
3224
  }
3184
3225
  ),
3185
- /* @__PURE__ */ jsxs("div", { className: "relative w-full overflow-auto", children: [
3226
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full overflow-auto", style: { maxHeight }, children: [
3186
3227
  /* @__PURE__ */ jsxs(
3187
3228
  "table",
3188
3229
  {
3189
- className: "w-full caption-bottom text-sm",
3230
+ "aria-label": ariaLabel,
3231
+ className: cn("w-full caption-bottom text-sm", striped && "[&_tbody>tr:nth-child(even)]:bg-muted/25"),
3190
3232
  style: {
3191
3233
  width: table.getCenterTotalSize() ? void 0 : "100%",
3192
3234
  minWidth: "100%"
3193
3235
  },
3194
3236
  children: [
3195
- /* @__PURE__ */ jsx("thead", { className: "sticky top-0 z-10 bg-card/95 backdrop-blur supports-[backdrop-filter]:bg-card/70", children: table.getHeaderGroups().map((hg) => /* @__PURE__ */ jsx("tr", { className: "border-b", children: hg.headers.map((header) => {
3237
+ /* @__PURE__ */ jsx("thead", { className: cn("bg-card", stickyHeader && "sticky top-0 z-10"), children: table.getHeaderGroups().map((hg) => /* @__PURE__ */ jsx("tr", { className: "border-b", children: hg.headers.map((header) => {
3196
3238
  const meta = header.column.columnDef.meta;
3197
3239
  const isUtility = header.column.id === "__select" || header.column.id === "__expand" || header.column.id === "__actions";
3198
3240
  const isPinned = !!header.column.getIsPinned();
@@ -3368,6 +3410,6 @@ function renderSkeleton(cols, rows) {
3368
3410
  return Array.from({ length: rows }).map((_, r) => /* @__PURE__ */ jsx("tr", { className: "border-b", children: Array.from({ length: cols }).map((__, c) => /* @__PURE__ */ jsx("td", { className: "px-2 py-2", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }) }, c)) }, r));
3369
3411
  }
3370
3412
 
3371
- export { ColumnFilterPanel, DataTable, DataTableColumnHeader, DataTablePagination, DataTableRowActions, DataTableToolbar, EditableCell, ISOLATE_DARK_TOKENS, ISOLATE_LIGHT_TOKENS, PortalContainerContext, booleanFilterFn, buildPreset, dateFilterFn, exportToCsv, exportToExcel, isFilterActive, numberFilterFn, setFilterFn, splitTheme, textFilterFn, themePresets, themeToStyle, tokensToCssBlock, tokensToStyle, usePortalContainer };
3413
+ export { ColumnFilterPanel, DataTable, DataTableColumnHeader, DataTablePagination, DataTableRowActions, DataTableToolbar, EditableCell, ISOLATE_DARK_TOKENS, ISOLATE_LIGHT_TOKENS, PortalContainerContext, booleanFilterFn, buildPreset, dateFilterFn, exportToCsv, exportToExcel, isFilterActive, numberFilterFn, sanitizeSpreadsheetValue, setFilterFn, splitTheme, textFilterFn, themePresets, themeToStyle, tokensToCssBlock, tokensToStyle, usePortalContainer };
3372
3414
  //# sourceMappingURL=index.js.map
3373
3415
  //# sourceMappingURL=index.js.map