argent-grid 0.2.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 (55) hide show
  1. package/AGENTS.md +70 -27
  2. package/e2e/advanced.spec.ts +1 -1
  3. package/e2e/benchmark.spec.ts +7 -7
  4. package/e2e/cell-renderers.spec.ts +152 -0
  5. package/e2e/debug-streaming.spec.ts +31 -0
  6. package/e2e/dnd.spec.ts +73 -0
  7. package/e2e/screenshots.spec.ts +1 -1
  8. package/e2e/visual.spec.ts +30 -9
  9. package/e2e/visual.spec.ts-snapshots/checkbox-renderer-mixed.png +0 -0
  10. package/e2e/visual.spec.ts-snapshots/debug.png +0 -0
  11. package/e2e/visual.spec.ts-snapshots/grid-column-group-headers.png +0 -0
  12. package/e2e/visual.spec.ts-snapshots/grid-default.png +0 -0
  13. package/e2e/visual.spec.ts-snapshots/grid-empty-state.png +0 -0
  14. package/e2e/visual.spec.ts-snapshots/grid-filter-popup.png +0 -0
  15. package/e2e/visual.spec.ts-snapshots/grid-scroll-borders.png +0 -0
  16. package/e2e/visual.spec.ts-snapshots/grid-sidebar-buttons.png +0 -0
  17. package/e2e/visual.spec.ts-snapshots/grid-text-filter.png +0 -0
  18. package/e2e/visual.spec.ts-snapshots/grid-with-selection.png +0 -0
  19. package/e2e/visual.spec.ts-snapshots/rating-renderer-varied.png +0 -0
  20. package/package.json +5 -5
  21. package/plan.md +30 -34
  22. package/src/lib/components/argent-grid.component.css +258 -549
  23. package/src/lib/components/argent-grid.component.html +272 -306
  24. package/src/lib/components/argent-grid.component.ts +585 -135
  25. package/src/lib/components/argent-grid.regressions.spec.ts +301 -0
  26. package/src/lib/components/argent-grid.selection.spec.ts +2 -2
  27. package/src/lib/components/set-filter/set-filter.component.spec.ts +191 -0
  28. package/src/lib/components/set-filter/set-filter.component.ts +7 -2
  29. package/src/lib/rendering/canvas-renderer.spec.ts +148 -1
  30. package/src/lib/rendering/canvas-renderer.ts +177 -286
  31. package/src/lib/rendering/render/cells.ts +122 -5
  32. package/src/lib/rendering/render/column-utils.ts +27 -5
  33. package/src/lib/rendering/render/hit-test.ts +6 -11
  34. package/src/lib/rendering/render/index.ts +15 -6
  35. package/src/lib/rendering/render/lines.ts +12 -6
  36. package/src/lib/rendering/render/primitives.ts +269 -7
  37. package/src/lib/rendering/render/types.ts +2 -1
  38. package/src/lib/rendering/render/walk.ts +39 -19
  39. package/src/lib/services/grid.service.spec.ts +76 -0
  40. package/src/lib/services/grid.service.ts +451 -114
  41. package/src/lib/themes/theme-quartz.ts +2 -2
  42. package/src/lib/types/ag-grid-types.ts +500 -0
  43. package/src/stories/Advanced.stories.ts +78 -17
  44. package/src/stories/ArgentGrid.stories.ts +50 -26
  45. package/src/stories/Benchmark.stories.ts +17 -15
  46. package/src/stories/CellRenderers.stories.ts +205 -31
  47. package/src/stories/Filtering.stories.ts +56 -16
  48. package/src/stories/Grouping.stories.ts +86 -13
  49. package/src/stories/Streaming.stories.ts +57 -0
  50. package/src/stories/Theming.stories.ts +23 -10
  51. package/src/stories/Tooltips.stories.ts +381 -0
  52. package/src/stories/benchmark-wrapper.component.ts +69 -29
  53. package/src/stories/story-utils.ts +88 -0
  54. package/src/stories/streaming-wrapper.component.ts +441 -0
  55. package/tsconfig.json +1 -0
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Shared utilities for Storybook stories
3
+ */
4
+
5
+ export const LOCATION_FLAGS: Record<string, string> = {
6
+ 'New York': 'πŸ‡ΊπŸ‡Έ New York',
7
+ 'San Francisco': 'πŸ‡ΊπŸ‡Έ San Francisco',
8
+ London: 'πŸ‡¬πŸ‡§ London',
9
+ Singapore: 'πŸ‡ΈπŸ‡¬ Singapore',
10
+ Remote: '🌐 Remote',
11
+ Berlin: 'πŸ‡©πŸ‡ͺ Berlin',
12
+ Tokyo: 'πŸ‡―πŸ‡΅ Tokyo',
13
+ };
14
+
15
+ export const DEPARTMENT_EMOJIS: Record<string, string> = {
16
+ Engineering: 'βš™οΈ Engineering',
17
+ Sales: 'πŸ’° Sales',
18
+ Marketing: 'πŸ“£ Marketing',
19
+ HR: 'πŸ‘₯ HR',
20
+ Finance: 'πŸ“ˆ Finance',
21
+ Design: '🎨 Design',
22
+ Operations: '🏒 Operations',
23
+ Support: '🎧 Support',
24
+ };
25
+
26
+ export const ROLE_EMOJIS: Record<string, string> = {
27
+ Engineer: 'πŸ’» Engineer',
28
+ 'Software Engineer': 'πŸ’» Software Engineer',
29
+ Manager: 'πŸ‘” Manager',
30
+ Director: '🏒 Director',
31
+ VP: 'πŸ’Ž VP',
32
+ Intern: 'πŸŽ“ Intern',
33
+ Analyst: 'πŸ“Š Analyst',
34
+ Lead: 'πŸ₯‡ Lead',
35
+ };
36
+
37
+ /**
38
+ * Common value formatter for location columns to add flags
39
+ */
40
+ export const locationValueFormatter = (params: any) => {
41
+ return LOCATION_FLAGS[params.value] ?? params.value;
42
+ };
43
+
44
+ /**
45
+ * Common value formatter for department columns to add emojis
46
+ */
47
+ export const departmentValueFormatter = (params: any) => {
48
+ return DEPARTMENT_EMOJIS[params.value] ?? params.value;
49
+ };
50
+
51
+ /**
52
+ * Common value formatter for role columns to add emojis
53
+ */
54
+ export const roleValueFormatter = (params: any) => {
55
+ return ROLE_EMOJIS[params.value] ?? params.value;
56
+ };
57
+
58
+ /**
59
+ * Standard locations for mock data generation
60
+ */
61
+ export const STORY_LOCATIONS = [
62
+ 'New York',
63
+ 'San Francisco',
64
+ 'London',
65
+ 'Singapore',
66
+ 'Remote',
67
+ 'Berlin',
68
+ 'Tokyo',
69
+ ];
70
+
71
+ /**
72
+ * Standard departments for mock data generation
73
+ */
74
+ export const STORY_DEPARTMENTS = [
75
+ 'Engineering',
76
+ 'Sales',
77
+ 'Marketing',
78
+ 'HR',
79
+ 'Finance',
80
+ 'Design',
81
+ 'Operations',
82
+ 'Support',
83
+ ];
84
+
85
+ /**
86
+ * Standard roles for mock data generation
87
+ */
88
+ export const STORY_ROLES = ['Engineer', 'Manager', 'Director', 'VP', 'Intern', 'Analyst', 'Lead'];
@@ -0,0 +1,441 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
3
+ import { ArgentGridComponent, ArgentGridModule, ColDef, GridApi, themeQuartz } from '../public-api';
4
+
5
+ interface Stock {
6
+ id: string;
7
+ symbol: string;
8
+ name: string;
9
+ price: number;
10
+ change: number;
11
+ changePct: number;
12
+ history: number[];
13
+ volume: number;
14
+ marketCap: number;
15
+ }
16
+
17
+ @Component({
18
+ selector: 'app-streaming-wrapper',
19
+ standalone: true,
20
+ imports: [CommonModule, ArgentGridModule],
21
+ template: `
22
+ <div class="streaming-container">
23
+ <div class="header">
24
+ <div class="title">
25
+ <h2>Live Stock Market Feed</h2>
26
+ <div class="status-badge" [class.active]="isRunning">
27
+ <span class="dot"></span>
28
+ {{ isRunning ? 'Streaming Live' : 'Paused' }}
29
+ </div>
30
+ </div>
31
+ <div class="controls">
32
+ <button (click)="checkData()">Check Data</button>
33
+ <button (click)="toggleStreaming()" [class.pause]="isRunning">
34
+ {{ isRunning ? 'Pause Stream' : 'Start Stream' }}
35
+ </button>
36
+ <div class="stats">
37
+ <span class="stat-label">Message Rate:</span>
38
+ <span class="stat-value">{{ messageRate | number:'1.1-1' }} msgs/sec</span>
39
+ </div>
40
+ </div>
41
+ </div>
42
+
43
+ <argent-grid
44
+ #grid
45
+ [columnDefs]="columnDefs"
46
+ [rowData]="rowData"
47
+ [height]="height"
48
+ [width]="width"
49
+ [theme]="theme"
50
+ [gridOptions]="gridOptions"
51
+ (gridReady)="onGridReady($event)"
52
+ />
53
+ </div>
54
+ `,
55
+ styles: [
56
+ `
57
+ .streaming-container {
58
+ display: flex;
59
+ flex-direction: column;
60
+ gap: 16px;
61
+ padding: 20px;
62
+ background: #f8fafc;
63
+ height: 600px;
64
+ box-sizing: border-box;
65
+ }
66
+ .header {
67
+ display: flex;
68
+ justify-content: space-between;
69
+ align-items: center;
70
+ background: white;
71
+ padding: 16px 24px;
72
+ border-radius: 8px;
73
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
74
+ }
75
+ .title h2 {
76
+ margin: 0;
77
+ font-size: 1.25rem;
78
+ color: #1e293b;
79
+ }
80
+ .status-badge {
81
+ display: inline-flex;
82
+ align-items: center;
83
+ gap: 6px;
84
+ font-size: 12px;
85
+ font-weight: 500;
86
+ color: #64748b;
87
+ margin-top: 4px;
88
+ }
89
+ .status-badge.active {
90
+ color: #10b981;
91
+ }
92
+ .dot {
93
+ width: 8px;
94
+ height: 8px;
95
+ background: #cbd5e1;
96
+ border-radius: 50%;
97
+ }
98
+ .active .dot {
99
+ background: #10b981;
100
+ box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.2);
101
+ animation: pulse 2s infinite;
102
+ }
103
+ @keyframes pulse {
104
+ 0% { transform: scale(0.95); opacity: 0.5; }
105
+ 50% { transform: scale(1.05); opacity: 1; }
106
+ 100% { transform: scale(0.95); opacity: 0.5; }
107
+ }
108
+ .controls {
109
+ display: flex;
110
+ gap: 20px;
111
+ align-items: center;
112
+ }
113
+ button {
114
+ padding: 8px 20px;
115
+ background: #3b82f6;
116
+ color: white;
117
+ border: none;
118
+ border-radius: 6px;
119
+ font-weight: 600;
120
+ cursor: pointer;
121
+ transition: all 0.2s;
122
+ }
123
+ button:hover {
124
+ background: #2563eb;
125
+ }
126
+ button.pause {
127
+ background: #ef4444;
128
+ }
129
+ button.pause:hover {
130
+ background: #dc2626;
131
+ }
132
+ .stats {
133
+ font-size: 14px;
134
+ }
135
+ .stat-label {
136
+ color: #64748b;
137
+ margin-right: 4px;
138
+ }
139
+ .stat-value {
140
+ color: #1e293b;
141
+ font-weight: 700;
142
+ font-family: monospace;
143
+ }
144
+ `,
145
+ ],
146
+ })
147
+ export class StreamingWrapperComponent implements OnInit, OnDestroy {
148
+ @ViewChild('grid') gridComponent!: ArgentGridComponent;
149
+
150
+ @Input() updateFrequency = 100; // ms
151
+ @Input() batchSize = 10;
152
+
153
+ columnDefs: ColDef<Stock>[] = [
154
+ { field: 'symbol', headerName: 'Symbol', width: 100, pinned: 'left', sortable: true },
155
+ { field: 'name', headerName: 'Name', width: 200, sortable: true },
156
+ {
157
+ field: 'price',
158
+ headerName: 'Price',
159
+ width: 120,
160
+ sortable: true,
161
+ cellRenderer: (params: any) => {
162
+ const arrow = params.data.change >= 0 ? 'β–²' : 'β–Ό';
163
+ return `${arrow} $${params.value.toFixed(2)}`;
164
+ },
165
+ cellStyle: (params: any) => ({
166
+ color: params.data.change >= 0 ? '#16a34a' : '#dc2626',
167
+ }),
168
+ tooltipValueGetter: (params: any) => {
169
+ const d = params.data;
170
+ const sign = d.change >= 0 ? '+' : '';
171
+ return `${d.name}\nPrice: $${d.price.toFixed(2)}\nChange: ${sign}$${d.change.toFixed(2)} (${sign}${d.changePct.toFixed(2)}%)\nVolume: ${d.volume.toLocaleString()}`;
172
+ },
173
+ },
174
+ {
175
+ field: 'change',
176
+ headerName: 'Change',
177
+ width: 100,
178
+ cellRenderer: (params: any) => {
179
+ const val = params.value;
180
+ const arrow = val >= 0 ? 'β–²' : 'β–Ό';
181
+ const sign = val >= 0 ? '+' : '';
182
+ return `${arrow} ${sign}${val.toFixed(2)}`;
183
+ },
184
+ cellStyle: (params: any) => ({
185
+ color: params.value >= 0 ? '#16a34a' : '#dc2626',
186
+ }),
187
+ },
188
+ {
189
+ field: 'changePct',
190
+ headerName: '% Change',
191
+ width: 110,
192
+ cellRenderer: (params: any) => {
193
+ const val = params.value;
194
+ const arrow = val >= 0 ? 'β–²' : 'β–Ό';
195
+ const sign = val >= 0 ? '+' : '';
196
+ return `${arrow} ${sign}${val.toFixed(2)}%`;
197
+ },
198
+ cellStyle: (params: any) => ({
199
+ color: params.value >= 0 ? '#16a34a' : '#dc2626',
200
+ }),
201
+ },
202
+ {
203
+ field: 'history',
204
+ headerName: 'Trend',
205
+ width: 140,
206
+ sortable: false,
207
+ sparklineOptions: {
208
+ type: 'bar',
209
+ column: {
210
+ fill: '#3b82f6',
211
+ stroke: '#2563eb',
212
+ strokeWidth: 0,
213
+ padding: 0.15,
214
+ },
215
+ padding: { top: 4, bottom: 4, left: 4, right: 4 },
216
+ },
217
+ },
218
+ {
219
+ field: 'volume',
220
+ headerName: 'Volume',
221
+ width: 140,
222
+ sortable: true,
223
+ valueFormatter: (params: any) => params.value.toLocaleString(),
224
+ },
225
+ {
226
+ field: 'marketCap',
227
+ headerName: 'Mkt Cap',
228
+ width: 140,
229
+ sortable: true,
230
+ cellRenderer: (params: any) => {
231
+ const val = params.value;
232
+ if (val >= 1e12) return `$${(val / 1e12).toFixed(2)}T`;
233
+ if (val >= 1e9) return `$${(val / 1e9).toFixed(1)}B`;
234
+ return `$${(val / 1e6).toFixed(1)}M`;
235
+ },
236
+ },
237
+ ];
238
+
239
+ rowData: Stock[] = [];
240
+ height = '100%';
241
+ width = '100%';
242
+ theme = themeQuartz;
243
+
244
+ gridOptions = {
245
+ getRowId: (params: any) => params.data.symbol,
246
+ defaultColDef: {
247
+ resizable: true,
248
+ },
249
+ };
250
+
251
+ private gridApi?: GridApi<Stock>;
252
+ private intervalId: any;
253
+ private rateIntervalId: any;
254
+ private flushIntervalId: any;
255
+ isRunning = false;
256
+ updateCount = 0;
257
+ messageRate = 0;
258
+ private lastUpdateCount = 0;
259
+
260
+ // Transaction throttling - buffer updates and apply in batches
261
+ private pendingUpdates: Stock[] = [];
262
+ private flushIntervalMs = 200; // Apply transactions at most every 500ms
263
+
264
+ ngOnInit(): void {
265
+ this.rowData = this.generateInitialData();
266
+ }
267
+
268
+ onGridReady(api: GridApi<Stock>): void {
269
+ this.gridApi = api;
270
+ console.log('Grid Ready, rowData count:', this.rowData.length);
271
+ this.startStreaming();
272
+ }
273
+
274
+ toggleStreaming(): void {
275
+ if (this.isRunning) {
276
+ this.stopStreaming();
277
+ } else {
278
+ this.startStreaming();
279
+ }
280
+ }
281
+
282
+ private startStreaming(): void {
283
+ this.isRunning = true;
284
+ this.intervalId = setInterval(() => {
285
+ this.updateStocks();
286
+ }, this.updateFrequency);
287
+
288
+ // Flush pending updates every 500ms
289
+ this.flushIntervalId = setInterval(() => {
290
+ this.flushPendingUpdates();
291
+ }, this.flushIntervalMs);
292
+
293
+ // Calculate message rate every second
294
+ this.rateIntervalId = setInterval(() => {
295
+ this.messageRate = this.updateCount - this.lastUpdateCount;
296
+ this.lastUpdateCount = this.updateCount;
297
+ }, 1000);
298
+ }
299
+
300
+ private stopStreaming(): void {
301
+ this.isRunning = false;
302
+ if (this.intervalId) {
303
+ clearInterval(this.intervalId);
304
+ }
305
+ if (this.rateIntervalId) {
306
+ clearInterval(this.rateIntervalId);
307
+ }
308
+ if (this.flushIntervalId) {
309
+ clearInterval(this.flushIntervalId);
310
+ }
311
+ // Flush any remaining updates before stopping
312
+ this.flushPendingUpdates();
313
+ }
314
+
315
+ forceRender(): void {
316
+ if (this.gridComponent) {
317
+ console.log('Forcing grid render...');
318
+ this.gridComponent.refresh();
319
+ }
320
+ }
321
+
322
+ checkData(): void {
323
+ if (this.gridApi) {
324
+ console.log('Current Row Data:', this.gridApi.getRowData());
325
+ console.log('Displayed Count:', this.gridApi.getDisplayedRowCount());
326
+ }
327
+ }
328
+
329
+ private generateInitialData(): Stock[] {
330
+ const symbols = [
331
+ { s: 'AAPL', n: 'Apple Inc.', p: 185.92, m: 2.89e12 },
332
+ { s: 'MSFT', n: 'Microsoft Corp.', p: 406.32, m: 3.02e12 },
333
+ { s: 'GOOGL', n: 'Alphabet Inc.', p: 142.65, m: 1.79e12 },
334
+ { s: 'AMZN', n: 'Amazon.com Inc.', p: 174.45, m: 1.81e12 },
335
+ { s: 'NVDA', n: 'NVIDIA Corp.', p: 788.17, m: 1.94e12 },
336
+ { s: 'META', n: 'Meta Platforms Inc.', p: 484.03, m: 1.24e12 },
337
+ { s: 'TSLA', n: 'Tesla Inc.', p: 191.97, m: 611.3e9 },
338
+ { s: 'BRK.B', n: 'Berkshire Hathaway', p: 408.84, m: 882.4e9 },
339
+ { s: 'V', n: 'Visa Inc.', p: 282.43, m: 581.2e9 },
340
+ { s: 'JPM', n: 'JPMorgan Chase & Co.', p: 184.21, m: 531.5e9 },
341
+ { s: 'UNH', n: 'UnitedHealth Group', p: 525.44, m: 485.1e9 },
342
+ { s: 'LLY', n: 'Eli Lilly & Co.', p: 769.72, m: 730.8e9 },
343
+ { s: 'XOM', n: 'Exxon Mobil Corp.', p: 105.21, m: 417.3e9 },
344
+ { s: 'MA', n: 'Mastercard Inc.', p: 471.22, m: 439.1e9 },
345
+ { s: 'AVGO', n: 'Broadcom Inc.', p: 1304.11, m: 605.4e9 },
346
+ { s: 'HD', n: 'Home Depot Inc.', p: 372.44, m: 369.2e9 },
347
+ { s: 'PG', n: 'Procter & Gamble', p: 160.21, m: 377.1e9 },
348
+ { s: 'COST', n: 'Costco Wholesale', p: 742.11, m: 329.4e9 },
349
+ { s: 'CVX', n: 'Chevron Corp.', p: 154.32, m: 289.1e9 },
350
+ { s: 'ABBV', n: 'AbbVie Inc.', p: 178.44, m: 315.2e9 },
351
+ ];
352
+
353
+ // Expand to 100 stocks for more activity
354
+ const allStocks: Stock[] = [];
355
+ for (let i = 0; i < 5; i++) {
356
+ symbols.forEach((sym) => {
357
+ const symbol = i === 0 ? sym.s : `${sym.s}_${i}`;
358
+ const name = i === 0 ? sym.n : `${sym.n} Class ${i}`;
359
+ const price = sym.p * (0.8 + Math.random() * 0.4);
360
+ const history = Array.from({ length: 20 }, () => price * (0.95 + Math.random() * 0.1));
361
+
362
+ allStocks.push({
363
+ id: symbol,
364
+ symbol,
365
+ name,
366
+ price,
367
+ change: 0,
368
+ changePct: 0,
369
+ history,
370
+ volume: Math.floor(Math.random() * 10000000) + 1000000,
371
+ marketCap: sym.m * (0.8 + Math.random() * 0.4),
372
+ });
373
+ });
374
+ }
375
+
376
+ return allStocks;
377
+ }
378
+
379
+ private updateStocks(): void {
380
+ if (!this.gridApi || !this.rowData.length) return;
381
+
382
+ const updates: Stock[] = [];
383
+ const indicesToUpdate = new Set<number>();
384
+
385
+ // Pick unique random stocks to update
386
+ while (indicesToUpdate.size < Math.min(this.batchSize, this.rowData.length)) {
387
+ indicesToUpdate.add(Math.floor(Math.random() * this.rowData.length));
388
+ }
389
+
390
+ // Create a NEW array for rowData to ensure OnPush detects change
391
+ const newRowData = [...this.rowData];
392
+
393
+ indicesToUpdate.forEach((idx) => {
394
+ const stock = newRowData[idx];
395
+
396
+ // Realistic price movement (Random Walk with slight mean reversion)
397
+ const volatility = 0.002; // 0.2% per update
398
+ const drift = 0.00001; // slight upward drift
399
+ const change = stock.price * (volatility * (Math.random() - 0.5) + drift);
400
+
401
+ const newPrice = Math.max(0.01, stock.price + change);
402
+ const dayChange = newPrice - (stock.price - stock.change);
403
+ const dayChangePct = (dayChange / (newPrice - dayChange)) * 100;
404
+
405
+ // Update history
406
+ const newHistory = [...stock.history.slice(1), newPrice];
407
+
408
+ const updatedStock = {
409
+ ...stock,
410
+ price: newPrice,
411
+ change: dayChange,
412
+ changePct: dayChangePct,
413
+ history: newHistory,
414
+ volume: stock.volume + Math.floor(Math.random() * 1000),
415
+ };
416
+
417
+ newRowData[idx] = updatedStock;
418
+ updates.push(updatedStock);
419
+ });
420
+
421
+ this.rowData = newRowData;
422
+
423
+ // Buffer updates for throttled applyTransaction
424
+ this.pendingUpdates.push(...updates);
425
+ this.updateCount += updates.length;
426
+ }
427
+
428
+ private flushPendingUpdates(): void {
429
+ if (!this.gridApi || this.pendingUpdates.length === 0) return;
430
+
431
+ // Apply all buffered updates in a single transaction
432
+ const updatesToApply = [...this.pendingUpdates];
433
+ this.pendingUpdates = [];
434
+
435
+ this.gridApi.applyTransaction({ update: updatesToApply });
436
+ }
437
+
438
+ ngOnDestroy(): void {
439
+ this.stopStreaming();
440
+ }
441
+ }
package/tsconfig.json CHANGED
@@ -23,6 +23,7 @@
23
23
  "forceConsistentCasingInFileNames": true,
24
24
  "resolveJsonModule": true,
25
25
  "paths": {
26
+ "exceljs": ["node_modules/exceljs/index.d.ts"],
26
27
  "argent-grid": ["dist"],
27
28
  "argent-grid/*": ["dist/*"]
28
29
  }