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,219 @@
1
+ import { provideExperimentalZonelessChangeDetection } from '@angular/core';
2
+ import { TestBed } from '@angular/core/testing';
3
+ import { ColDef } from '../types/ag-grid-types';
4
+ import { GridService } from './grid.service';
5
+
6
+ describe('GridService - Set Filter', () => {
7
+ let service: GridService<any>;
8
+
9
+ const testColumnDefs: ColDef[] = [
10
+ { field: 'id', headerName: 'ID', width: 100, filter: 'text' },
11
+ { field: 'name', headerName: 'Name', width: 150, filter: 'text' },
12
+ { field: 'department', headerName: 'Department', width: 150, filter: 'set' },
13
+ { field: 'status', headerName: 'Status', width: 100, filter: 'set' },
14
+ ];
15
+
16
+ const testRowData = [
17
+ { id: 1, name: 'John', department: 'Engineering', status: 'active' },
18
+ { id: 2, name: 'Jane', department: 'Engineering', status: 'active' },
19
+ { id: 3, name: 'Bob', department: 'Sales', status: 'inactive' },
20
+ { id: 4, name: 'Alice', department: 'Sales', status: 'active' },
21
+ { id: 5, name: 'Charlie', department: 'Marketing', status: 'inactive' },
22
+ ];
23
+
24
+ beforeEach(() => {
25
+ TestBed.configureTestingModule({
26
+ providers: [GridService, provideExperimentalZonelessChangeDetection()],
27
+ });
28
+ service = TestBed.inject(GridService);
29
+ });
30
+
31
+ describe('getUniqueValues', () => {
32
+ it('should return unique values for a field', () => {
33
+ service.createApi(testColumnDefs, [...testRowData]);
34
+ const values = service.getUniqueValues('department');
35
+
36
+ expect(values).toEqual(['Engineering', 'Marketing', 'Sales']);
37
+ });
38
+
39
+ it('should return sorted values', () => {
40
+ service.createApi(testColumnDefs, [...testRowData]);
41
+ const values = service.getUniqueValues('status');
42
+
43
+ expect(values).toEqual(['active', 'inactive']);
44
+ });
45
+
46
+ it('should exclude null values', () => {
47
+ const dataWithNulls = [
48
+ { id: 1, department: 'Engineering' },
49
+ { id: 2, department: null },
50
+ { id: 3, department: 'Sales' },
51
+ { id: 4, department: undefined },
52
+ ];
53
+ service.createApi(testColumnDefs, dataWithNulls);
54
+ const values = service.getUniqueValues('department');
55
+
56
+ expect(values).toEqual(['Engineering', 'Sales']);
57
+ });
58
+
59
+ it('should return empty array for non-existent field', () => {
60
+ service.createApi(testColumnDefs, [...testRowData]);
61
+ const values = service.getUniqueValues('nonExistent');
62
+
63
+ expect(values).toEqual([]);
64
+ });
65
+
66
+ it('should handle numeric values', () => {
67
+ const numericData = [
68
+ { id: 1, count: 10 },
69
+ { id: 2, count: 20 },
70
+ { id: 3, count: 10 },
71
+ { id: 4, count: 30 },
72
+ ];
73
+ service.createApi(testColumnDefs, numericData);
74
+ const values = service.getUniqueValues('count');
75
+
76
+ expect(values).toEqual([10, 20, 30]);
77
+ });
78
+ });
79
+
80
+ describe('matchesSetFilter', () => {
81
+ it('should match value in filter array', () => {
82
+ const api = service.createApi(testColumnDefs, [...testRowData]);
83
+
84
+ // Apply set filter
85
+ api.setFilterModel({
86
+ department: { filterType: 'set', values: ['Engineering', 'Sales'] },
87
+ });
88
+
89
+ expect(api.getDisplayedRowCount()).toBe(4); // John, Jane, Bob, Alice
90
+ });
91
+
92
+ it('should not match value not in filter array', () => {
93
+ const api = service.createApi(testColumnDefs, [...testRowData]);
94
+
95
+ // Apply set filter excluding Engineering
96
+ api.setFilterModel({
97
+ department: { filterType: 'set', values: ['Sales', 'Marketing'] },
98
+ });
99
+
100
+ expect(api.getDisplayedRowCount()).toBe(3); // Bob, Alice, Charlie
101
+ });
102
+
103
+ it('should return all rows when filter is empty array', () => {
104
+ const api = service.createApi(testColumnDefs, [...testRowData]);
105
+
106
+ // Empty filter = no filter applied
107
+ api.setFilterModel({
108
+ department: { filterType: 'set', values: [] },
109
+ });
110
+
111
+ expect(api.getDisplayedRowCount()).toBe(5); // All rows
112
+ });
113
+
114
+ it('should work with numeric values', () => {
115
+ const numericData = [
116
+ { id: 1, name: 'A', department: 'Eng', status: 10 },
117
+ { id: 2, name: 'B', department: 'Eng', status: 20 },
118
+ { id: 3, name: 'C', department: 'Eng', status: 30 },
119
+ ];
120
+ const api = service.createApi(testColumnDefs, numericData);
121
+
122
+ api.setFilterModel({
123
+ status: { filterType: 'set', values: [10, 30] },
124
+ });
125
+
126
+ expect(api.getDisplayedRowCount()).toBe(2); // id 1 and 3
127
+ });
128
+
129
+ it('should handle null/undefined values correctly', () => {
130
+ const dataWithNulls = [
131
+ { id: 1, status: 'active' },
132
+ { id: 2, status: null },
133
+ { id: 3, status: 'inactive' },
134
+ { id: 4, status: undefined },
135
+ ];
136
+ const api = service.createApi(testColumnDefs, dataWithNulls);
137
+
138
+ api.setFilterModel({
139
+ status: { filterType: 'set', values: ['active'] },
140
+ });
141
+
142
+ expect(api.getDisplayedRowCount()).toBe(1); // Only active
143
+ });
144
+
145
+ it('should combine with other filters', () => {
146
+ const api = service.createApi(testColumnDefs, [...testRowData]);
147
+
148
+ // Combine set filter with text filter
149
+ api.setFilterModel({
150
+ department: { filterType: 'set', values: ['Engineering', 'Sales'] },
151
+ name: { filterType: 'text', type: 'contains', filter: 'o' },
152
+ });
153
+
154
+ expect(api.getDisplayedRowCount()).toBe(2); // Bob (Sales) and John (Engineering)
155
+ });
156
+
157
+ it('should update when filter changes', () => {
158
+ const api = service.createApi(testColumnDefs, [...testRowData]);
159
+
160
+ // Initial filter
161
+ api.setFilterModel({
162
+ department: { filterType: 'set', values: ['Engineering'] },
163
+ });
164
+
165
+ expect(api.getDisplayedRowCount()).toBe(2); // John, Jane
166
+
167
+ // Change filter
168
+ api.setFilterModel({
169
+ department: { filterType: 'set', values: ['Sales'] },
170
+ });
171
+
172
+ expect(api.getDisplayedRowCount()).toBe(2); // Bob, Alice
173
+ });
174
+ });
175
+
176
+ describe('Set Filter API Integration', () => {
177
+ it('should get filter model with set filter', () => {
178
+ const api = service.createApi(testColumnDefs, [...testRowData]);
179
+
180
+ api.setFilterModel({
181
+ department: { filterType: 'set', values: ['Engineering'] },
182
+ });
183
+
184
+ const model = api.getFilterModel();
185
+ expect(model.department).toEqual({
186
+ filterType: 'set',
187
+ values: ['Engineering'],
188
+ });
189
+ });
190
+
191
+ it('should clear set filter', () => {
192
+ const api = service.createApi(testColumnDefs, [...testRowData]);
193
+
194
+ api.setFilterModel({
195
+ department: { filterType: 'set', values: ['Engineering'] },
196
+ });
197
+
198
+ // Clear filter
199
+ api.setFilterModel({});
200
+
201
+ const model = api.getFilterModel();
202
+ expect(model.department).toBeUndefined();
203
+ });
204
+
205
+ it('should work with getDisplayedRowCount', () => {
206
+ const api = service.createApi(testColumnDefs, [...testRowData]);
207
+
208
+ // No filter
209
+ expect(api.getDisplayedRowCount()).toBe(5);
210
+
211
+ // Apply set filter
212
+ api.setFilterModel({
213
+ department: { filterType: 'set', values: ['Engineering'] },
214
+ });
215
+
216
+ expect(api.getDisplayedRowCount()).toBe(2);
217
+ });
218
+ });
219
+ });