argent-grid 0.1.0 → 0.3.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 (122) hide show
  1. package/.github/workflows/ci.yml +69 -0
  2. package/.github/workflows/pages.yml +6 -12
  3. package/.storybook/main.ts +20 -0
  4. package/.storybook/preview.ts +18 -0
  5. package/.storybook/tsconfig.json +24 -0
  6. package/AGENTS.md +70 -27
  7. package/README.md +51 -34
  8. package/angular.json +66 -0
  9. package/biome.json +66 -0
  10. package/demo-app/e2e/selection-screenshot.spec.ts +20 -0
  11. package/docs/AG-GRID-COMPARISON.md +725 -0
  12. package/docs/CELL-RENDERER-GUIDE.md +241 -0
  13. package/docs/CONTEXT-MENU-GUIDE.md +371 -0
  14. package/docs/LIVE-DATA-OPTIMIZATIONS.md +497 -0
  15. package/docs/PERFORMANCE-OPTIMIZATIONS-PHASE1.md +162 -0
  16. package/docs/PERFORMANCE-REVIEW.md +571 -0
  17. package/docs/RESEARCH-STATUS.md +234 -0
  18. package/docs/STATE-PERSISTENCE-GUIDE.md +370 -0
  19. package/docs/STORYBOOK-REFACTOR.md +215 -0
  20. package/docs/STORYBOOK-STATUS.md +156 -0
  21. package/docs/TEST-COVERAGE-REPORT.md +276 -0
  22. package/docs/THEME-API-GUIDE.md +445 -0
  23. package/docs/THEME-API-PLAN.md +364 -0
  24. package/e2e/advanced.spec.ts +109 -0
  25. package/e2e/argentgrid.spec.ts +65 -0
  26. package/e2e/benchmark.spec.ts +52 -0
  27. package/e2e/cell-renderers.spec.ts +152 -0
  28. package/e2e/debug-streaming.spec.ts +31 -0
  29. package/e2e/dnd.spec.ts +73 -0
  30. package/e2e/screenshots.spec.ts +52 -0
  31. package/e2e/theming.spec.ts +35 -0
  32. package/e2e/visual.spec.ts +112 -0
  33. package/e2e/visual.spec.ts-snapshots/checkbox-renderer-mixed.png +0 -0
  34. package/e2e/visual.spec.ts-snapshots/debug.png +0 -0
  35. package/e2e/visual.spec.ts-snapshots/grid-column-group-headers.png +0 -0
  36. package/e2e/visual.spec.ts-snapshots/grid-default.png +0 -0
  37. package/e2e/visual.spec.ts-snapshots/grid-empty-state.png +0 -0
  38. package/e2e/visual.spec.ts-snapshots/grid-filter-popup.png +0 -0
  39. package/e2e/visual.spec.ts-snapshots/grid-scroll-borders.png +0 -0
  40. package/e2e/visual.spec.ts-snapshots/grid-sidebar-buttons.png +0 -0
  41. package/e2e/visual.spec.ts-snapshots/grid-text-filter.png +0 -0
  42. package/e2e/visual.spec.ts-snapshots/grid-with-selection.png +0 -0
  43. package/e2e/visual.spec.ts-snapshots/rating-renderer-varied.png +0 -0
  44. package/package.json +21 -7
  45. package/plan.md +56 -28
  46. package/playwright.config.ts +38 -0
  47. package/setup-vitest.ts +10 -13
  48. package/src/lib/argent-grid.module.ts +10 -12
  49. package/src/lib/components/argent-grid.component.css +281 -321
  50. package/src/lib/components/argent-grid.component.html +295 -207
  51. package/src/lib/components/argent-grid.component.spec.ts +120 -160
  52. package/src/lib/components/argent-grid.component.ts +1193 -290
  53. package/src/lib/components/argent-grid.regressions.spec.ts +301 -0
  54. package/src/lib/components/argent-grid.selection.spec.ts +132 -0
  55. package/src/lib/components/set-filter/set-filter.component.spec.ts +191 -0
  56. package/src/lib/components/set-filter/set-filter.component.ts +307 -0
  57. package/src/lib/directives/ag-grid-compatibility.directive.ts +16 -26
  58. package/src/lib/directives/click-outside.directive.ts +19 -0
  59. package/src/lib/rendering/canvas-renderer.spec.ts +513 -0
  60. package/src/lib/rendering/canvas-renderer.ts +456 -452
  61. package/src/lib/rendering/live-data-handler.ts +110 -0
  62. package/src/lib/rendering/live-data-optimizations.ts +133 -0
  63. package/src/lib/rendering/render/blit.spec.ts +16 -27
  64. package/src/lib/rendering/render/blit.ts +48 -36
  65. package/src/lib/rendering/render/cells.spec.ts +132 -0
  66. package/src/lib/rendering/render/cells.ts +167 -28
  67. package/src/lib/rendering/render/column-utils.ts +95 -0
  68. package/src/lib/rendering/render/hit-test.ts +50 -0
  69. package/src/lib/rendering/render/index.ts +88 -76
  70. package/src/lib/rendering/render/lines.ts +53 -47
  71. package/src/lib/rendering/render/primitives.ts +423 -0
  72. package/src/lib/rendering/render/theme.spec.ts +8 -12
  73. package/src/lib/rendering/render/theme.ts +7 -10
  74. package/src/lib/rendering/render/types.ts +3 -2
  75. package/src/lib/rendering/render/walk.spec.ts +35 -38
  76. package/src/lib/rendering/render/walk.ts +94 -64
  77. package/src/lib/rendering/utils/damage-tracker.spec.ts +8 -7
  78. package/src/lib/rendering/utils/damage-tracker.ts +6 -18
  79. package/src/lib/rendering/utils/index.ts +1 -1
  80. package/src/lib/services/grid.service.set-filter.spec.ts +219 -0
  81. package/src/lib/services/grid.service.spec.ts +1241 -201
  82. package/src/lib/services/grid.service.ts +1204 -235
  83. package/src/lib/themes/parts/color-schemes.ts +132 -0
  84. package/src/lib/themes/parts/icon-sets.ts +258 -0
  85. package/src/lib/themes/theme-builder.ts +347 -0
  86. package/src/lib/themes/theme-quartz.ts +72 -0
  87. package/src/lib/themes/types.ts +238 -0
  88. package/src/lib/types/ag-grid-types.ts +573 -14
  89. package/src/public-api.ts +39 -9
  90. package/src/stories/Advanced.stories.ts +249 -0
  91. package/src/stories/ArgentGrid.stories.ts +301 -0
  92. package/src/stories/Benchmark.stories.ts +76 -0
  93. package/src/stories/CellRenderers.stories.ts +395 -0
  94. package/src/stories/Filtering.stories.ts +292 -0
  95. package/src/stories/Grouping.stories.ts +290 -0
  96. package/src/stories/Streaming.stories.ts +57 -0
  97. package/src/stories/Theming.stories.ts +137 -0
  98. package/src/stories/Tooltips.stories.ts +381 -0
  99. package/src/stories/benchmark-wrapper.component.ts +355 -0
  100. package/src/stories/story-utils.ts +88 -0
  101. package/src/stories/streaming-wrapper.component.ts +441 -0
  102. package/tsconfig.json +1 -0
  103. package/tsconfig.storybook.json +10 -0
  104. package/vitest.config.ts +9 -9
  105. package/demo-app/README.md +0 -70
  106. package/demo-app/angular.json +0 -78
  107. package/demo-app/e2e/benchmark.spec.ts +0 -53
  108. package/demo-app/e2e/demo-page.spec.ts +0 -77
  109. package/demo-app/e2e/grid-features.spec.ts +0 -269
  110. package/demo-app/package-lock.json +0 -14023
  111. package/demo-app/package.json +0 -36
  112. package/demo-app/playwright-test-menu.js +0 -19
  113. package/demo-app/playwright.config.ts +0 -23
  114. package/demo-app/src/app/app.component.ts +0 -10
  115. package/demo-app/src/app/app.config.ts +0 -13
  116. package/demo-app/src/app/app.routes.ts +0 -7
  117. package/demo-app/src/app/demo-page/demo-page.component.css +0 -313
  118. package/demo-app/src/app/demo-page/demo-page.component.html +0 -124
  119. package/demo-app/src/app/demo-page/demo-page.component.ts +0 -366
  120. package/demo-app/src/index.html +0 -19
  121. package/demo-app/src/main.ts +0 -6
  122. package/demo-app/tsconfig.json +0 -31
@@ -0,0 +1,395 @@
1
+ import { BrowserModule } from '@angular/platform-browser';
2
+ import type { Meta, StoryObj } from '@storybook/angular';
3
+ import { moduleMetadata } from '@storybook/angular';
4
+ import { ArgentGridComponent, ArgentGridModule, themeQuartz } from '../public-api';
5
+ import { STORY_LOCATIONS } from './story-utils';
6
+
7
+ interface Employee {
8
+ id: number;
9
+ name: string;
10
+ department: string;
11
+ role: string;
12
+ salary: number;
13
+ salaryTrend: number[];
14
+ location: string;
15
+ performance: number;
16
+ status: string;
17
+ }
18
+
19
+ const meta: Meta<ArgentGridComponent<Employee>> = {
20
+ title: 'Features/CellRenderers',
21
+ component: ArgentGridComponent,
22
+ decorators: [
23
+ moduleMetadata({
24
+ imports: [ArgentGridModule, BrowserModule],
25
+ }),
26
+ ],
27
+ parameters: {
28
+ layout: 'fullscreen',
29
+ },
30
+ };
31
+
32
+ export default meta;
33
+ type Story = StoryObj<ArgentGridComponent<Employee>>;
34
+
35
+ function generateStaticData(count: number): Employee[] {
36
+ const departments = ['Engineering', 'Sales', 'Marketing', 'HR', 'Finance'];
37
+ const roles = ['Engineer', 'Manager', 'Director', 'VP', 'Intern'];
38
+ const locations = STORY_LOCATIONS;
39
+ const statuses = ['Active', 'On Leave', 'Remote', 'Travel'];
40
+
41
+ return Array.from({ length: count }, (_, i) => ({
42
+ id: i + 1,
43
+ name: `Employee ${i + 1}`,
44
+ department: departments[i % departments.length],
45
+ role: roles[i % roles.length],
46
+ salary: 50000 + i * 1000,
47
+ salaryTrend: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100].map((v) => (v + i * 5) % 100),
48
+ location: locations[i % locations.length],
49
+ // Use deterministic "semi-random" patterns based on index for stable E2E screenshots
50
+ performance: 60 + ((i * 7) % 40),
51
+ status: statuses[(i * 3) % statuses.length],
52
+ }));
53
+ }
54
+
55
+ export const SparklineArea: Story = {
56
+ args: {
57
+ columnDefs: [
58
+ { field: 'id', headerName: 'ID', width: 80 },
59
+ { field: 'name', headerName: 'Name', width: 200 },
60
+ { field: 'department', headerName: 'Department', width: 180 },
61
+ {
62
+ field: 'salaryTrend',
63
+ headerName: 'Salary Trend',
64
+ width: 200,
65
+ cellRenderer: 'sparkline',
66
+ sparklineOptions: {
67
+ type: 'area',
68
+ area: {
69
+ fill: 'rgba(74, 222, 128, 0.2)',
70
+ stroke: '#4ade80',
71
+ strokeWidth: 2,
72
+ },
73
+ },
74
+ },
75
+ ],
76
+ rowData: generateStaticData(50),
77
+ height: 'calc(100vh - 60px)',
78
+ width: '100%',
79
+ theme: themeQuartz,
80
+ },
81
+ parameters: {
82
+ docs: {
83
+ description: {
84
+ story: 'Area sparkline showing salary trend data over time.',
85
+ },
86
+ },
87
+ },
88
+ };
89
+
90
+ export const SparklineLine: Story = {
91
+ args: {
92
+ columnDefs: [
93
+ { field: 'id', headerName: 'ID', width: 80 },
94
+ { field: 'name', headerName: 'Name', width: 200 },
95
+ { field: 'department', headerName: 'Department', width: 180 },
96
+ {
97
+ field: 'salaryTrend',
98
+ headerName: 'Trend',
99
+ width: 150,
100
+ cellRenderer: 'sparkline',
101
+ sparklineOptions: {
102
+ type: 'line',
103
+ line: {
104
+ stroke: '#3b82f6',
105
+ strokeWidth: 2,
106
+ },
107
+ },
108
+ },
109
+ ],
110
+ rowData: generateStaticData(50),
111
+ height: 'calc(100vh - 60px)',
112
+ width: '100%',
113
+ theme: themeQuartz,
114
+ },
115
+ parameters: {
116
+ docs: {
117
+ description: {
118
+ story: 'Line sparkline showing trend data.',
119
+ },
120
+ },
121
+ },
122
+ };
123
+
124
+ export const SparklineBar: Story = {
125
+ args: {
126
+ columnDefs: [
127
+ { field: 'id', headerName: 'ID', width: 80 },
128
+ { field: 'name', headerName: 'Name', width: 200 },
129
+ { field: 'department', headerName: 'Department', width: 180 },
130
+ {
131
+ field: 'salaryTrend',
132
+ headerName: 'Salary Trend',
133
+ width: 200,
134
+ cellRenderer: 'sparkline',
135
+ sparklineOptions: {
136
+ type: 'bar',
137
+ bar: {
138
+ fill: '#6366f1',
139
+ strokeWidth: 0,
140
+ },
141
+ },
142
+ },
143
+ ],
144
+ rowData: generateStaticData(50),
145
+ height: 'calc(100vh - 60px)',
146
+ width: '100%',
147
+ theme: themeQuartz,
148
+ },
149
+ parameters: {
150
+ docs: {
151
+ description: {
152
+ story: 'Bar sparkline showing salary trend data as a series of vertical bars.',
153
+ },
154
+ },
155
+ },
156
+ };
157
+
158
+ export const ProgressBar: Story = {
159
+ args: {
160
+ columnDefs: [
161
+ { field: 'id', headerName: 'ID', width: 80 },
162
+ { field: 'name', headerName: 'Name', width: 200 },
163
+ { field: 'department', headerName: 'Department', width: 180 },
164
+ {
165
+ field: 'performance',
166
+ headerName: 'Performance',
167
+ width: 180,
168
+ progressOptions: {
169
+ min: 0,
170
+ max: 100,
171
+ fill: (value: number) => (value >= 80 ? '#22c55e' : value >= 60 ? '#eab308' : '#ef4444'),
172
+ showLabel: true,
173
+ },
174
+ },
175
+ ],
176
+ rowData: generateStaticData(50),
177
+ height: 'calc(100vh - 60px)',
178
+ width: '100%',
179
+ theme: themeQuartz,
180
+ },
181
+ parameters: {
182
+ docs: {
183
+ description: {
184
+ story:
185
+ 'Built-in progress bar cell renderer with traffic-light color coding (green ≥ 80, yellow ≥ 60, red < 60).',
186
+ },
187
+ },
188
+ },
189
+ };
190
+
191
+ export const StatusBadge: Story = {
192
+ args: {
193
+ columnDefs: [
194
+ { field: 'id', headerName: 'ID', width: 80 },
195
+ { field: 'name', headerName: 'Name', width: 200 },
196
+ { field: 'department', headerName: 'Department', width: 180 },
197
+ {
198
+ field: 'status',
199
+ headerName: 'Status',
200
+ width: 120,
201
+ badgeOptions: {
202
+ colorMap: {
203
+ Active: { fill: '#dcfce7', text: '#16a34a' },
204
+ 'On Leave': { fill: '#fef3c7', text: '#d97706' },
205
+ Remote: { fill: '#dbeafe', text: '#2563eb' },
206
+ Travel: { fill: '#f3e8ff', text: '#9333ea' },
207
+ },
208
+ defaultColors: { fill: '#f3f4f6', text: '#6b7280' },
209
+ },
210
+ },
211
+ { field: 'salary', headerName: 'Salary', width: 120 },
212
+ ],
213
+ rowData: generateStaticData(50),
214
+ height: 'calc(100vh - 60px)',
215
+ width: '100%',
216
+ theme: themeQuartz,
217
+ },
218
+ parameters: {
219
+ docs: {
220
+ description: {
221
+ story:
222
+ 'Built-in badge cell renderer with per-value color mapping (green = Active, yellow = On Leave, blue = Remote, purple = Travel).',
223
+ },
224
+ },
225
+ },
226
+ };
227
+
228
+ export const ButtonCell: Story = {
229
+ args: {
230
+ columnDefs: [
231
+ { field: 'id', headerName: 'ID', width: 80 },
232
+ { field: 'name', headerName: 'Name', width: 200 },
233
+ { field: 'department', headerName: 'Department', width: 180 },
234
+ {
235
+ field: 'status',
236
+ headerName: 'Action',
237
+ width: 140,
238
+ buttonOptions: {
239
+ label: 'View Details',
240
+ variant: 'primary',
241
+ onClick: (params: any) => {
242
+ alert(`Clicked row ${params.node.rowIndex}: ${params.data.name}`);
243
+ },
244
+ },
245
+ },
246
+ {
247
+ field: 'status',
248
+ headerName: 'Delete',
249
+ width: 120,
250
+ buttonOptions: {
251
+ label: 'Remove',
252
+ variant: 'danger',
253
+ onClick: (params: any) => {
254
+ alert(`Delete ${params.data.name}?`);
255
+ },
256
+ },
257
+ },
258
+ {
259
+ field: 'status',
260
+ headerName: 'Export',
261
+ width: 120,
262
+ buttonOptions: {
263
+ label: 'Export',
264
+ variant: 'secondary',
265
+ onClick: (params: any) => {
266
+ alert(`Export ${params.data.name}`);
267
+ },
268
+ },
269
+ },
270
+ ],
271
+ rowData: generateStaticData(50),
272
+ height: 'calc(100vh - 60px)',
273
+ width: '100%',
274
+ theme: themeQuartz,
275
+ },
276
+ parameters: {
277
+ docs: {
278
+ description: {
279
+ story:
280
+ 'Built-in button cell renderer with `primary`, `danger`, and `secondary` variants. `onClick` receives AG Grid-compatible params: `{ value, data, node, api, colDef, event }`.',
281
+ },
282
+ },
283
+ },
284
+ };
285
+
286
+ export const CurrencyFormatter: Story = {
287
+ args: {
288
+ columnDefs: [
289
+ { field: 'id', headerName: 'ID', width: 80 },
290
+ { field: 'name', headerName: 'Name', width: 200 },
291
+ { field: 'department', headerName: 'Department', width: 180 },
292
+ {
293
+ field: 'salary',
294
+ headerName: 'Salary',
295
+ width: 130,
296
+ valueFormatter: (params: any) => (params.value ? `$${params.value.toLocaleString()}` : ''),
297
+ },
298
+ ],
299
+ rowData: generateStaticData(50),
300
+ height: 'calc(100vh - 60px)',
301
+ width: '100%',
302
+ theme: themeQuartz,
303
+ },
304
+ parameters: {
305
+ docs: {
306
+ description: {
307
+ story: 'Currency formatter showing salary with dollar sign and comma separators.',
308
+ },
309
+ },
310
+ },
311
+ };
312
+
313
+ export const CheckboxRenderer: Story = {
314
+ args: {
315
+ columnDefs: [
316
+ { field: 'id', headerName: 'ID', width: 80 },
317
+ { field: 'name', headerName: 'Name', width: 200 },
318
+ {
319
+ field: 'performance',
320
+ headerName: 'High Perf?',
321
+ width: 120,
322
+ cellRenderer: 'checkbox',
323
+ // Example: boolean logic for checkbox
324
+ valueGetter: (params: any) => params.data.performance >= 80,
325
+ },
326
+ {
327
+ field: 'status',
328
+ headerName: 'Remote?',
329
+ width: 120,
330
+ cellRenderer: 'checkbox',
331
+ valueGetter: (params: any) => params.data.status === 'Remote',
332
+ },
333
+ ],
334
+ rowData: generateStaticData(50),
335
+ height: 'calc(100vh - 60px)',
336
+ width: '100%',
337
+ theme: themeQuartz,
338
+ },
339
+ parameters: {
340
+ docs: {
341
+ description: {
342
+ story:
343
+ 'Dedicated **checkbox cell renderer**. Renders a boolean value as a centered checkbox. ' +
344
+ 'Can be used with `valueGetter` to derive boolean state from complex data.',
345
+ },
346
+ },
347
+ },
348
+ };
349
+
350
+ export const RatingRenderer: Story = {
351
+ args: {
352
+ columnDefs: [
353
+ { field: 'id', headerName: 'ID', width: 80 },
354
+ { field: 'name', headerName: 'Name', width: 200 },
355
+ {
356
+ field: 'performance',
357
+ headerName: 'Performance',
358
+ width: 150,
359
+ cellRenderer: 'rating',
360
+ // Scale 60-100 to 0-5 stars
361
+ valueGetter: (params: any) => (params.data.performance - 60) / 8,
362
+ ratingOptions: {
363
+ color: '#ffb400',
364
+ size: 16,
365
+ },
366
+ },
367
+ {
368
+ field: 'performance',
369
+ headerName: 'Stars (Small)',
370
+ width: 120,
371
+ cellRenderer: 'rating',
372
+ valueGetter: (params: any) => (params.data.performance - 60) / 8,
373
+ ratingOptions: {
374
+ color: '#3b82f6',
375
+ size: 10,
376
+ max: 5,
377
+ },
378
+ },
379
+ ],
380
+ rowData: generateStaticData(50),
381
+ height: 'calc(100vh - 60px)',
382
+ width: '100%',
383
+ theme: themeQuartz,
384
+ },
385
+ parameters: {
386
+ docs: {
387
+ description: {
388
+ story:
389
+ '**Rating cell renderer** using SVG-style star shapes on Canvas. ' +
390
+ 'Supports custom colors, sizes, and max star count. ' +
391
+ 'Great for visualising scores or feedback.',
392
+ },
393
+ },
394
+ },
395
+ };
@@ -0,0 +1,292 @@
1
+ import { BrowserModule } from '@angular/platform-browser';
2
+ import type { Meta, StoryObj } from '@storybook/angular';
3
+ import { moduleMetadata } from '@storybook/angular';
4
+ import { ArgentGridComponent, ArgentGridModule, themeQuartz } from '../public-api';
5
+ import {
6
+ departmentValueFormatter,
7
+ locationValueFormatter,
8
+ roleValueFormatter,
9
+ STORY_DEPARTMENTS,
10
+ STORY_LOCATIONS,
11
+ STORY_ROLES,
12
+ } from './story-utils';
13
+
14
+ interface Employee {
15
+ id: number;
16
+ name: string;
17
+ department: string;
18
+ role: string;
19
+ salary: number;
20
+ location: string;
21
+ startDate: string;
22
+ }
23
+
24
+ const meta: Meta<ArgentGridComponent<Employee>> = {
25
+ title: 'Features/Filtering',
26
+ component: ArgentGridComponent,
27
+ decorators: [
28
+ moduleMetadata({
29
+ imports: [ArgentGridModule, BrowserModule],
30
+ }),
31
+ ],
32
+ parameters: {
33
+ layout: 'fullscreen',
34
+ },
35
+ };
36
+
37
+ export default meta;
38
+ type Story = StoryObj<ArgentGridComponent<Employee>>;
39
+
40
+ function generateStaticData(count: number): Employee[] {
41
+ const departments = STORY_DEPARTMENTS;
42
+ const roles = STORY_ROLES;
43
+ const locations = STORY_LOCATIONS;
44
+
45
+ return Array.from({ length: count }, (_, i) => ({
46
+ id: i + 1,
47
+ name: `Employee ${i + 1}`,
48
+ department: departments[i % departments.length],
49
+ role: roles[i % roles.length],
50
+ salary: 50000 + i * 1000,
51
+ location: locations[i % locations.length],
52
+ startDate: '2020-01-01',
53
+ }));
54
+ }
55
+
56
+ export const TextFilter: Story = {
57
+ args: {
58
+ columnDefs: [
59
+ { field: 'id', headerName: 'ID', width: 80 },
60
+ {
61
+ field: 'name',
62
+ headerName: 'Name 🔤',
63
+ width: 200,
64
+ filter: 'text',
65
+ floatingFilter: true,
66
+ headerComponentParams: { filterIcon: '🔤' },
67
+ },
68
+ {
69
+ field: 'department',
70
+ headerName: 'Department 🔤',
71
+ width: 180,
72
+ filter: 'text',
73
+ floatingFilter: true,
74
+ headerComponentParams: { filterIcon: '🔤' },
75
+ valueFormatter: departmentValueFormatter,
76
+ },
77
+ {
78
+ field: 'role',
79
+ headerName: 'Role 🔤',
80
+ width: 250,
81
+ filter: 'text',
82
+ floatingFilter: true,
83
+ headerComponentParams: { filterIcon: '🔤' },
84
+ valueFormatter: roleValueFormatter,
85
+ },
86
+ { field: 'salary', headerName: 'Salary', width: 120 },
87
+ {
88
+ field: 'location',
89
+ headerName: 'Location',
90
+ width: 150,
91
+ valueFormatter: locationValueFormatter,
92
+ },
93
+ ],
94
+ rowData: generateStaticData(50),
95
+ height: 'calc(100vh - 60px)',
96
+ width: '100%',
97
+ theme: themeQuartz,
98
+ },
99
+ parameters: {
100
+ docs: {
101
+ description: {
102
+ story:
103
+ 'Text filters on Name, Department, and Role columns. **Filter inputs are visible in the header row** (floating filters). Type to filter results.',
104
+ },
105
+ },
106
+ },
107
+ };
108
+
109
+ export const NumberFilter: Story = {
110
+ args: {
111
+ columnDefs: [
112
+ {
113
+ field: 'id',
114
+ headerName: 'ID',
115
+ width: 80,
116
+ filter: 'number',
117
+ floatingFilter: true,
118
+ headerComponentParams: { filterIcon: '🔢' },
119
+ },
120
+ { field: 'name', headerName: 'Name', width: 200 },
121
+ {
122
+ field: 'department',
123
+ headerName: 'Department',
124
+ width: 180,
125
+ valueFormatter: departmentValueFormatter,
126
+ },
127
+ {
128
+ field: 'salary',
129
+ headerName: 'Salary 🔢',
130
+ width: 120,
131
+ filter: 'number',
132
+ floatingFilter: true,
133
+ headerComponentParams: { filterIcon: '🔢' },
134
+ },
135
+ {
136
+ field: 'location',
137
+ headerName: 'Location',
138
+ width: 150,
139
+ valueFormatter: locationValueFormatter,
140
+ },
141
+ ],
142
+ rowData: generateStaticData(50),
143
+ height: 'calc(100vh - 60px)',
144
+ width: '100%',
145
+ theme: themeQuartz,
146
+ },
147
+ parameters: {
148
+ docs: {
149
+ description: {
150
+ story:
151
+ 'Number filters on ID and Salary columns. **Filter inputs visible in header**. Supports equals, greater than, less than, etc. Try typing "> 100000" in Salary filter.',
152
+ },
153
+ },
154
+ },
155
+ };
156
+
157
+ export const SetFilter: Story = {
158
+ args: {
159
+ columnDefs: [
160
+ { field: 'id', headerName: 'ID', width: 80 },
161
+ { field: 'name', headerName: 'Name', width: 200 },
162
+ {
163
+ field: 'department',
164
+ headerName: 'Department ☑️',
165
+ width: 180,
166
+ filter: 'set',
167
+ floatingFilter: true,
168
+ headerComponentParams: { filterIcon: '☑️' },
169
+ valueFormatter: departmentValueFormatter,
170
+ },
171
+ { field: 'role', headerName: 'Role', width: 250, valueFormatter: roleValueFormatter },
172
+ { field: 'salary', headerName: 'Salary', width: 120 },
173
+ {
174
+ field: 'location',
175
+ headerName: 'Location ☑️',
176
+ width: 150,
177
+ filter: 'set',
178
+ floatingFilter: true,
179
+ headerComponentParams: { filterIcon: '☑️' },
180
+ valueFormatter: locationValueFormatter,
181
+ },
182
+ ],
183
+ rowData: generateStaticData(50),
184
+ height: 'calc(100vh - 60px)',
185
+ width: '100%',
186
+ theme: themeQuartz,
187
+ },
188
+ parameters: {
189
+ docs: {
190
+ description: {
191
+ story:
192
+ 'Set filters on Department and Location columns. **Filter inputs visible in header**. Click the filter input to see a dropdown list of unique values with checkboxes for multi-select.',
193
+ },
194
+ },
195
+ },
196
+ };
197
+
198
+ export const HiddenFloatingFilters: Story = {
199
+ args: {
200
+ columnDefs: [
201
+ { field: 'id', headerName: 'ID', width: 80 },
202
+ { field: 'name', headerName: 'Name', width: 200, filter: 'text' },
203
+ {
204
+ field: 'department',
205
+ headerName: 'Department',
206
+ width: 180,
207
+ filter: 'text',
208
+ valueFormatter: departmentValueFormatter,
209
+ },
210
+ {
211
+ field: 'role',
212
+ headerName: 'Role',
213
+ width: 250,
214
+ filter: 'text',
215
+ valueFormatter: roleValueFormatter,
216
+ },
217
+ { field: 'salary', headerName: 'Salary', width: 120, filter: 'number' },
218
+ ],
219
+ rowData: generateStaticData(50),
220
+ height: 'calc(100vh - 60px)',
221
+ width: '100%',
222
+ theme: themeQuartz,
223
+ },
224
+ parameters: {
225
+ docs: {
226
+ description: {
227
+ story:
228
+ 'Filtering enabled but **floating filters are hidden**. Use the column header menu (3 dots) to change filter types and values.',
229
+ },
230
+ },
231
+ },
232
+ };
233
+
234
+ export const AllFilterTypes: Story = {
235
+ args: {
236
+ columnDefs: [
237
+ {
238
+ field: 'id',
239
+ headerName: 'ID',
240
+ width: 80,
241
+ filter: 'number',
242
+ floatingFilter: true,
243
+ headerComponentParams: { filterIcon: '🔢' },
244
+ },
245
+ {
246
+ field: 'name',
247
+ headerName: 'Name 🔤',
248
+ width: 200,
249
+ filter: 'text',
250
+ floatingFilter: true,
251
+ headerComponentParams: { filterIcon: '🔤' },
252
+ },
253
+ {
254
+ field: 'department',
255
+ headerName: 'Department ☑️',
256
+ width: 180,
257
+ filter: 'set',
258
+ floatingFilter: true,
259
+ headerComponentParams: { filterIcon: '☑️' },
260
+ valueFormatter: departmentValueFormatter,
261
+ },
262
+ {
263
+ field: 'startDate',
264
+ headerName: 'Start Date 📅',
265
+ width: 150,
266
+ filter: 'date',
267
+ floatingFilter: true,
268
+ headerComponentParams: { filterIcon: '📅' },
269
+ },
270
+ {
271
+ field: 'salary',
272
+ headerName: 'Salary 🔢',
273
+ width: 120,
274
+ filter: 'number',
275
+ floatingFilter: true,
276
+ headerComponentParams: { filterIcon: '🔢' },
277
+ },
278
+ ],
279
+ rowData: generateStaticData(50),
280
+ height: 'calc(100vh - 60px)',
281
+ width: '100%',
282
+ theme: themeQuartz,
283
+ },
284
+ parameters: {
285
+ docs: {
286
+ description: {
287
+ story:
288
+ '**All filter types in one grid** with floating filters enabled. Each column shows its filter type with an emoji indicator (🔤 Text, 🔢 Number, ☑️ Set, 📅 Date). Filter inputs are visible in the header row for easy access.',
289
+ },
290
+ },
291
+ },
292
+ };