@bmsuisse/datagrid 0.40.0 → 0.41.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.ts CHANGED
@@ -1687,6 +1687,23 @@ interface DataGridProps<TRow> {
1687
1687
  */
1688
1688
  selectedIds?: ReadonlySet<string>;
1689
1689
  onSelectedIdsChange?: (ids: ReadonlySet<string>) => void;
1690
+ /**
1691
+ * `"multiple"` (default) renders a checkbox per row plus a select-all in the
1692
+ * header. `"single"` renders a radio per row instead, selects exactly one
1693
+ * row (choosing another replaces it; a radio can't be cleared by clicking
1694
+ * it again), and leaves the header cell empty. Setting `"single"` shows the
1695
+ * selection column even when neither `selectedIds` nor `headerActions` is
1696
+ * supplied; the selection itself is still read through `selectedIds` /
1697
+ * `onSelectedIdsChange`, which hold at most one id in this mode.
1698
+ */
1699
+ selectionMode?: "multiple" | "single";
1700
+ /**
1701
+ * Caps the height of the scroll container (px number or any CSS length such
1702
+ * as `"65vh"`) without needing `virtualize` — the header stays sticky while
1703
+ * the rows scroll under it. Ignored when `virtualize` is active, which uses
1704
+ * `virtualize.maxBodyHeight` instead. Omit for a grid that grows with its rows.
1705
+ */
1706
+ maxHeight?: number | string;
1690
1707
  /**
1691
1708
  * Extra props (className, onClick, data-* attributes, etc.) spread onto a
1692
1709
  * row's own `<tr>`. Applied AFTER `<DataGrid>`'s own `data-testid`/
@@ -1838,7 +1855,7 @@ interface DataGridProps<TRow> {
1838
1855
  * (`"server"`). Column filter UI defaults to the type-appropriate widget
1839
1856
  * from `src/filter` unless a column supplies its own `cell` renderer.
1840
1857
  */
1841
- declare function DataGrid<TRow extends RowData>({ columns, dataSource, getRowId, rowActions, headerActions, enableMultiSort, initialState, columnVisibility, renderDetail, enableColumnResizing, columnResizeMode, columnSizing: controlledColumnSizing, onColumnSizingChange, virtualize, showPagination, getRowProps, getRowTestId, gridState, onGridStateChange, selectedIds: controlledSelectedIds, onSelectedIdsChange, testId, loading: loadingProp, error, onRetry, statusLabels, groupBy, renderGroupHeader, defaultGroupsExpanded, expandedGroups: controlledExpandedGroups, onExpandedGroupsChange, zebra, showTotals, editing, cellEditing, filterLabels, }: DataGridProps<TRow>): ReactElement;
1858
+ declare function DataGrid<TRow extends RowData>({ columns, dataSource, getRowId, rowActions, headerActions, enableMultiSort, initialState, columnVisibility, renderDetail, enableColumnResizing, columnResizeMode, columnSizing: controlledColumnSizing, onColumnSizingChange, virtualize, showPagination, getRowProps, getRowTestId, gridState, onGridStateChange, selectedIds: controlledSelectedIds, onSelectedIdsChange, selectionMode, maxHeight, testId, loading: loadingProp, error, onRetry, statusLabels, groupBy, renderGroupHeader, defaultGroupsExpanded, expandedGroups: controlledExpandedGroups, onExpandedGroupsChange, zebra, showTotals, editing, cellEditing, filterLabels, }: DataGridProps<TRow>): ReactElement;
1842
1859
 
1843
1860
  interface GridStateController {
1844
1861
  state: GridState;
package/dist/index.js CHANGED
@@ -3267,7 +3267,7 @@ function GridInlineError({
3267
3267
  }
3268
3268
 
3269
3269
  // src/grid/DataGrid.tsx
3270
- import { Fragment as Fragment3, useEffect as useEffect12, useMemo as useMemo9, useRef as useRef13, useState as useState16 } from "react";
3270
+ import { Fragment as Fragment3, useEffect as useEffect12, useId as useId4, useMemo as useMemo9, useRef as useRef13, useState as useState16 } from "react";
3271
3271
 
3272
3272
  // src/cell-editing/renderAlwaysEditCell.tsx
3273
3273
  import {
@@ -3689,6 +3689,8 @@ function DataGrid({
3689
3689
  onGridStateChange,
3690
3690
  selectedIds: controlledSelectedIds,
3691
3691
  onSelectedIdsChange,
3692
+ selectionMode = "multiple",
3693
+ maxHeight,
3692
3694
  testId,
3693
3695
  loading: loadingProp = false,
3694
3696
  error,
@@ -3715,11 +3717,18 @@ function DataGrid({
3715
3717
  onGridStateChange
3716
3718
  );
3717
3719
  const [internalSelectedIds, setInternalSelectedIds] = useState16(/* @__PURE__ */ new Set());
3718
- const selectedIds = controlledSelectedIds ?? internalSelectedIds;
3720
+ const rawSelectedIds = controlledSelectedIds ?? internalSelectedIds;
3721
+ const selectedIds = useMemo9(
3722
+ () => selectionMode === "single" && rawSelectedIds.size > 1 ? new Set([...rawSelectedIds].slice(0, 1)) : rawSelectedIds,
3723
+ [selectionMode, rawSelectedIds]
3724
+ );
3719
3725
  function updateSelectedIds(next) {
3720
3726
  setInternalSelectedIds(next);
3721
3727
  onSelectedIdsChange?.(next);
3722
3728
  }
3729
+ useEffect12(() => {
3730
+ if (selectedIds !== rawSelectedIds) updateSelectedIds(selectedIds);
3731
+ }, [selectedIds, rawSelectedIds]);
3723
3732
  const [internalColumnSizing, setInternalColumnSizing] = useState16({});
3724
3733
  const columnSizing = controlledColumnSizing ?? internalColumnSizing;
3725
3734
  function updateColumnSizing(next) {
@@ -3760,7 +3769,13 @@ function DataGrid({
3760
3769
  [rows, selectedIds, getRowId]
3761
3770
  );
3762
3771
  const allOnPageSelected = rows.length > 0 && rows.every((row) => selectedIds.has(getRowId(row)));
3772
+ const singleSelect = selectionMode === "single";
3773
+ const selectionGroupName = useId4();
3763
3774
  function toggleRowSelected(id) {
3775
+ if (singleSelect) {
3776
+ updateSelectedIds(/* @__PURE__ */ new Set([id]));
3777
+ return;
3778
+ }
3764
3779
  const next = new Set(selectedIds);
3765
3780
  if (next.has(id)) next.delete(id);
3766
3781
  else next.add(id);
@@ -3803,7 +3818,7 @@ function DataGrid({
3803
3818
  const labels = resolveStatusLabels(statusLabels);
3804
3819
  const hasError = toErrorInfo(error) !== void 0;
3805
3820
  const loading = loadingProp || (dataSource.mode === "server" ? Boolean(dataSource.loading) : false);
3806
- const showSelectionColumn = Boolean(headerActions?.length) || controlledSelectedIds !== void 0;
3821
+ const showSelectionColumn = Boolean(headerActions?.length) || controlledSelectedIds !== void 0 || selectionMode === "single";
3807
3822
  const showRowActionsColumn = Boolean(rowActions?.length);
3808
3823
  const showDetailColumn = Boolean(renderDetail);
3809
3824
  const totalColumnCount = visibleColumns.length + (showDetailColumn ? 1 : 0) + (showSelectionColumn ? 1 : 0) + (showRowActionsColumn ? 1 : 0);
@@ -4124,6 +4139,8 @@ function DataGrid({
4124
4139
  }
4125
4140
  function handleCellKeyDown(event) {
4126
4141
  if (!hasCellEditing || !cellEditingCtx) return;
4142
+ if (event.target instanceof HTMLInputElement && (event.target.type === "radio" || event.target.type === "checkbox") && !event.target.closest("[data-cell-row]"))
4143
+ return;
4127
4144
  if (cellEditingCtx.alwaysEdit) return;
4128
4145
  if (cellEditingCtx.editingCell && !cellEditingCtx.consumeJustCommitted()) return;
4129
4146
  const direction = CELL_NAV_KEYS[event.key];
@@ -4253,7 +4270,8 @@ function DataGrid({
4253
4270
  children: /* @__PURE__ */ jsx35(
4254
4271
  "input",
4255
4272
  {
4256
- type: "checkbox",
4273
+ type: singleSelect ? "radio" : "checkbox",
4274
+ name: singleSelect ? selectionGroupName : void 0,
4257
4275
  "aria-label": `Select row ${row.id}`,
4258
4276
  checked: selectedIds.has(row.id),
4259
4277
  onClick: stopRowClick,
@@ -4432,7 +4450,7 @@ function DataGrid({
4432
4450
  "h-full overflow-auto rounded-md border",
4433
4451
  hasCellEditing && "relative"
4434
4452
  ),
4435
- style: shouldVirtualize ? { maxHeight: virtualize?.maxBodyHeight ?? 480 } : void 0,
4453
+ style: shouldVirtualize ? { maxHeight: virtualize?.maxBodyHeight ?? 480 } : maxHeight !== void 0 ? { maxHeight } : void 0,
4436
4454
  tabIndex: hasCellEditing ? 0 : void 0,
4437
4455
  onMouseDown: hasCellEditing ? handleCellMouseDown : void 0,
4438
4456
  onDoubleClick: hasCellEditing ? handleCellDoubleClick : void 0,
@@ -4550,7 +4568,7 @@ function DataGrid({
4550
4568
  rowSpan: 2,
4551
4569
  className: selectionHeaderCellProps.className,
4552
4570
  style: selectionHeaderCellProps.style,
4553
- children: /* @__PURE__ */ jsx35(
4571
+ children: !singleSelect && /* @__PURE__ */ jsx35(
4554
4572
  "input",
4555
4573
  {
4556
4574
  type: "checkbox",
@@ -4596,7 +4614,7 @@ function DataGrid({
4596
4614
  {
4597
4615
  className: selectionHeaderCellProps.className,
4598
4616
  style: selectionHeaderCellProps.style,
4599
- children: /* @__PURE__ */ jsx35(
4617
+ children: !singleSelect && /* @__PURE__ */ jsx35(
4600
4618
  "input",
4601
4619
  {
4602
4620
  type: "checkbox",