@redsift/ds-mcp-server 12.5.0-muiv7 → 12.5.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.
Files changed (45) hide show
  1. package/data/demos/patterns/_shared/StateDebugPanel.tsx +2 -2
  2. package/data/demos/patterns/_shared/columns.tsx +3 -3
  3. package/data/demos/patterns/_shared/defaults.ts +1 -1
  4. package/data/demos/patterns/_shared/filter-helpers.ts +1 -1
  5. package/data/demos/patterns/_shared/helpers.tsx +1 -1
  6. package/data/demos/patterns/_shared/server-logic.ts +1 -1
  7. package/data/demos/patterns/_shared/story-helpers.ts +55 -38
  8. package/data/demos/patterns/crossfiltered-datagrid-client-side/CrossfilteredDatagridClientSide.interaction.stories.tsx +2 -2
  9. package/data/demos/patterns/crossfiltered-datagrid-client-side/example.tsx +2 -2
  10. package/data/demos/patterns/crossfiltered-datagrid-server-side/CrossfilteredDatagridServerSide.interaction.stories.tsx +2 -2
  11. package/data/demos/patterns/crossfiltered-datagrid-server-side/example.tsx +5 -5
  12. package/data/demos/patterns/drilldowned-datagrid-client-side/DrilldownedDatagridClientSide.interaction.stories.tsx +2 -2
  13. package/data/demos/patterns/drilldowned-datagrid-client-side/example.tsx +1 -1
  14. package/data/demos/patterns/drilldowned-datagrid-server-side/DrilldownedDatagridServerSide.interaction.stories.tsx +2 -2
  15. package/data/demos/patterns/drilldowned-datagrid-server-side/example.tsx +1 -1
  16. package/data/demos/patterns/single-datagrid-client-side/SingleDatagridClientSide.interaction.stories.tsx +3 -3
  17. package/data/demos/patterns/single-datagrid-client-side/example.tsx +5 -5
  18. package/data/demos/patterns/single-datagrid-server-side/SingleDatagridServerSide.interaction.stories.tsx +3 -3
  19. package/data/demos/patterns/single-datagrid-server-side/example.tsx +5 -5
  20. package/data/demos/patterns/stateful-single-datagrid-client-side/StatefulSingleDatagridClientSide.interaction.stories.tsx +1 -1
  21. package/data/demos/patterns/stateful-single-datagrid-client-side/example.tsx +4 -4
  22. package/data/demos/patterns/stateful-single-datagrid-server-side/StatefulSingleDatagridServerSide.interaction.stories.tsx +2 -4
  23. package/data/demos/patterns/stateful-single-datagrid-server-side/example.tsx +4 -4
  24. package/data/demos/patterns/summary-dashboard/SummaryDashboard.interaction.stories.tsx +2 -2
  25. package/data/demos/patterns/tabbed-datagrid-client-side/TabbedDatagridClientSide.interaction.stories.tsx +2 -2
  26. package/data/demos/patterns/tabbed-datagrid-server-side/TabbedDatagridServerSide.interaction.stories.tsx +2 -2
  27. package/data/demos/patterns/tabbed-datagrid-server-side/example.tsx +1 -1
  28. package/data/docs/components/dashboard/Dashboard.json +2 -2
  29. package/data/docs/components/table/DataGrid.json +3 -30
  30. package/data/docs/components/table/StatefulDataGrid.json +3 -30
  31. package/data/docs/components-index.json +2 -2
  32. package/data/docs/components.json +10 -64
  33. package/data/docs/llms-full.txt +36 -42
  34. package/data/docs/llms.txt +6 -6
  35. package/data/docs/patterns-catalog.md +24 -25
  36. package/data/docs/patterns.json +4 -4
  37. package/data/metadata.json +2 -2
  38. package/data/patterns/crossfiltered-datagrid-server-side.mdx +1 -1
  39. package/data/patterns/drilldowned-datagrid-client-side.mdx +1 -1
  40. package/data/patterns/drilldowned-datagrid-server-side.mdx +1 -1
  41. package/data/patterns/single-datagrid-client-side.mdx +9 -9
  42. package/data/patterns/single-datagrid-server-side.mdx +4 -4
  43. package/data/patterns/stateful-single-datagrid-client-side.mdx +1 -1
  44. package/data/patterns/tabbed-datagrid-server-side.mdx +1 -1
  45. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  import React, { useCallback, useEffect, useState } from 'react';
2
- import type { GridApiPro } from '@mui/x-data-grid-pro/models/gridApiPro';
2
+ import type { GridApiPremium } from '@mui/x-data-grid-premium';
3
3
 
4
4
  // localStorage key categories — must match @redsift/table internals
5
5
  const LS_CATEGORIES = [
@@ -13,7 +13,7 @@ const LS_CATEGORIES = [
13
13
  ];
14
14
 
15
15
  interface StateDebugPanelProps {
16
- apiRef: React.MutableRefObject<GridApiPro>;
16
+ apiRef: React.MutableRefObject<GridApiPremium | null>;
17
17
  useRouter: () => { pathname: string; search: string; historyReplace: (newSearch: string) => void };
18
18
  localStorageVersion?: number;
19
19
  }
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { createColumn, TextCell } from '@redsift/table';
3
3
  import { Flexbox, Icon, IconButtonLink, Pill } from '@redsift/design-system';
4
4
  import { mdiArrowRight, mdiCheck, mdiClose } from '@redsift/icons';
5
- import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid-pro';
5
+ import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid-premium';
6
6
  import { Row } from './data';
7
7
 
8
8
  // -- Option constants -------------------------------------------------------
@@ -110,7 +110,7 @@ export const columns: GridColDef<Row>[] = [
110
110
  width: 140,
111
111
  display: 'flex',
112
112
  ...createColumn('date'),
113
- valueGetter: (value: unknown) => parseDate(value),
113
+ valueGetter: (value: string) => parseDate(value),
114
114
  renderCell: ({ value }: GridRenderCellParams) => <TextCell>{value ? formatDate(value as Date) : '—'}</TextCell>,
115
115
  },
116
116
  // DateTime
@@ -120,7 +120,7 @@ export const columns: GridColDef<Row>[] = [
120
120
  width: 180,
121
121
  display: 'flex',
122
122
  ...createColumn('dateTime'),
123
- valueGetter: (value: unknown) => parseDate(value),
123
+ valueGetter: (value: string) => parseDate(value),
124
124
  renderCell: ({ value }: GridRenderCellParams) => <TextCell>{value ? formatDateTime(value as Date) : '—'}</TextCell>,
125
125
  },
126
126
  // Boolean — in stock
@@ -1,4 +1,4 @@
1
- import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-pro';
1
+ import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-premium';
2
2
 
3
3
  /**
4
4
  * Default filter model applied to all pattern examples.
@@ -1,4 +1,4 @@
1
- import { GridFilterModel } from '@mui/x-data-grid-pro';
1
+ import { GridFilterModel } from '@mui/x-data-grid-premium';
2
2
  import { Row } from './data';
3
3
 
4
4
  // -- Types ------------------------------------------------------------------
@@ -8,7 +8,7 @@ import {
8
8
  GridToolbarExport,
9
9
  GridToolbarFilterButton,
10
10
  GridToolbarQuickFilter,
11
- } from '@mui/x-data-grid-pro';
11
+ } from '@mui/x-data-grid-premium';
12
12
 
13
13
  // -- Toolbar ----------------------------------------------------------------
14
14
 
@@ -1,4 +1,4 @@
1
- import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-pro';
1
+ import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-premium';
2
2
  import { Row, allRows } from './data';
3
3
  import { Aggregates, computeAggregates, applyFilters } from './filter-helpers';
4
4
 
@@ -320,34 +320,37 @@ export const clickHeaderCheckbox = async (canvasElement: HTMLElement) => {
320
320
  const headerCheckbox = canvasElement.querySelector('.MuiDataGrid-columnHeaderCheckbox input[type="checkbox"]');
321
321
  expect(headerCheckbox).toBeTruthy();
322
322
  },
323
- { timeout: 3000 }
323
+ { timeout: 5000 }
324
324
  );
325
325
  // Small yield to let React finish any pending microtask re-renders
326
326
  await new Promise((resolve) => setTimeout(resolve, 200));
327
327
  const headerCheckbox = canvasElement.querySelector('.MuiDataGrid-columnHeaderCheckbox input[type="checkbox"]')!;
328
- fireEvent.click(headerCheckbox);
328
+ // Use userEvent.click for reliable event dispatching — fireEvent.click on a hidden
329
+ // checkbox input doesn't trigger the native change event in Playwright/Chromium,
330
+ // causing server-side pagination grids to miss the selection update.
331
+ await userEvent.click(headerCheckbox);
329
332
  // Wait for React and MUI DataGrid to process the selection change
330
333
  await new Promise((resolve) => setTimeout(resolve, 200));
331
334
  };
332
335
 
333
336
  /** Click a row checkbox by row index (0-based, within the visible page). */
334
337
  export const clickRowCheckbox = async (canvasElement: HTMLElement, rowIndex: number) => {
335
- let checkbox!: HTMLInputElement;
336
- await waitFor(() => {
337
- const row = canvasElement.querySelector(`.MuiDataGrid-row[data-rowindex="${rowIndex}"]`);
338
- expect(row).toBeTruthy();
339
- checkbox = row!.querySelector('input[type="checkbox"]') as HTMLInputElement;
340
- expect(checkbox).toBeTruthy();
341
- });
342
- const wasChecked = checkbox.checked;
338
+ // Wait for BOTH the row AND its checkbox to be present.
339
+ // Server-side grids may render rows before checkboxes are mounted.
340
+ await waitFor(
341
+ () => {
342
+ const rows = canvasElement.querySelectorAll('.MuiDataGrid-row');
343
+ expect(rows.length).toBeGreaterThan(rowIndex);
344
+ const cb = rows[rowIndex].querySelector('input[type="checkbox"]');
345
+ expect(cb).toBeTruthy();
346
+ },
347
+ { timeout: 5000 }
348
+ );
349
+ const rows = canvasElement.querySelectorAll('.MuiDataGrid-row');
350
+ const checkbox = rows[rowIndex].querySelector('input[type="checkbox"]')!;
343
351
  await userEvent.click(checkbox);
344
- // Wait for the click to actually toggle the checkbox (needed for MUI v7 re-render timing)
345
- await waitFor(() => {
346
- const freshRow = canvasElement.querySelector(`.MuiDataGrid-row[data-rowindex="${rowIndex}"]`);
347
- const freshCheckbox = freshRow?.querySelector('input[type="checkbox"]') as HTMLInputElement | null;
348
- expect(freshCheckbox).toBeTruthy();
349
- expect(freshCheckbox!.checked).toBe(!wasChecked);
350
- });
352
+ // Wait for React and MUI DataGrid to process the selection change
353
+ await new Promise((resolve) => setTimeout(resolve, 200));
351
354
  };
352
355
 
353
356
  // ---------------------------------------------------------------------------
@@ -913,29 +916,42 @@ export const waitForPaginationEnabled = async (canvasElement: HTMLElement, direc
913
916
 
914
917
  /**
915
918
  * Change the page size via the MUI pagination "Rows per page" select.
916
- * The dropdown menu renders as a portal on document.body.
919
+ * MUI Material v7's `useSlot()` applies `.MuiTablePagination-select` to the
920
+ * Select wrapper, NOT the inner display div that has the `onMouseDown` handler.
921
+ * We target `[role="combobox"]` inside the pagination toolbar instead, which is
922
+ * the actual interactive element rendered by `SelectInput`.
923
+ * `userEvent.click` in the Storybook Playwright runner doesn't reliably
924
+ * trigger mouseDown on MUI Select, so we use `fireEvent.mouseDown` directly,
925
+ * then `userEvent.click` to select the option in the dropdown.
917
926
  */
918
927
  export const changePageSize = async (canvasElement: HTMLElement, newSize: number) => {
919
- // Wait for the rows-per-page select to be available
920
- let select!: HTMLElement;
921
- await waitFor(() => {
922
- // The bottom pagination renders a MUI Select with role="combobox"
923
- const selects = canvasElement.querySelectorAll<HTMLElement>('[role="combobox"]');
924
- // Pick the last one (bottom pagination) — top pagination may not have one
925
- select = selects[selects.length - 1];
926
- expect(select).toBeTruthy();
927
- });
928
- // MUI Select listens on mouseDown to open its menu
928
+ // Wait for the pagination combobox to be present
929
+ await waitFor(
930
+ () => {
931
+ const el = canvasElement.querySelector('.MuiTablePagination-toolbar [role="combobox"]');
932
+ expect(el).toBeTruthy();
933
+ },
934
+ { timeout: 5000 }
935
+ );
936
+
937
+ const select = canvasElement.querySelector('.MuiTablePagination-toolbar [role="combobox"]') as HTMLElement;
938
+
939
+ // Use fireEvent.mouseDown to reliably open MUI v7 Select dropdown
929
940
  fireEvent.mouseDown(select);
930
- // The menu renders as a MUI portal on document.body — wait for options
931
- await waitFor(() => {
932
- const options = document.querySelectorAll('li[role="option"]');
933
- expect(options.length).toBeGreaterThan(0);
934
- });
935
- const options = document.querySelectorAll('li[role="option"]');
941
+
942
+ // Wait for the dropdown to render (MUI uses a portal on document.body)
943
+ await waitFor(
944
+ () => {
945
+ const options = document.querySelectorAll('[role="option"]');
946
+ expect(options.length).toBeGreaterThan(0);
947
+ },
948
+ { timeout: 5000 }
949
+ );
950
+
951
+ const options = document.querySelectorAll('[role="option"]');
936
952
  const target = Array.from(options).find((opt) => opt.textContent === String(newSize));
937
953
  if (!target) throw new Error(`Could not find page size option "${newSize}"`);
938
- fireEvent.click(target);
954
+ await userEvent.click(target);
939
955
  };
940
956
 
941
957
  // ---------------------------------------------------------------------------
@@ -949,7 +965,7 @@ export const openColumnsPanel = async (canvasElement: HTMLElement) => {
949
965
  ) as HTMLElement | null;
950
966
  if (!btn) throw new Error('Could not find columns toolbar button');
951
967
  await userEvent.click(btn);
952
- // Wait for the panel to appear on document.body (v7: columnsManagement, v6: columnsPanel)
968
+ // Wait for the panel to appear on document.body
953
969
  await waitFor(() => {
954
970
  const panel = document.querySelector('.MuiDataGrid-columnsManagement');
955
971
  expect(panel).toBeTruthy();
@@ -960,8 +976,9 @@ export const openColumnsPanel = async (canvasElement: HTMLElement) => {
960
976
  export const toggleColumnInPanel = async (fieldLabel: string) => {
961
977
  const panel = document.querySelector('.MuiDataGrid-columnsManagement');
962
978
  if (!panel) throw new Error('Columns panel is not open');
963
- const labels = Array.from(panel.querySelectorAll('.MuiFormControlLabel-root'));
964
- const target = labels.find((label) => label.textContent?.includes(fieldLabel));
979
+ // MUI v8 renders each column toggle as a baseCheckbox slot with class columnsManagementRow
980
+ const rows = Array.from(panel.querySelectorAll('.MuiDataGrid-columnsManagementRow'));
981
+ const target = rows.find((row) => row.textContent?.includes(fieldLabel));
965
982
  if (!target) throw new Error(`Could not find column "${fieldLabel}" in columns panel`);
966
983
  const checkbox = target.querySelector('input[type="checkbox"]') as HTMLElement | null;
967
984
  if (!checkbox) throw new Error(`Could not find checkbox for column "${fieldLabel}"`);
@@ -85,9 +85,9 @@ import {
85
85
  RU7_RM_PASTRY,
86
86
  } from '../_shared/expected-values';
87
87
 
88
- const meta: Meta<typeof Example> = {
88
+ const meta: Meta = {
89
89
  title: 'Patterns/Crossfiltered Datagrid (Client)',
90
- component: Example,
90
+ component: Example as any,
91
91
  };
92
92
  export default meta;
93
93
  type Story = StoryObj;
@@ -18,7 +18,7 @@ export default () => (
18
18
  {/* Category card — two-way: counts update when other cards filter */}
19
19
  <WithFilters
20
20
  field="Category"
21
- dimension={(d: Row) => d.Category}
21
+ dimension={(d: any) => d.Category}
22
22
  datagridCategoryDimFilter={{ field: 'Category', operator: 'isAnyOf' }}
23
23
  syncMode="two-way"
24
24
  >
@@ -51,7 +51,7 @@ export default () => (
51
51
  {/* Allergens card — two-way */}
52
52
  <WithFilters
53
53
  field="Allergens"
54
- dimension={(d: Row) => d.Allergens}
54
+ dimension={(d: any) => d.Allergens}
55
55
  isDimensionArray
56
56
  datagridCategoryDimFilter={{ field: 'Allergens', operator: 'hasAnyOf' }}
57
57
  syncMode="two-way"
@@ -84,9 +84,9 @@ import {
84
84
  RU7_RM_PASTRY,
85
85
  } from '../_shared/expected-values';
86
86
 
87
- const meta: Meta<typeof Example> = {
87
+ const meta: Meta = {
88
88
  title: 'Patterns/Crossfiltered Datagrid (Server)',
89
- component: Example,
89
+ component: Example as any,
90
90
  parameters: {
91
91
  msw: { handlers: bakeryHandlers },
92
92
  },
@@ -4,7 +4,7 @@ import { Flexbox } from '@redsift/design-system';
4
4
  import { DataCard, DataRow } from '@redsift/dashboard';
5
5
  import { BarChart, PieChart, ArcDatum, BarDatum } from '@redsift/charts';
6
6
  import { mdiShapeOutline, mdiToggleSwitch, mdiFoodOff } from '@redsift/icons';
7
- import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-pro';
7
+ import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-premium';
8
8
  import { Row } from '../_shared/data';
9
9
  import { columns, CATEGORY_OPTIONS, ALLERGEN_OPTIONS } from '../_shared/columns';
10
10
  import { fetchBakeryData, FetchResult } from '../_shared/api-client';
@@ -208,7 +208,7 @@ export default () => {
208
208
  data={itemsChartData}
209
209
  sliceRole="option"
210
210
  onSliceClick={(datum: ArcDatum) => {
211
- const key = datum.data.key as string;
211
+ const key = datum.data.key;
212
212
  setFilterModel((prev) => {
213
213
  const selected = getSelectedFromFilterModel(prev, 'Items');
214
214
  const next = selected.includes(key) ? selected.filter((v) => v !== key) : [...selected, key];
@@ -217,7 +217,7 @@ export default () => {
217
217
  setPage(0);
218
218
  }}
219
219
  isSliceSelected={(datum: ArcDatum) =>
220
- itemsSelection.length === 0 || itemsSelection.includes(datum.data.key as string)
220
+ itemsSelection.length === 0 || itemsSelection.includes(datum.data.key)
221
221
  }
222
222
  />
223
223
 
@@ -239,7 +239,7 @@ export default () => {
239
239
  data={tagsChartData}
240
240
  barRole="option"
241
241
  onBarClick={(datum: BarDatum) => {
242
- const key = datum.data.key as string;
242
+ const key = String(datum.data.key);
243
243
  setFilterModel((prev) => {
244
244
  const selected = getSelectedFromFilterModel(prev, 'Tags');
245
245
  const next = selected.includes(key) ? selected.filter((v) => v !== key) : [...selected, key];
@@ -248,7 +248,7 @@ export default () => {
248
248
  setPage(0);
249
249
  }}
250
250
  isBarSelected={(datum: BarDatum) =>
251
- tagsSelection.length === 0 || tagsSelection.includes(datum.data.key as string)
251
+ tagsSelection.length === 0 || tagsSelection.includes(String(datum.data.key))
252
252
  }
253
253
  />
254
254
  </Flexbox>
@@ -34,9 +34,9 @@ import {
34
34
  ALLERGENS_HASANYOF_GLUTEN,
35
35
  } from '../_shared/expected-values';
36
36
 
37
- const meta: Meta<typeof Example> = {
37
+ const meta: Meta = {
38
38
  title: 'Patterns/Drilldowned Datagrid (Client)',
39
- component: Example,
39
+ component: Example as any,
40
40
  };
41
41
  export default meta;
42
42
  type Story = StoryObj;
@@ -3,7 +3,7 @@ import { DataGrid } from '@redsift/table';
3
3
  import { Flexbox } from '@redsift/design-system';
4
4
  import { DataCard, DataRow } from '@redsift/dashboard';
5
5
  import { mdiShapeOutline, mdiToggleSwitch, mdiFoodOff } from '@redsift/icons';
6
- import { GridFilterModel } from '@mui/x-data-grid-pro';
6
+ import { GridFilterModel } from '@mui/x-data-grid-premium';
7
7
  import { rows } from '../_shared/data';
8
8
  import { columns, CATEGORY_OPTIONS, ALLERGEN_OPTIONS } from '../_shared/columns';
9
9
  import { CustomToolbar } from '../_shared/helpers';
@@ -35,9 +35,9 @@ import {
35
35
  ALLERGENS_HASANYOF_GLUTEN,
36
36
  } from '../_shared/expected-values';
37
37
 
38
- const meta: Meta<typeof Example> = {
38
+ const meta: Meta = {
39
39
  title: 'Patterns/Drilldowned Datagrid (Server)',
40
- component: Example,
40
+ component: Example as any,
41
41
  parameters: {
42
42
  msw: { handlers: bakeryHandlers },
43
43
  },
@@ -3,7 +3,7 @@ import { DataGrid } from '@redsift/table';
3
3
  import { Flexbox } from '@redsift/design-system';
4
4
  import { DataCard, DataRow } from '@redsift/dashboard';
5
5
  import { mdiShapeOutline, mdiToggleSwitch, mdiFoodOff } from '@redsift/icons';
6
- import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-pro';
6
+ import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-premium';
7
7
  import { Row } from '../_shared/data';
8
8
  import { columns, CATEGORY_OPTIONS, ALLERGEN_OPTIONS } from '../_shared/columns';
9
9
  import { fetchBakeryData, FetchResult } from '../_shared/api-client';
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import type { Meta, StoryObj } from '@storybook/react';
3
3
  import { within, userEvent } from '@storybook/testing-library';
4
4
  import { expect } from '@storybook/jest';
5
- import { GridFilterModel } from '@mui/x-data-grid-pro';
5
+ import { GridFilterModel } from '@mui/x-data-grid-premium';
6
6
 
7
7
  import Example from './example';
8
8
  import WithLoadingExample from './with-loading';
@@ -51,9 +51,9 @@ import {
51
51
  TAGS_HASANYOF_LOCAL_NEW,
52
52
  } from '../_shared/expected-values';
53
53
 
54
- const meta: Meta<typeof Example> = {
54
+ const meta: Meta = {
55
55
  title: 'Patterns/Single Datagrid (Client)',
56
- component: Example,
56
+ component: Example as any,
57
57
  };
58
58
  export default meta;
59
59
  type Story = StoryObj;
@@ -1,20 +1,20 @@
1
1
  import React, { useState } from 'react';
2
- import { DataGrid } from '@redsift/table';
2
+ import { DataGrid, EMPTY_ROW_SELECTION_MODEL, getSelectionCount } from '@redsift/table';
3
3
  import { Flexbox } from '@redsift/design-system';
4
- import { GridFilterModel, GridRowSelectionModel } from '@mui/x-data-grid-pro';
4
+ import { GridFilterModel, GridRowSelectionModel } from '@mui/x-data-grid-premium';
5
5
  import { rows } from '../_shared/data';
6
6
  import { columns } from '../_shared/columns';
7
7
  import { CustomToolbar, BulkActionBar } from '../_shared/helpers';
8
8
  import { DEFAULT_FILTER_MODEL, DEFAULT_SORT_MODEL } from '../_shared/defaults';
9
9
 
10
10
  export default ({ initialFilterModel }: { initialFilterModel?: GridFilterModel }) => {
11
- const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>([]);
11
+ const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(EMPTY_ROW_SELECTION_MODEL);
12
12
 
13
13
  return (
14
14
  <div style={{ width: '100%' }}>
15
15
  <Flexbox flexDirection="column" gap="0px">
16
16
  <BulkActionBar
17
- count={selectionModel.length}
17
+ count={getSelectionCount(selectionModel)}
18
18
  onLog={() => console.log('Selected:', selectionModel)}
19
19
  onDelete={() => console.log('Delete:', selectionModel)}
20
20
  />
@@ -22,8 +22,8 @@ export default ({ initialFilterModel }: { initialFilterModel?: GridFilterModel }
22
22
  <DataGrid
23
23
  autoHeight
24
24
  pagination
25
+ density="compact"
25
26
  initialState={{
26
- density: 'compact',
27
27
  filter: { filterModel: initialFilterModel ?? DEFAULT_FILTER_MODEL },
28
28
  sorting: { sortModel: DEFAULT_SORT_MODEL },
29
29
  pagination: { paginationModel: { page: 0, pageSize: 10 } },
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import type { Meta, StoryObj } from '@storybook/react';
3
3
  import { within, userEvent } from '@storybook/testing-library';
4
4
  import { expect } from '@storybook/jest';
5
- import { GridFilterModel } from '@mui/x-data-grid-pro';
5
+ import { GridFilterModel } from '@mui/x-data-grid-premium';
6
6
 
7
7
  import Example from './example';
8
8
  import WithLoadingExample from './with-loading';
@@ -54,9 +54,9 @@ import {
54
54
  TAGS_HASANYOF_LOCAL_NEW,
55
55
  } from '../_shared/expected-values';
56
56
 
57
- const meta: Meta<typeof Example> = {
57
+ const meta: Meta = {
58
58
  title: 'Patterns/Single Datagrid (Server)',
59
- component: Example,
59
+ component: Example as any,
60
60
  parameters: {
61
61
  msw: { handlers: bakeryHandlers },
62
62
  },
@@ -1,7 +1,7 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
- import { DataGrid } from '@redsift/table';
2
+ import { DataGrid, EMPTY_ROW_SELECTION_MODEL, getSelectionCount } from '@redsift/table';
3
3
  import { Flexbox } from '@redsift/design-system';
4
- import { GridFilterModel, GridRowSelectionModel, GridSortModel } from '@mui/x-data-grid-pro';
4
+ import { GridFilterModel, GridRowSelectionModel, GridSortModel } from '@mui/x-data-grid-premium';
5
5
  import { Row } from '../_shared/data';
6
6
  import { columns } from '../_shared/columns';
7
7
  import { fetchBakeryData } from '../_shared/api-client';
@@ -16,7 +16,7 @@ export default ({ initialFilterModel }: { initialFilterModel?: GridFilterModel }
16
16
  const [pageSize, setPageSize] = useState(10);
17
17
  const [sortModel, setSortModel] = useState<GridSortModel>(DEFAULT_SORT_MODEL);
18
18
  const [filterModel, setFilterModel] = useState<GridFilterModel>(initialFilterModel ?? DEFAULT_FILTER_MODEL);
19
- const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>([]);
19
+ const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(EMPTY_ROW_SELECTION_MODEL);
20
20
 
21
21
  const quickFilterText = (filterModel as { quickFilterValues?: string[] }).quickFilterValues?.join(' ') || '';
22
22
  const debounceRef = useRef<ReturnType<typeof setTimeout>>();
@@ -54,7 +54,7 @@ export default ({ initialFilterModel }: { initialFilterModel?: GridFilterModel }
54
54
  <div style={{ width: '100%' }}>
55
55
  <Flexbox flexDirection="column" gap="0px">
56
56
  <BulkActionBar
57
- count={selectionModel.length}
57
+ count={getSelectionCount(selectionModel)}
58
58
  onLog={() => console.log('Selected:', selectionModel)}
59
59
  onDelete={() => console.log('Delete:', selectionModel)}
60
60
  />
@@ -62,7 +62,7 @@ export default ({ initialFilterModel }: { initialFilterModel?: GridFilterModel }
62
62
  <DataGrid
63
63
  autoHeight
64
64
  pagination
65
- initialState={{ density: 'compact' }}
65
+ density="compact"
66
66
  paginationMode="server"
67
67
  sortingMode="server"
68
68
  filterMode="server"
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import type { Meta, StoryObj } from '@storybook/react';
3
3
  import { within, userEvent } from '@storybook/testing-library';
4
4
  import { expect } from '@storybook/jest';
5
- import { GridFilterModel } from '@mui/x-data-grid-pro';
5
+ import { GridFilterModel } from '@mui/x-data-grid-premium';
6
6
 
7
7
  import Example from './example';
8
8
  import WithLoadingExample from './with-loading';
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from 'react';
2
- import { StatefulDataGrid } from '@redsift/table';
2
+ import { StatefulDataGrid, EMPTY_ROW_SELECTION_MODEL, getSelectionCount } from '@redsift/table';
3
3
  import { Flexbox } from '@redsift/design-system';
4
- import { GridFilterModel, GridRowSelectionModel, useGridApiRef } from '@mui/x-data-grid-pro';
4
+ import { GridFilterModel, GridRowSelectionModel, useGridApiRef } from '@mui/x-data-grid-premium';
5
5
  import { rows } from '../_shared/data';
6
6
  import { columns } from '../_shared/columns';
7
7
  import { CustomToolbar, BulkActionBar } from '../_shared/helpers';
@@ -16,14 +16,14 @@ interface Props {
16
16
 
17
17
  export default ({ initialFilterModel, useRouter = useRouterAdapter }: Props) => {
18
18
  const apiRef = useGridApiRef();
19
- const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>([]);
19
+ const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(EMPTY_ROW_SELECTION_MODEL);
20
20
 
21
21
  return (
22
22
  <div style={{ width: '100%' }}>
23
23
  <StateDebugPanel apiRef={apiRef} useRouter={useRouter} localStorageVersion={1} />
24
24
  <Flexbox flexDirection="column" gap="0px">
25
25
  <BulkActionBar
26
- count={selectionModel.length}
26
+ count={getSelectionCount(selectionModel)}
27
27
  onLog={() => console.log('Selected:', selectionModel)}
28
28
  onDelete={() => console.log('Delete:', selectionModel)}
29
29
  />
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import type { Meta, StoryObj } from '@storybook/react';
3
3
  import { within, userEvent } from '@storybook/testing-library';
4
4
  import { expect } from '@storybook/jest';
5
- import { GridFilterModel } from '@mui/x-data-grid-pro';
5
+ import { GridFilterModel } from '@mui/x-data-grid-premium';
6
6
 
7
7
  import Example from './example';
8
8
  import WithLoadingExample from './with-loading';
@@ -385,9 +385,7 @@ export const SelectionPersistsAcrossPages: Story = {
385
385
  await waitForServerResponse(canvas);
386
386
  await assertDisplayedRowsText(canvasElement, '11–20 of 14,075');
387
387
  await assertBulkActionBarVisible(canvasElement, 2);
388
- // In MUI v7, the header checkbox reflects current-page selection only.
389
- // No page-2 rows are selected, so the header is unchecked (not indeterminate).
390
- await assertHeaderCheckboxState(canvasElement, 'unchecked');
388
+ await assertHeaderCheckboxState(canvasElement, 'indeterminate');
391
389
  await assertRowCheckboxChecked(canvasElement, 0, false);
392
390
  await assertAllStatesInSync({ getSearch });
393
391
  });
@@ -1,7 +1,7 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
- import { StatefulDataGrid } from '@redsift/table';
2
+ import { StatefulDataGrid, EMPTY_ROW_SELECTION_MODEL, getSelectionCount } from '@redsift/table';
3
3
  import { Flexbox } from '@redsift/design-system';
4
- import { GridFilterModel, GridRowSelectionModel, GridSortModel, useGridApiRef } from '@mui/x-data-grid-pro';
4
+ import { GridFilterModel, GridRowSelectionModel, GridSortModel, useGridApiRef } from '@mui/x-data-grid-premium';
5
5
  import { Row } from '../_shared/data';
6
6
  import { columns } from '../_shared/columns';
7
7
  import { fetchBakeryData } from '../_shared/api-client';
@@ -20,7 +20,7 @@ export default ({ initialFilterModel, useRouter = useRouterAdapter }: Props) =>
20
20
  const [rows, setRows] = useState<Row[]>([]);
21
21
  const [totalRows, setTotalRows] = useState(0);
22
22
  const [loading, setLoading] = useState(true);
23
- const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>([]);
23
+ const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(EMPTY_ROW_SELECTION_MODEL);
24
24
 
25
25
  // Refs track the latest model values so fetchData() always reads current state.
26
26
  // StatefulDataGrid manages filter/sort/pagination internally — we use callbacks
@@ -55,7 +55,7 @@ export default ({ initialFilterModel, useRouter = useRouterAdapter }: Props) =>
55
55
  <StateDebugPanel apiRef={apiRef} useRouter={useRouter} localStorageVersion={1} />
56
56
  <Flexbox flexDirection="column" gap="0px">
57
57
  <BulkActionBar
58
- count={selectionModel.length}
58
+ count={getSelectionCount(selectionModel)}
59
59
  onLog={() => console.log('Selected:', selectionModel)}
60
60
  onDelete={() => console.log('Delete:', selectionModel)}
61
61
  />
@@ -24,9 +24,9 @@ import {
24
24
  } from '../_shared/story-helpers';
25
25
  import { AGG_CATEGORY, AGG_ALLERGENS, AGG_INSTOCK } from '../_shared/expected-values';
26
26
 
27
- const meta: Meta<typeof Example> = {
27
+ const meta: Meta = {
28
28
  title: 'Patterns/Summary Dashboard',
29
- component: Example,
29
+ component: Example as any,
30
30
  };
31
31
  export default meta;
32
32
  type Story = StoryObj;
@@ -16,9 +16,9 @@ import {
16
16
  } from '../_shared/story-helpers';
17
17
  import { TOTAL, CATEGORY_BAKERY, CATEGORY_BEVERAGE, CATEGORY_PASTRY, CATEGORY_OTHER } from '../_shared/expected-values';
18
18
 
19
- const meta: Meta<typeof Example> = {
19
+ const meta: Meta = {
20
20
  title: 'Patterns/Tabbed Datagrid (Client)',
21
- component: Example,
21
+ component: Example as any,
22
22
  };
23
23
  export default meta;
24
24
  type Story = StoryObj;
@@ -18,9 +18,9 @@ import {
18
18
  } from '../_shared/story-helpers';
19
19
  import { TOTAL, CATEGORY_BAKERY, CATEGORY_BEVERAGE, CATEGORY_PASTRY, CATEGORY_OTHER } from '../_shared/expected-values';
20
20
 
21
- const meta: Meta<typeof Example> = {
21
+ const meta: Meta = {
22
22
  title: 'Patterns/Tabbed Datagrid (Server)',
23
- component: Example,
23
+ component: Example as any,
24
24
  parameters: {
25
25
  msw: { handlers: bakeryHandlers },
26
26
  },
@@ -1,7 +1,7 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { DataGrid } from '@redsift/table';
3
3
  import { Flexbox, Pill, Number, Text, Tabs, Tab } from '@redsift/design-system';
4
- import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-pro';
4
+ import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-premium';
5
5
  import { Row } from '../_shared/data';
6
6
  import { columns, CATEGORY_OPTIONS } from '../_shared/columns';
7
7
  import { fetchBakeryData } from '../_shared/api-client';
@@ -14,8 +14,8 @@
14
14
  },
15
15
  {
16
16
  "name": "dataGridApiRef",
17
- "description": "Datagrid API Ref.",
18
- "type": "MutableRefObject<GridApiPro>",
17
+ "description": "Datagrid API Ref. MUI v8: can be null initially.",
18
+ "type": "MutableRefObject<GridApiPremium | null>",
19
19
  "required": false,
20
20
  "defaultValue": null,
21
21
  "category": "props"