@redsift/ds-mcp-server 12.5.3-muiv7 → 12.5.3

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 (116) hide show
  1. package/consumer-instructions/redsift-design-system.instructions.md +82 -1
  2. package/data/demos/patterns/_shared/StateDebugPanel.tsx +2 -2
  3. package/data/demos/patterns/_shared/columns.tsx +3 -3
  4. package/data/demos/patterns/_shared/defaults.ts +1 -1
  5. package/data/demos/patterns/_shared/filter-helpers.ts +1 -1
  6. package/data/demos/patterns/_shared/helpers.tsx +1 -1
  7. package/data/demos/patterns/_shared/server-logic.ts +1 -1
  8. package/data/demos/patterns/_shared/story-helpers.ts +106 -36
  9. package/data/demos/patterns/crossfiltered-datagrid-client-side/CrossfilteredDatagridClientSide.interaction.stories.tsx +4 -19
  10. package/data/demos/patterns/crossfiltered-datagrid-client-side/example.tsx +2 -2
  11. package/data/demos/patterns/crossfiltered-datagrid-server-side/CrossfilteredDatagridServerSide.interaction.stories.tsx +3 -3
  12. package/data/demos/patterns/crossfiltered-datagrid-server-side/example.tsx +5 -5
  13. package/data/demos/patterns/drilldowned-datagrid-client-side/DrilldownedDatagridClientSide.interaction.stories.tsx +2 -2
  14. package/data/demos/patterns/drilldowned-datagrid-client-side/example.tsx +1 -1
  15. package/data/demos/patterns/drilldowned-datagrid-server-side/DrilldownedDatagridServerSide.interaction.stories.tsx +2 -2
  16. package/data/demos/patterns/drilldowned-datagrid-server-side/example.tsx +5 -19
  17. package/data/demos/patterns/single-datagrid-client-side/SingleDatagridClientSide.interaction.stories.tsx +3 -3
  18. package/data/demos/patterns/single-datagrid-client-side/example.tsx +5 -5
  19. package/data/demos/patterns/single-datagrid-server-side/SingleDatagridServerSide.interaction.stories.tsx +3 -3
  20. package/data/demos/patterns/single-datagrid-server-side/example.tsx +5 -6
  21. package/data/demos/patterns/stateful-single-datagrid-client-side/StatefulSingleDatagridClientSide.interaction.stories.tsx +130 -3
  22. package/data/demos/patterns/stateful-single-datagrid-client-side/example.tsx +6 -6
  23. package/data/demos/patterns/stateful-single-datagrid-server-side/StatefulSingleDatagridServerSide.interaction.stories.tsx +136 -6
  24. package/data/demos/patterns/stateful-single-datagrid-server-side/example.tsx +6 -9
  25. package/data/demos/patterns/summary-dashboard/SummaryDashboard.interaction.stories.tsx +2 -2
  26. package/data/demos/patterns/tabbed-datagrid-client-side/TabbedDatagridClientSide.interaction.stories.tsx +2 -2
  27. package/data/demos/patterns/tabbed-datagrid-server-side/TabbedDatagridServerSide.interaction.stories.tsx +2 -2
  28. package/data/demos/patterns/tabbed-datagrid-server-side/example.tsx +1 -1
  29. package/data/docs/components/charts/Axis.json +6 -1
  30. package/data/docs/components/charts/BarChart.json +7 -1
  31. package/data/docs/components/charts/ChartContainerTitle.json +5 -1
  32. package/data/docs/components/charts/Legend.json +6 -1
  33. package/data/docs/components/charts/LineChart.json +7 -1
  34. package/data/docs/components/charts/PieChart.json +6 -1
  35. package/data/docs/components/charts/ScatterPlot.json +6 -1
  36. package/data/docs/components/dashboard/ChartEmptyState.json +8 -1
  37. package/data/docs/components/dashboard/Dashboard.json +8 -3
  38. package/data/docs/components/dashboard/DataCard.json +12 -0
  39. package/data/docs/components/dashboard/DataCardBody.json +4 -0
  40. package/data/docs/components/dashboard/DataCardHeader.json +4 -0
  41. package/data/docs/components/dashboard/DataCardListbox.json +5 -0
  42. package/data/docs/components/dashboard/DataRow.json +7 -1
  43. package/data/docs/components/dashboard/PdfExportButton.json +6 -1
  44. package/data/docs/components/dashboard/TimeSeriesBarChart.json +6 -1
  45. package/data/docs/components/dashboard/WithFilters.json +5 -1
  46. package/data/docs/components/design-system/Alert.json +8 -1
  47. package/data/docs/components/design-system/AppBar.json +6 -1
  48. package/data/docs/components/design-system/AppContent.json +4 -0
  49. package/data/docs/components/design-system/AppSidePanel.json +5 -0
  50. package/data/docs/components/design-system/Badge.json +6 -1
  51. package/data/docs/components/design-system/Breadcrumbs.json +4 -0
  52. package/data/docs/components/design-system/Button.json +5 -0
  53. package/data/docs/components/design-system/Card.json +9 -0
  54. package/data/docs/components/design-system/CardActions.json +4 -0
  55. package/data/docs/components/design-system/CardBody.json +3 -0
  56. package/data/docs/components/design-system/CardHeader.json +4 -0
  57. package/data/docs/components/design-system/DetailedCard.json +6 -0
  58. package/data/docs/components/design-system/Flexbox.json +14 -1
  59. package/data/docs/components/design-system/Grid.json +6 -1
  60. package/data/docs/components/design-system/Heading.json +11 -0
  61. package/data/docs/components/design-system/Icon.json +6 -1
  62. package/data/docs/components/design-system/IconButton.json +9 -0
  63. package/data/docs/components/design-system/Pill.json +10 -0
  64. package/data/docs/components/design-system/Skeleton.json +10 -1
  65. package/data/docs/components/design-system/SkeletonCircle.json +6 -1
  66. package/data/docs/components/design-system/SkeletonText.json +6 -1
  67. package/data/docs/components/design-system/Tab.json +4 -0
  68. package/data/docs/components/design-system/TabPanel.json +4 -0
  69. package/data/docs/components/design-system/Tabs.json +6 -0
  70. package/data/docs/components/design-system/Text.json +9 -0
  71. package/data/docs/components/design-system/TextField.json +6 -1
  72. package/data/docs/components/pickers/Combobox.json +6 -0
  73. package/data/docs/components/pickers/MenuButton.json +5 -0
  74. package/data/docs/components/pickers/Select.json +5 -0
  75. package/data/docs/components/popovers/Dialog.json +6 -0
  76. package/data/docs/components/popovers/Toggletip.json +5 -0
  77. package/data/docs/components/popovers/Tooltip.json +4 -0
  78. package/data/docs/components/table/DataGrid.json +12 -31
  79. package/data/docs/components/table/StatefulDataGrid.json +9 -31
  80. package/data/docs/components-index.json +343 -53
  81. package/data/docs/components.json +10 -64
  82. package/data/docs/llms-full.txt +291 -68
  83. package/data/docs/llms.txt +56 -6
  84. package/data/docs/patterns-catalog.md +215 -25
  85. package/data/docs/patterns.json +369 -31
  86. package/data/metadata.json +2 -2
  87. package/data/patterns/crossfiltered-datagrid-server-side.mdx +1 -1
  88. package/data/patterns/drilldowned-datagrid-client-side.mdx +1 -1
  89. package/data/patterns/drilldowned-datagrid-server-side.mdx +1 -1
  90. package/data/patterns/single-datagrid-client-side.mdx +9 -9
  91. package/data/patterns/single-datagrid-server-side.mdx +4 -4
  92. package/data/patterns/stateful-single-datagrid-client-side.mdx +36 -20
  93. package/data/patterns/stateful-single-datagrid-server-side.mdx +46 -18
  94. package/data/patterns/tabbed-datagrid-server-side.mdx +1 -1
  95. package/data/prompts/ds-advisor.md +103 -0
  96. package/dist/data-store.d.ts +21 -1
  97. package/dist/data-store.d.ts.map +1 -1
  98. package/dist/data-store.js +65 -15
  99. package/dist/data-store.js.map +1 -1
  100. package/dist/pattern-store.d.ts +18 -1
  101. package/dist/pattern-store.d.ts.map +1 -1
  102. package/dist/pattern-store.js +64 -22
  103. package/dist/pattern-store.js.map +1 -1
  104. package/dist/prompts.d.ts.map +1 -1
  105. package/dist/prompts.js +56 -27
  106. package/dist/prompts.js.map +1 -1
  107. package/dist/resources.d.ts.map +1 -1
  108. package/dist/resources.js +26 -0
  109. package/dist/resources.js.map +1 -1
  110. package/dist/tools.d.ts.map +1 -1
  111. package/dist/tools.js +12 -0
  112. package/dist/tools.js.map +1 -1
  113. package/dist/types.d.ts +11 -0
  114. package/dist/types.d.ts.map +1 -1
  115. package/dist/types.js.map +1 -1
  116. package/package.json +4 -2
@@ -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, waitFor } 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';
@@ -55,9 +55,9 @@ import {
55
55
  TAGS_HASANYOF_LOCAL_NEW,
56
56
  } from '../_shared/expected-values';
57
57
 
58
- const meta: Meta<typeof Example> = {
58
+ const meta: Meta = {
59
59
  title: 'Patterns/Single Datagrid (Server)',
60
- component: Example,
60
+ component: Example as any,
61
61
  parameters: {
62
62
  msw: { handlers: bakeryHandlers },
63
63
  },
@@ -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"
@@ -74,7 +74,6 @@ export default ({ initialFilterModel }: { initialFilterModel?: GridFilterModel }
74
74
  pageSizeOptions={[10, 25, 50]}
75
75
  onPaginationModelChange={(model) => {
76
76
  if (model.pageSize !== pageSize) {
77
- setRows([]);
78
77
  setPageSize(model.pageSize);
79
78
  setPage(0);
80
79
  } else {
@@ -2,8 +2,7 @@ import React from 'react';
2
2
  import type { Meta, StoryObj } from '@storybook/react';
3
3
  import { within, userEvent, waitFor } from '@storybook/testing-library';
4
4
  import { expect } from '@storybook/jest';
5
- import { GridFilterModel, useGridApiRef } from '@mui/x-data-grid-pro';
6
- import type { GridApiPro } from '@mui/x-data-grid-pro';
5
+ import { GridFilterModel, useGridApiRef } from '@mui/x-data-grid-premium';
7
6
 
8
7
  import Example from './example';
9
8
  import WithLoadingExample from './with-loading';
@@ -627,12 +626,94 @@ export const SortingInteraction: Story = {
627
626
  },
628
627
  };
629
628
 
629
+ // ---------------------------------------------------------------------------
630
+ // Row Grouping — set via apiRef, assert URL
631
+ // ---------------------------------------------------------------------------
632
+
633
+ let _rowGroupingRouter: ReturnType<typeof createMockRouter>;
634
+ let _rowGroupingApiRef: ReturnType<typeof useGridApiRef>;
635
+
636
+ export const RowGroupingInteraction: Story = {
637
+ render: () => {
638
+ _rowGroupingRouter = usePersistentMockRouter();
639
+ _rowGroupingApiRef = useGridApiRef();
640
+ return <Example useRouter={_rowGroupingRouter.useRouter} apiRef={_rowGroupingApiRef} />;
641
+ },
642
+ play: async ({ canvasElement, step }) => {
643
+ const canvas = within(canvasElement);
644
+ const { getSearch } = _rowGroupingRouter;
645
+
646
+ await step('Wait for grid to load', async () => {
647
+ await waitForGridToLoad(canvas);
648
+ });
649
+
650
+ await step('Set row grouping to Category', async () => {
651
+ _rowGroupingApiRef.current!.setRowGroupingModel(['Category']);
652
+ await waitFor(() => {
653
+ expect(getSearch()).toContain('_rowGrouping=Category');
654
+ });
655
+ });
656
+
657
+ await step('Assert sync', async () => {
658
+ await assertAllStatesInSync({ getSearch, checkRowGrouping: true });
659
+ });
660
+
661
+ await step('Clear row grouping', async () => {
662
+ _rowGroupingApiRef.current!.setRowGroupingModel([]);
663
+ await waitFor(() => {
664
+ expect(getSearch()).not.toContain('_rowGrouping');
665
+ });
666
+ });
667
+ },
668
+ };
669
+
670
+ // ---------------------------------------------------------------------------
671
+ // Aggregation — set via apiRef, assert URL
672
+ // ---------------------------------------------------------------------------
673
+
674
+ let _aggregationRouter: ReturnType<typeof createMockRouter>;
675
+ let _aggregationApiRef: ReturnType<typeof useGridApiRef>;
676
+
677
+ export const AggregationInteraction: Story = {
678
+ render: () => {
679
+ _aggregationRouter = usePersistentMockRouter();
680
+ _aggregationApiRef = useGridApiRef();
681
+ return <Example useRouter={_aggregationRouter.useRouter} apiRef={_aggregationApiRef} />;
682
+ },
683
+ play: async ({ canvasElement, step }) => {
684
+ const canvas = within(canvasElement);
685
+ const { getSearch } = _aggregationRouter;
686
+
687
+ await step('Wait for grid to load', async () => {
688
+ await waitForGridToLoad(canvas);
689
+ });
690
+
691
+ await step('Set aggregation Paid=sum', async () => {
692
+ _aggregationApiRef.current!.setAggregationModel({ Paid: 'sum' });
693
+ await waitFor(() => {
694
+ expect(getSearch()).toContain('_aggregation=Paid.sum');
695
+ });
696
+ });
697
+
698
+ await step('Assert sync', async () => {
699
+ await assertAllStatesInSync({ getSearch, checkAggregation: true });
700
+ });
701
+
702
+ await step('Clear aggregation', async () => {
703
+ _aggregationApiRef.current!.setAggregationModel({});
704
+ await waitFor(() => {
705
+ expect(getSearch()).not.toContain('_aggregation');
706
+ });
707
+ });
708
+ },
709
+ };
710
+
630
711
  // ---------------------------------------------------------------------------
631
712
  // Column Order — reorder via apiRef, assert URL
632
713
  // ---------------------------------------------------------------------------
633
714
 
634
715
  let _columnOrderRouter: ReturnType<typeof createMockRouter>;
635
- let _columnOrderApiRef: React.MutableRefObject<GridApiPro>;
716
+ let _columnOrderApiRef: ReturnType<typeof useGridApiRef>;
636
717
 
637
718
  export const ColumnOrderInteraction: Story = {
638
719
  render: () => {
@@ -669,6 +750,52 @@ export const ColumnOrderInteraction: Story = {
669
750
  },
670
751
  };
671
752
 
753
+ // ---------------------------------------------------------------------------
754
+ // Pivot — activate via apiRef, assert URL
755
+ // ---------------------------------------------------------------------------
756
+
757
+ let _pivotRouter: ReturnType<typeof createMockRouter>;
758
+ let _pivotApiRef: ReturnType<typeof useGridApiRef>;
759
+
760
+ export const PivotInteraction: Story = {
761
+ render: () => {
762
+ _pivotRouter = usePersistentMockRouter();
763
+ _pivotApiRef = useGridApiRef();
764
+ return <Example useRouter={_pivotRouter.useRouter} apiRef={_pivotApiRef} />;
765
+ },
766
+ play: async ({ canvasElement, step }) => {
767
+ const canvas = within(canvasElement);
768
+ const { getSearch } = _pivotRouter;
769
+
770
+ await step('Wait for grid to load', async () => {
771
+ await waitForGridToLoad(canvas);
772
+ });
773
+
774
+ await step('Activate pivot with Category columns, Items rows, Paid sum values', async () => {
775
+ _pivotApiRef.current!.setPivotModel({
776
+ columns: [{ field: 'Category' }],
777
+ rows: [{ field: 'Items' }],
778
+ values: [{ field: 'Paid', aggFunc: 'sum' }],
779
+ });
780
+ _pivotApiRef.current!.setPivotActive(true);
781
+ await waitFor(() => {
782
+ expect(getSearch()).toContain('_pivot=');
783
+ });
784
+ });
785
+
786
+ await step('Assert pivot params in URL', async () => {
787
+ const search = getSearch();
788
+ expect(search).toContain('cols:Category');
789
+ expect(search).toContain('rows:Items');
790
+ expect(search).toContain('vals:Paid.sum');
791
+ });
792
+
793
+ await step('Assert sync', async () => {
794
+ await assertAllStatesInSync({ getSearch, checkPivot: true });
795
+ });
796
+ },
797
+ };
798
+
672
799
  // ---------------------------------------------------------------------------
673
800
  // State variants — with interaction assertions
674
801
  // ---------------------------------------------------------------------------
@@ -1,8 +1,8 @@
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';
5
- import type { GridApiPro } from '@mui/x-data-grid-pro';
4
+ import { GridFilterModel, GridRowSelectionModel, useGridApiRef } from '@mui/x-data-grid-premium';
5
+ import type { GridApiPremium } from '@mui/x-data-grid-premium';
6
6
  import { rows } from '../_shared/data';
7
7
  import { columns } from '../_shared/columns';
8
8
  import { CustomToolbar, BulkActionBar } from '../_shared/helpers';
@@ -13,20 +13,20 @@ import { StateDebugPanel } from '../_shared/StateDebugPanel';
13
13
  interface Props {
14
14
  initialFilterModel?: GridFilterModel;
15
15
  useRouter?: () => { pathname: string; search: string; historyReplace: (newSearch: string) => void };
16
- apiRef?: React.MutableRefObject<GridApiPro>;
16
+ apiRef?: React.MutableRefObject<GridApiPremium | null>;
17
17
  }
18
18
 
19
19
  export default ({ initialFilterModel, useRouter = useRouterAdapter, apiRef: propsApiRef }: Props) => {
20
20
  const internalApiRef = useGridApiRef();
21
21
  const apiRef = propsApiRef ?? internalApiRef;
22
- const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>([]);
22
+ const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(EMPTY_ROW_SELECTION_MODEL);
23
23
 
24
24
  return (
25
25
  <div style={{ width: '100%' }}>
26
26
  <StateDebugPanel apiRef={apiRef} useRouter={useRouter} localStorageVersion={1} />
27
27
  <Flexbox flexDirection="column" gap="0px">
28
28
  <BulkActionBar
29
- count={selectionModel.length}
29
+ count={getSelectionCount(selectionModel)}
30
30
  onLog={() => console.log('Selected:', selectionModel)}
31
31
  onDelete={() => console.log('Delete:', selectionModel)}
32
32
  />
@@ -2,8 +2,7 @@ import React from 'react';
2
2
  import type { Meta, StoryObj } from '@storybook/react';
3
3
  import { within, userEvent, waitFor } from '@storybook/testing-library';
4
4
  import { expect } from '@storybook/jest';
5
- import { GridFilterModel, useGridApiRef } from '@mui/x-data-grid-pro';
6
- import type { GridApiPro } from '@mui/x-data-grid-pro';
5
+ import { GridFilterModel, useGridApiRef } from '@mui/x-data-grid-premium';
7
6
 
8
7
  import Example from './example';
9
8
  import WithLoadingExample from './with-loading';
@@ -387,9 +386,7 @@ export const SelectionPersistsAcrossPages: Story = {
387
386
  await waitForServerResponse(canvas);
388
387
  await assertDisplayedRowsText(canvasElement, '11–20 of 14,075');
389
388
  await assertBulkActionBarVisible(canvasElement, 2);
390
- // In MUI v7, the header checkbox reflects current-page selection only.
391
- // No page-2 rows are selected, so the header is unchecked (not indeterminate).
392
- await assertHeaderCheckboxState(canvasElement, 'unchecked');
389
+ await assertHeaderCheckboxState(canvasElement, 'indeterminate');
393
390
  await assertRowCheckboxChecked(canvasElement, 0, false);
394
391
  await assertAllStatesInSync({ getSearch });
395
392
  });
@@ -648,12 +645,98 @@ export const SortingInteraction: Story = {
648
645
  },
649
646
  };
650
647
 
648
+ // ---------------------------------------------------------------------------
649
+ // Row Grouping — set via apiRef, assert URL
650
+ // ---------------------------------------------------------------------------
651
+
652
+ let _rowGroupingRouter: ReturnType<typeof createMockRouter>;
653
+ let _rowGroupingApiRef: ReturnType<typeof useGridApiRef>;
654
+
655
+ export const RowGroupingInteraction: Story = {
656
+ render: () => {
657
+ _rowGroupingRouter = usePersistentMockRouter();
658
+ _rowGroupingApiRef = useGridApiRef();
659
+ return <Example useRouter={_rowGroupingRouter.useRouter} apiRef={_rowGroupingApiRef} />;
660
+ },
661
+ play: async ({ canvasElement, step }) => {
662
+ const canvas = within(canvasElement);
663
+ const { getSearch } = _rowGroupingRouter;
664
+
665
+ await step('Wait for grid to load', async () => {
666
+ await waitForGridToLoad(canvas);
667
+ });
668
+
669
+ await step('Set row grouping to Category', async () => {
670
+ _rowGroupingApiRef.current!.setRowGroupingModel(['Category']);
671
+ await waitForServerResponse(canvas);
672
+ await waitFor(() => {
673
+ expect(getSearch()).toContain('_rowGrouping=Category');
674
+ });
675
+ });
676
+
677
+ await step('Assert sync', async () => {
678
+ await assertAllStatesInSync({ getSearch, checkRowGrouping: true });
679
+ });
680
+
681
+ await step('Clear row grouping', async () => {
682
+ _rowGroupingApiRef.current!.setRowGroupingModel([]);
683
+ await waitForServerResponse(canvas);
684
+ await waitFor(() => {
685
+ expect(getSearch()).not.toContain('_rowGrouping');
686
+ });
687
+ });
688
+ },
689
+ };
690
+
691
+ // ---------------------------------------------------------------------------
692
+ // Aggregation — set via apiRef, assert URL
693
+ // ---------------------------------------------------------------------------
694
+
695
+ let _aggregationRouter: ReturnType<typeof createMockRouter>;
696
+ let _aggregationApiRef: ReturnType<typeof useGridApiRef>;
697
+
698
+ export const AggregationInteraction: Story = {
699
+ render: () => {
700
+ _aggregationRouter = usePersistentMockRouter();
701
+ _aggregationApiRef = useGridApiRef();
702
+ return <Example useRouter={_aggregationRouter.useRouter} apiRef={_aggregationApiRef} />;
703
+ },
704
+ play: async ({ canvasElement, step }) => {
705
+ const canvas = within(canvasElement);
706
+ const { getSearch } = _aggregationRouter;
707
+
708
+ await step('Wait for grid to load', async () => {
709
+ await waitForGridToLoad(canvas);
710
+ });
711
+
712
+ await step('Set aggregation Paid=sum', async () => {
713
+ _aggregationApiRef.current!.setAggregationModel({ Paid: 'sum' });
714
+ await waitForServerResponse(canvas);
715
+ await waitFor(() => {
716
+ expect(getSearch()).toContain('_aggregation=Paid.sum');
717
+ });
718
+ });
719
+
720
+ await step('Assert sync', async () => {
721
+ await assertAllStatesInSync({ getSearch, checkAggregation: true });
722
+ });
723
+
724
+ await step('Clear aggregation', async () => {
725
+ _aggregationApiRef.current!.setAggregationModel({});
726
+ await waitForServerResponse(canvas);
727
+ await waitFor(() => {
728
+ expect(getSearch()).not.toContain('_aggregation');
729
+ });
730
+ });
731
+ },
732
+ };
733
+
651
734
  // ---------------------------------------------------------------------------
652
735
  // Column Order — reorder via apiRef, assert URL
653
736
  // ---------------------------------------------------------------------------
654
737
 
655
738
  let _columnOrderRouter: ReturnType<typeof createMockRouter>;
656
- let _columnOrderApiRef: React.MutableRefObject<GridApiPro>;
739
+ let _columnOrderApiRef: ReturnType<typeof useGridApiRef>;
657
740
 
658
741
  export const ColumnOrderInteraction: Story = {
659
742
  render: () => {
@@ -690,6 +773,53 @@ export const ColumnOrderInteraction: Story = {
690
773
  },
691
774
  };
692
775
 
776
+ // ---------------------------------------------------------------------------
777
+ // Pivot — activate via apiRef, assert URL
778
+ // ---------------------------------------------------------------------------
779
+
780
+ let _pivotRouter: ReturnType<typeof createMockRouter>;
781
+ let _pivotApiRef: ReturnType<typeof useGridApiRef>;
782
+
783
+ export const PivotInteraction: Story = {
784
+ render: () => {
785
+ _pivotRouter = usePersistentMockRouter();
786
+ _pivotApiRef = useGridApiRef();
787
+ return <Example useRouter={_pivotRouter.useRouter} apiRef={_pivotApiRef} />;
788
+ },
789
+ play: async ({ canvasElement, step }) => {
790
+ const canvas = within(canvasElement);
791
+ const { getSearch } = _pivotRouter;
792
+
793
+ await step('Wait for grid to load', async () => {
794
+ await waitForGridToLoad(canvas);
795
+ });
796
+
797
+ await step('Activate pivot with Category columns, Items rows, Paid sum values', async () => {
798
+ _pivotApiRef.current!.setPivotModel({
799
+ columns: [{ field: 'Category' }],
800
+ rows: [{ field: 'Items' }],
801
+ values: [{ field: 'Paid', aggFunc: 'sum' }],
802
+ });
803
+ _pivotApiRef.current!.setPivotActive(true);
804
+ await waitForServerResponse(canvas);
805
+ await waitFor(() => {
806
+ expect(getSearch()).toContain('_pivot=');
807
+ });
808
+ });
809
+
810
+ await step('Assert pivot params in URL', async () => {
811
+ const search = getSearch();
812
+ expect(search).toContain('cols:Category');
813
+ expect(search).toContain('rows:Items');
814
+ expect(search).toContain('vals:Paid.sum');
815
+ });
816
+
817
+ await step('Assert sync', async () => {
818
+ await assertAllStatesInSync({ getSearch, checkPivot: true });
819
+ });
820
+ },
821
+ };
822
+
693
823
  // ---------------------------------------------------------------------------
694
824
  // State variants — with interaction assertions
695
825
  // ---------------------------------------------------------------------------
@@ -1,8 +1,8 @@
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';
5
- import type { GridApiPro } from '@mui/x-data-grid-pro';
4
+ import { GridFilterModel, GridRowSelectionModel, GridSortModel, useGridApiRef } from '@mui/x-data-grid-premium';
5
+ import type { GridApiPremium } from '@mui/x-data-grid-premium';
6
6
  import { Row } from '../_shared/data';
7
7
  import { columns } from '../_shared/columns';
8
8
  import { fetchBakeryData } from '../_shared/api-client';
@@ -14,7 +14,7 @@ import { StateDebugPanel } from '../_shared/StateDebugPanel';
14
14
  interface Props {
15
15
  initialFilterModel?: GridFilterModel;
16
16
  useRouter?: () => { pathname: string; search: string; historyReplace: (newSearch: string) => void };
17
- apiRef?: React.MutableRefObject<GridApiPro>;
17
+ apiRef?: React.MutableRefObject<GridApiPremium | null>;
18
18
  }
19
19
 
20
20
  export default ({ initialFilterModel, useRouter = useRouterAdapter, apiRef: propsApiRef }: Props) => {
@@ -23,7 +23,7 @@ export default ({ initialFilterModel, useRouter = useRouterAdapter, apiRef: prop
23
23
  const [rows, setRows] = useState<Row[]>([]);
24
24
  const [totalRows, setTotalRows] = useState(0);
25
25
  const [loading, setLoading] = useState(true);
26
- const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>([]);
26
+ const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(EMPTY_ROW_SELECTION_MODEL);
27
27
 
28
28
  // Refs track the latest model values so fetchData() always reads current state.
29
29
  // StatefulDataGrid manages filter/sort/pagination internally — we use callbacks
@@ -58,7 +58,7 @@ export default ({ initialFilterModel, useRouter = useRouterAdapter, apiRef: prop
58
58
  <StateDebugPanel apiRef={apiRef} useRouter={useRouter} localStorageVersion={1} />
59
59
  <Flexbox flexDirection="column" gap="0px">
60
60
  <BulkActionBar
61
- count={selectionModel.length}
61
+ count={getSelectionCount(selectionModel)}
62
62
  onLog={() => console.log('Selected:', selectionModel)}
63
63
  onDelete={() => console.log('Delete:', selectionModel)}
64
64
  />
@@ -94,9 +94,6 @@ export default ({ initialFilterModel, useRouter = useRouterAdapter, apiRef: prop
94
94
  fetchData();
95
95
  }}
96
96
  onPaginationModelChange={(model) => {
97
- if (model.pageSize !== pageSizeRef.current) {
98
- setRows([]);
99
- }
100
97
  pageRef.current = model.page;
101
98
  pageSizeRef.current = model.pageSize;
102
99
  fetchData();
@@ -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;
@@ -17,9 +17,9 @@ import {
17
17
  } from '../_shared/story-helpers';
18
18
  import { TOTAL, CATEGORY_BAKERY, CATEGORY_BEVERAGE, CATEGORY_PASTRY, CATEGORY_OTHER } from '../_shared/expected-values';
19
19
 
20
- const meta: Meta<typeof Example> = {
20
+ const meta: Meta = {
21
21
  title: 'Patterns/Tabbed Datagrid (Client)',
22
- component: Example,
22
+ component: Example as any,
23
23
  };
24
24
  export default meta;
25
25
  type Story = StoryObj;
@@ -19,9 +19,9 @@ import {
19
19
  } from '../_shared/story-helpers';
20
20
  import { TOTAL, CATEGORY_BAKERY, CATEGORY_BEVERAGE, CATEGORY_PASTRY, CATEGORY_OTHER } from '../_shared/expected-values';
21
21
 
22
- const meta: Meta<typeof Example> = {
22
+ const meta: Meta = {
23
23
  title: 'Patterns/Tabbed Datagrid (Server)',
24
- component: Example,
24
+ component: Example as any,
25
25
  parameters: {
26
26
  msw: { handlers: bakeryHandlers },
27
27
  },
@@ -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';
@@ -265,5 +265,10 @@
265
265
  }
266
266
  ],
267
267
  "examples": [],
268
- "tags": {}
268
+ "tags": {},
269
+ "keywords": [
270
+ "chart axis",
271
+ "x axis",
272
+ "y axis"
273
+ ]
269
274
  }
@@ -848,5 +848,11 @@
848
848
  }
849
849
  ],
850
850
  "examples": [],
851
- "tags": {}
851
+ "tags": {},
852
+ "keywords": [
853
+ "bar graph",
854
+ "histogram",
855
+ "column chart",
856
+ "bar visualization"
857
+ ]
852
858
  }
@@ -570,5 +570,9 @@
570
570
  }
571
571
  ],
572
572
  "examples": [],
573
- "tags": {}
573
+ "tags": {},
574
+ "keywords": [
575
+ "chart title",
576
+ "chart heading"
577
+ ]
574
578
  }
@@ -506,5 +506,10 @@
506
506
  }
507
507
  ],
508
508
  "examples": [],
509
- "tags": {}
509
+ "tags": {},
510
+ "keywords": [
511
+ "chart legend",
512
+ "color legend",
513
+ "series legend"
514
+ ]
510
515
  }
@@ -749,5 +749,11 @@
749
749
  }
750
750
  ],
751
751
  "examples": [],
752
- "tags": {}
752
+ "tags": {},
753
+ "keywords": [
754
+ "line graph",
755
+ "time series",
756
+ "trend chart",
757
+ "line visualization"
758
+ ]
753
759
  }
@@ -822,5 +822,10 @@
822
822
  }
823
823
  ],
824
824
  "examples": [],
825
- "tags": {}
825
+ "tags": {},
826
+ "keywords": [
827
+ "pie graph",
828
+ "donut chart",
829
+ "pie visualization"
830
+ ]
826
831
  }
@@ -798,5 +798,10 @@
798
798
  }
799
799
  ],
800
800
  "examples": [],
801
- "tags": {}
801
+ "tags": {},
802
+ "keywords": [
803
+ "scatter graph",
804
+ "dot plot",
805
+ "scatter visualization"
806
+ ]
802
807
  }