@bmsuisse/datagrid 0.23.0 → 0.23.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/index.d.ts CHANGED
@@ -772,7 +772,7 @@ interface DataGridProps<TRow> {
772
772
  * (`"server"`). Column filter UI defaults to the type-appropriate widget
773
773
  * from `src/filter` unless a column supplies its own `cell` renderer.
774
774
  */
775
- declare function DataGrid<TRow extends RowData>({ columns, dataSource, getRowId, rowActions, headerActions, enableMultiSort, initialState, columnVisibility, renderDetail, enableColumnResizing, columnResizeMode, columnSizing, onColumnSizingChange, virtualize, showPagination, getRowProps, getRowTestId, gridState, selectedIds: controlledSelectedIds, onSelectedIdsChange, testId, loading: loadingProp, }: DataGridProps<TRow>): ReactElement;
775
+ 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, selectedIds: controlledSelectedIds, onSelectedIdsChange, testId, loading: loadingProp, }: DataGridProps<TRow>): ReactElement;
776
776
 
777
777
  interface GridStateController {
778
778
  state: GridState;
package/dist/index.js CHANGED
@@ -1743,9 +1743,12 @@ function useGridState(dataSource, initialState, externalState) {
1743
1743
  import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
1744
1744
  var gridTableFeatures = tableFeatures({ columnSizingFeature, columnResizingFeature });
1745
1745
  var DEFAULT_COLUMN_SIZE = 150;
1746
- function pinnedOffsets(visibleColumns, side, getSize) {
1746
+ var DETAIL_COLUMN_WIDTH = 44;
1747
+ var SELECTION_COLUMN_WIDTH = 44;
1748
+ var ROW_ACTIONS_COLUMN_WIDTH = 44;
1749
+ function pinnedOffsets(visibleColumns, side, getSize, leadingOffset) {
1747
1750
  const offsets = /* @__PURE__ */ new Map();
1748
- let cursor = 0;
1751
+ let cursor = leadingOffset;
1749
1752
  const ordered = side === "left" ? visibleColumns : [...visibleColumns].reverse();
1750
1753
  for (const column of ordered) {
1751
1754
  if (column.pinned !== side) continue;
@@ -1789,7 +1792,7 @@ function DataGrid({
1789
1792
  renderDetail,
1790
1793
  enableColumnResizing = false,
1791
1794
  columnResizeMode = "onChange",
1792
- columnSizing,
1795
+ columnSizing: controlledColumnSizing,
1793
1796
  onColumnSizingChange,
1794
1797
  virtualize,
1795
1798
  showPagination = true,
@@ -1812,6 +1815,12 @@ function DataGrid({
1812
1815
  setInternalSelectedIds(next);
1813
1816
  onSelectedIdsChange?.(next);
1814
1817
  }
1818
+ const [internalColumnSizing, setInternalColumnSizing] = useState6({});
1819
+ const columnSizing = controlledColumnSizing ?? internalColumnSizing;
1820
+ function updateColumnSizing(next) {
1821
+ setInternalColumnSizing(next);
1822
+ onColumnSizingChange?.(next);
1823
+ }
1815
1824
  const [expandedIds, setExpandedIds] = useState6(/* @__PURE__ */ new Set());
1816
1825
  function toggleRowExpanded(id) {
1817
1826
  setExpandedIds((prev) => {
@@ -1862,13 +1871,11 @@ function DataGrid({
1862
1871
  getRowId,
1863
1872
  enableColumnResizing,
1864
1873
  columnResizeMode,
1865
- ...columnSizing ? {
1866
- state: { columnSizing },
1867
- onColumnSizingChange: (updater) => {
1868
- const next = typeof updater === "function" ? updater(columnSizing) : updater;
1869
- onColumnSizingChange?.(next);
1870
- }
1871
- } : {}
1874
+ state: { columnSizing },
1875
+ onColumnSizingChange: (updater) => {
1876
+ const next = typeof updater === "function" ? updater(columnSizing) : updater;
1877
+ updateColumnSizing(next);
1878
+ }
1872
1879
  });
1873
1880
  const pageCount = Math.max(1, Math.ceil(rowCount / state.pageSize));
1874
1881
  const loading = loadingProp || (dataSource.mode === "server" ? Boolean(dataSource.loading) : false);
@@ -1885,8 +1892,10 @@ function DataGrid({
1885
1892
  return column.renderFilter ? column.renderFilter(value, onChange, state.filter) : renderDefaultFilterWidget(column, value, onChange);
1886
1893
  }
1887
1894
  const columnSize = (columnId) => table.getColumn(columnId)?.getSize() ?? DEFAULT_COLUMN_SIZE;
1888
- const leftPinnedOffsets = pinnedOffsets(visibleColumns, "left", columnSize);
1889
- const rightPinnedOffsets = pinnedOffsets(visibleColumns, "right", columnSize);
1895
+ const leadingStructuralWidth = (showDetailColumn ? DETAIL_COLUMN_WIDTH : 0) + (showSelectionColumn ? SELECTION_COLUMN_WIDTH : 0);
1896
+ const trailingStructuralWidth = showRowActionsColumn ? ROW_ACTIONS_COLUMN_WIDTH : 0;
1897
+ const leftPinnedOffsets = pinnedOffsets(visibleColumns, "left", columnSize, leadingStructuralWidth);
1898
+ const rightPinnedOffsets = pinnedOffsets(visibleColumns, "right", columnSize, trailingStructuralWidth);
1890
1899
  function pinnedCellProps(column, area = "body") {
1891
1900
  const bg = area === "header" ? "bg-muted" : "bg-background";
1892
1901
  if (column.pinned === "left") {
@@ -1898,6 +1907,25 @@ function DataGrid({
1898
1907
  if (enableColumnResizing) return { style: { width: columnSize(column.id) } };
1899
1908
  return { style: column.width ? { width: column.width } : void 0 };
1900
1909
  }
1910
+ function structuralCellProps(side, offset, width, area = "body") {
1911
+ const bg = area === "header" ? "bg-muted" : "bg-background";
1912
+ return { className: cn("sticky z-10", bg), style: { [side]: offset, width } };
1913
+ }
1914
+ const detailCellProps = structuralCellProps("left", 0, DETAIL_COLUMN_WIDTH);
1915
+ const selectionCellProps = structuralCellProps(
1916
+ "left",
1917
+ showDetailColumn ? DETAIL_COLUMN_WIDTH : 0,
1918
+ SELECTION_COLUMN_WIDTH
1919
+ );
1920
+ const rowActionsCellProps = structuralCellProps("right", 0, ROW_ACTIONS_COLUMN_WIDTH);
1921
+ const detailHeaderCellProps = structuralCellProps("left", 0, DETAIL_COLUMN_WIDTH, "header");
1922
+ const selectionHeaderCellProps = structuralCellProps(
1923
+ "left",
1924
+ showDetailColumn ? DETAIL_COLUMN_WIDTH : 0,
1925
+ SELECTION_COLUMN_WIDTH,
1926
+ "header"
1927
+ );
1928
+ const rowActionsHeaderCellProps = structuralCellProps("right", 0, ROW_ACTIONS_COLUMN_WIDTH, "header");
1901
1929
  const tableRows = table.getRowModel().rows;
1902
1930
  const shouldVirtualize = Boolean(virtualize) && tableRows.length > (virtualize?.threshold ?? 100);
1903
1931
  const scrollRef = useRef5(null);
@@ -1933,10 +1961,12 @@ function DataGrid({
1933
1961
  "data-testid": rowTestId,
1934
1962
  className: cn(rowProps?.className, row.index % 2 === 1 && "bg-foreground/5"),
1935
1963
  children: [
1936
- showDetailColumn && /* @__PURE__ */ jsx19("td", { className: "border-b p-2", children: /* @__PURE__ */ jsx19(
1937
- "button",
1964
+ showDetailColumn && /* @__PURE__ */ jsx19("td", { className: cn("border-b p-1", detailCellProps.className), style: detailCellProps.style, children: /* @__PURE__ */ jsx19(
1965
+ Button,
1938
1966
  {
1939
1967
  type: "button",
1968
+ variant: "ghost",
1969
+ size: "icon",
1940
1970
  "aria-label": `${isExpanded ? "Collapse" : "Expand"} row ${row.id}`,
1941
1971
  "aria-expanded": isExpanded,
1942
1972
  onClick: (event) => {
@@ -1946,7 +1976,7 @@ function DataGrid({
1946
1976
  children: /* @__PURE__ */ jsx19(ChevronRight, { className: cn("h-4 w-4 transition-transform", isExpanded && "rotate-90"), "aria-hidden": true })
1947
1977
  }
1948
1978
  ) }),
1949
- showSelectionColumn && /* @__PURE__ */ jsx19("td", { className: "border-b p-2", children: /* @__PURE__ */ jsx19(
1979
+ showSelectionColumn && /* @__PURE__ */ jsx19("td", { className: cn("border-b p-1", selectionCellProps.className), style: selectionCellProps.style, children: /* @__PURE__ */ jsx19(
1950
1980
  "input",
1951
1981
  {
1952
1982
  type: "checkbox",
@@ -1961,7 +1991,7 @@ function DataGrid({
1961
1991
  const pinnedProps = cellColumn && (cellColumn.pinned || enableColumnResizing) ? pinnedCellProps(cellColumn) : void 0;
1962
1992
  return /* @__PURE__ */ jsx19("td", { style: pinnedProps?.style, className: cn("border-b p-2", pinnedProps?.className), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id);
1963
1993
  }),
1964
- showRowActionsColumn && rowActions && /* @__PURE__ */ jsx19("td", { className: "border-b p-2", children: /* @__PURE__ */ jsx19(ActionsMenu, { items: rowActions, ctx: { row: row.original }, triggerLabel: `Row actions for ${row.id}` }) })
1994
+ showRowActionsColumn && rowActions && /* @__PURE__ */ jsx19("td", { className: cn("border-b p-1", rowActionsCellProps.className), style: rowActionsCellProps.style, children: /* @__PURE__ */ jsx19(ActionsMenu, { items: rowActions, ctx: { row: row.original }, triggerLabel: `Row actions for ${row.id}` }) })
1965
1995
  ]
1966
1996
  }
1967
1997
  ),
@@ -1992,7 +2022,7 @@ function DataGrid({
1992
2022
  "data-testid": testId,
1993
2023
  className: cn("overflow-x-auto rounded-md border", shouldVirtualize && "overflow-y-auto"),
1994
2024
  style: shouldVirtualize ? { maxHeight: virtualize?.maxBodyHeight ?? 480 } : void 0,
1995
- children: /* @__PURE__ */ jsxs12("table", { className: "w-full border-collapse text-sm", children: [
2025
+ children: /* @__PURE__ */ jsxs12("table", { className: cn("w-full border-collapse text-sm", enableColumnResizing && "table-fixed"), children: [
1996
2026
  /* @__PURE__ */ jsxs12("thead", { className: "bg-muted", children: [
1997
2027
  table.getHeaderGroups().map((headerGroup) => {
1998
2028
  const headerById = new Map(headerGroup.headers.map((header) => [header.id, header]));
@@ -2049,16 +2079,32 @@ function DataGrid({
2049
2079
  }
2050
2080
  return /* @__PURE__ */ jsxs12(Fragment2, { children: [
2051
2081
  hasHeaderGroups && /* @__PURE__ */ jsxs12("tr", { "data-testid": "header-group-row", children: [
2052
- showDetailColumn && /* @__PURE__ */ jsx19("th", { rowSpan: 2, className: "border-b p-2", "aria-hidden": true }),
2053
- showSelectionColumn && /* @__PURE__ */ jsx19("th", { rowSpan: 2, className: "border-b p-2", children: /* @__PURE__ */ jsx19(
2054
- "input",
2082
+ showDetailColumn && /* @__PURE__ */ jsx19(
2083
+ "th",
2055
2084
  {
2056
- type: "checkbox",
2057
- "aria-label": "Select all rows on this page",
2058
- checked: allOnPageSelected,
2059
- onChange: toggleAllOnPageSelected
2085
+ rowSpan: 2,
2086
+ className: cn("border-b p-1", detailHeaderCellProps.className),
2087
+ style: detailHeaderCellProps.style,
2088
+ "aria-hidden": true
2060
2089
  }
2061
- ) }),
2090
+ ),
2091
+ showSelectionColumn && /* @__PURE__ */ jsx19(
2092
+ "th",
2093
+ {
2094
+ rowSpan: 2,
2095
+ className: cn("border-b p-1", selectionHeaderCellProps.className),
2096
+ style: selectionHeaderCellProps.style,
2097
+ children: /* @__PURE__ */ jsx19(
2098
+ "input",
2099
+ {
2100
+ type: "checkbox",
2101
+ "aria-label": "Select all rows on this page",
2102
+ checked: allOnPageSelected,
2103
+ onChange: toggleAllOnPageSelected
2104
+ }
2105
+ )
2106
+ }
2107
+ ),
2062
2108
  headerRuns.map(
2063
2109
  (run) => run.kind === "single" ? renderLeafHeaderCell(run.column, 2) : /* @__PURE__ */ jsx19(
2064
2110
  "th",
@@ -2070,31 +2116,66 @@ function DataGrid({
2070
2116
  `group-${run.label}-${run.columns[0].id}`
2071
2117
  )
2072
2118
  ),
2073
- showRowActionsColumn && /* @__PURE__ */ jsx19("th", { rowSpan: 2, className: "border-b p-2", "aria-label": "Row actions" })
2119
+ showRowActionsColumn && /* @__PURE__ */ jsx19(
2120
+ "th",
2121
+ {
2122
+ rowSpan: 2,
2123
+ className: cn("border-b p-1", rowActionsHeaderCellProps.className),
2124
+ style: rowActionsHeaderCellProps.style,
2125
+ "aria-label": "Row actions"
2126
+ }
2127
+ )
2074
2128
  ] }, `${headerGroup.id}-groups`),
2075
2129
  /* @__PURE__ */ jsxs12("tr", { children: [
2076
- !hasHeaderGroups && showDetailColumn && /* @__PURE__ */ jsx19("th", { className: "border-b p-2", "aria-hidden": true }),
2077
- !hasHeaderGroups && showSelectionColumn && /* @__PURE__ */ jsx19("th", { className: "border-b p-2", children: /* @__PURE__ */ jsx19(
2078
- "input",
2130
+ !hasHeaderGroups && showDetailColumn && /* @__PURE__ */ jsx19(
2131
+ "th",
2132
+ {
2133
+ className: cn("border-b p-1", detailHeaderCellProps.className),
2134
+ style: detailHeaderCellProps.style,
2135
+ "aria-hidden": true
2136
+ }
2137
+ ),
2138
+ !hasHeaderGroups && showSelectionColumn && /* @__PURE__ */ jsx19(
2139
+ "th",
2079
2140
  {
2080
- type: "checkbox",
2081
- "aria-label": "Select all rows on this page",
2082
- checked: allOnPageSelected,
2083
- onChange: toggleAllOnPageSelected
2141
+ className: cn("border-b p-1", selectionHeaderCellProps.className),
2142
+ style: selectionHeaderCellProps.style,
2143
+ children: /* @__PURE__ */ jsx19(
2144
+ "input",
2145
+ {
2146
+ type: "checkbox",
2147
+ "aria-label": "Select all rows on this page",
2148
+ checked: allOnPageSelected,
2149
+ onChange: toggleAllOnPageSelected
2150
+ }
2151
+ )
2084
2152
  }
2085
- ) }),
2153
+ ),
2086
2154
  headerGroup.headers.map((header) => {
2087
2155
  const column = columnById.get(header.id);
2088
2156
  if (!column || hasHeaderGroups && !column.headerGroup) return null;
2089
2157
  return renderLeafHeaderCell(column);
2090
2158
  }),
2091
- !hasHeaderGroups && showRowActionsColumn && /* @__PURE__ */ jsx19("th", { className: "border-b p-2", "aria-label": "Row actions" })
2159
+ !hasHeaderGroups && showRowActionsColumn && /* @__PURE__ */ jsx19(
2160
+ "th",
2161
+ {
2162
+ className: cn("border-b p-1", rowActionsHeaderCellProps.className),
2163
+ style: rowActionsHeaderCellProps.style,
2164
+ "aria-label": "Row actions"
2165
+ }
2166
+ )
2092
2167
  ] }, headerGroup.id)
2093
2168
  ] }, headerGroup.id);
2094
2169
  }),
2095
2170
  hasFilterRow && /* @__PURE__ */ jsxs12("tr", { "data-testid": "filter-row", children: [
2096
- showDetailColumn && /* @__PURE__ */ jsx19("th", { className: "border-b p-2" }),
2097
- showSelectionColumn && /* @__PURE__ */ jsx19("th", { className: "border-b p-2" }),
2171
+ showDetailColumn && /* @__PURE__ */ jsx19("th", { className: cn("border-b p-1", detailHeaderCellProps.className), style: detailHeaderCellProps.style }),
2172
+ showSelectionColumn && /* @__PURE__ */ jsx19(
2173
+ "th",
2174
+ {
2175
+ className: cn("border-b p-1", selectionHeaderCellProps.className),
2176
+ style: selectionHeaderCellProps.style
2177
+ }
2178
+ ),
2098
2179
  visibleColumns.map((column) => {
2099
2180
  const pinnedProps = pinnedCellProps(column, "header");
2100
2181
  return /* @__PURE__ */ jsx19(
@@ -2107,7 +2188,13 @@ function DataGrid({
2107
2188
  column.id
2108
2189
  );
2109
2190
  }),
2110
- showRowActionsColumn && /* @__PURE__ */ jsx19("th", { className: "border-b p-2" })
2191
+ showRowActionsColumn && /* @__PURE__ */ jsx19(
2192
+ "th",
2193
+ {
2194
+ className: cn("border-b p-1", rowActionsHeaderCellProps.className),
2195
+ style: rowActionsHeaderCellProps.style
2196
+ }
2197
+ )
2111
2198
  ] })
2112
2199
  ] }),
2113
2200
  rows.length === 0 ? /* @__PURE__ */ jsx19("tbody", { children: /* @__PURE__ */ jsx19("tr", { children: /* @__PURE__ */ jsx19("td", { colSpan: totalColumnCount, className: "p-4 text-center text-muted-foreground", children: loading ? "Loading..." : "No results." }) }) }) : shouldVirtualize ? /* @__PURE__ */ jsxs12(Fragment3, { children: [