@smartnet360/svelte-components 0.0.102 → 0.0.104

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 (85) hide show
  1. package/dist/apps/antenna-pattern/index.d.ts +1 -0
  2. package/dist/apps/antenna-pattern/index.js +1 -0
  3. package/dist/apps/antenna-pattern/utils/load-static-antennas.d.ts +17 -0
  4. package/dist/apps/antenna-pattern/utils/load-static-antennas.js +83 -0
  5. package/dist/apps/site-check/SiteCheck.svelte +13 -81
  6. package/dist/apps/site-check/SiteCheckControls.svelte +0 -7
  7. package/dist/apps/site-check/helper.js +0 -33
  8. package/dist/apps/site-check/transforms.js +15 -65
  9. package/dist/core/CellTable/CellTable.svelte +456 -0
  10. package/dist/core/CellTable/CellTable.svelte.d.ts +27 -0
  11. package/dist/core/CellTable/CellTablePanel.svelte +211 -0
  12. package/dist/core/CellTable/CellTablePanel.svelte.d.ts +49 -0
  13. package/dist/core/CellTable/CellTableToolbar.svelte +218 -0
  14. package/dist/core/CellTable/CellTableToolbar.svelte.d.ts +32 -0
  15. package/dist/core/CellTable/column-config.d.ts +63 -0
  16. package/dist/core/CellTable/column-config.js +465 -0
  17. package/dist/core/CellTable/index.d.ts +10 -0
  18. package/dist/core/CellTable/index.js +11 -0
  19. package/dist/core/CellTable/types.d.ts +166 -0
  20. package/dist/core/CellTable/types.js +6 -0
  21. package/dist/core/Charts/ChartCard.svelte +118 -31
  22. package/dist/core/Charts/ChartCard.svelte.d.ts +2 -0
  23. package/dist/core/Charts/ChartComponent.svelte +8 -31
  24. package/dist/core/Charts/data-processor.js +1 -19
  25. package/dist/core/CoverageMap/ai/AITools.d.ts +117 -0
  26. package/dist/core/CoverageMap/ai/AITools.js +380 -0
  27. package/dist/core/CoverageMap/core/CoverageCalculator.d.ts +138 -0
  28. package/dist/core/CoverageMap/core/CoverageCalculator.js +375 -0
  29. package/dist/core/CoverageMap/core/GridCalculator.d.ts +115 -0
  30. package/dist/core/CoverageMap/core/GridCalculator.js +484 -0
  31. package/dist/core/CoverageMap/core/PathLossModels.d.ts +253 -0
  32. package/dist/core/CoverageMap/core/PathLossModels.js +380 -0
  33. package/dist/core/CoverageMap/core/SignalProcessor.d.ts +288 -0
  34. package/dist/core/CoverageMap/core/SignalProcessor.js +424 -0
  35. package/dist/core/CoverageMap/data/AntennaStore.d.ts +165 -0
  36. package/dist/core/CoverageMap/data/AntennaStore.js +327 -0
  37. package/dist/core/CoverageMap/data/SiteStore.d.ts +155 -0
  38. package/dist/core/CoverageMap/data/SiteStore.js +355 -0
  39. package/dist/core/CoverageMap/index.d.ts +74 -0
  40. package/dist/core/CoverageMap/index.js +103 -0
  41. package/dist/core/CoverageMap/types.d.ts +252 -0
  42. package/dist/core/CoverageMap/types.js +7 -0
  43. package/dist/core/CoverageMap/utils/geoUtils.d.ts +223 -0
  44. package/dist/core/CoverageMap/utils/geoUtils.js +374 -0
  45. package/dist/core/CoverageMap/utils/rfUtils.d.ts +329 -0
  46. package/dist/core/CoverageMap/utils/rfUtils.js +434 -0
  47. package/dist/core/CoverageMap/visualization/ColorSchemes.d.ts +149 -0
  48. package/dist/core/CoverageMap/visualization/ColorSchemes.js +377 -0
  49. package/dist/core/TreeView/index.d.ts +4 -4
  50. package/dist/core/TreeView/index.js +5 -5
  51. package/dist/core/TreeView/tree-utils.d.ts +12 -0
  52. package/dist/core/TreeView/tree-utils.js +115 -6
  53. package/dist/core/TreeView/tree.store.svelte.d.ts +94 -0
  54. package/dist/core/TreeView/tree.store.svelte.js +274 -0
  55. package/dist/core/index.d.ts +1 -0
  56. package/dist/core/index.js +2 -0
  57. package/dist/map-v2/features/cells/controls/CellFilterControl.svelte +16 -27
  58. package/dist/map-v2/features/repeaters/controls/RepeaterFilterControl.svelte +33 -42
  59. package/dist/map-v2/features/sites/controls/SiteFilterControl.svelte +12 -19
  60. package/dist/map-v3/core/components/Map.svelte +4 -0
  61. package/dist/map-v3/core/stores/map.store.svelte.js +2 -0
  62. package/dist/map-v3/features/cells/components/CellFilterControl.svelte +24 -30
  63. package/dist/map-v3/features/coverage/index.d.ts +12 -0
  64. package/dist/map-v3/features/coverage/index.js +16 -0
  65. package/dist/map-v3/features/coverage/layers/CoverageLayer.svelte +198 -0
  66. package/dist/map-v3/features/coverage/layers/CoverageLayer.svelte.d.ts +10 -0
  67. package/dist/map-v3/features/coverage/logic/coloring.d.ts +28 -0
  68. package/dist/map-v3/features/coverage/logic/coloring.js +77 -0
  69. package/dist/map-v3/features/coverage/logic/geometry.d.ts +33 -0
  70. package/dist/map-v3/features/coverage/logic/geometry.js +112 -0
  71. package/dist/map-v3/features/coverage/stores/coverage.data.svelte.d.ts +46 -0
  72. package/dist/map-v3/features/coverage/stores/coverage.data.svelte.js +95 -0
  73. package/dist/map-v3/features/coverage/stores/coverage.display.svelte.d.ts +33 -0
  74. package/dist/map-v3/features/coverage/stores/coverage.display.svelte.js +90 -0
  75. package/dist/map-v3/features/coverage/types.d.ts +52 -0
  76. package/dist/map-v3/features/coverage/types.js +7 -0
  77. package/dist/map-v3/features/repeaters/components/RepeaterFilterControl.svelte +14 -20
  78. package/dist/map-v3/features/sites/components/SiteFilterControl.svelte +23 -33
  79. package/dist/map-v3/index.d.ts +4 -0
  80. package/dist/map-v3/index.js +5 -0
  81. package/package.json +4 -3
  82. package/dist/apps/site-check/transforms-old.d.ts +0 -56
  83. package/dist/apps/site-check/transforms-old.js +0 -273
  84. package/dist/core/TreeView/tree.store.d.ts +0 -10
  85. package/dist/core/TreeView/tree.store.js +0 -320
@@ -0,0 +1,456 @@
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from 'svelte';
3
+ import { TabulatorFull as Tabulator } from 'tabulator-tables';
4
+ // Import Bootstrap 5 theme for proper styling
5
+ import 'tabulator-tables/dist/css/tabulator_bootstrap5.min.css';
6
+ import type { Options, RowComponent } from 'tabulator-tables';
7
+ import type {
8
+ CellTableProps,
9
+ CellData,
10
+ RowSelectionEvent,
11
+ RowClickEvent,
12
+ RowDblClickEvent,
13
+ DataChangeEvent
14
+ } from './types';
15
+ import {
16
+ getColumnsForPreset,
17
+ getGroupHeaderFormatter,
18
+ DEFAULT_TECH_COLORS,
19
+ DEFAULT_STATUS_COLORS
20
+ } from './column-config';
21
+
22
+ interface Props extends CellTableProps {
23
+ /** Row selection change event */
24
+ onselectionchange?: (event: RowSelectionEvent) => void;
25
+ /** Row click event */
26
+ onrowclick?: (event: RowClickEvent) => void;
27
+ /** Row double-click event */
28
+ onrowdblclick?: (event: RowDblClickEvent) => void;
29
+ /** Data change event (filter, sort, etc.) */
30
+ ondatachange?: (event: DataChangeEvent) => void;
31
+ }
32
+
33
+ let {
34
+ cells = [],
35
+ groupBy = 'none',
36
+ columnPreset = 'default',
37
+ columnVisibility,
38
+ selectable = false,
39
+ multiSelect = true,
40
+ height = '100%',
41
+ virtualDom = true,
42
+ tabulatorOptions,
43
+ techColors = DEFAULT_TECH_COLORS,
44
+ statusColors = DEFAULT_STATUS_COLORS,
45
+ headerFilters = true,
46
+ resizableColumns = true,
47
+ movableColumns = true,
48
+ persistLayout = false,
49
+ storageKey = 'cell-table-layout',
50
+ onselectionchange,
51
+ onrowclick,
52
+ onrowdblclick,
53
+ ondatachange
54
+ }: Props = $props();
55
+
56
+ let tableContainer: HTMLDivElement;
57
+ let table: Tabulator | null = null;
58
+ let isInitialized = $state(false);
59
+
60
+ // Reactive column configuration
61
+ let columns = $derived(getColumnsForPreset(columnPreset, techColors, statusColors, headerFilters));
62
+
63
+ // Build Tabulator options
64
+ function buildOptions(): Options {
65
+ const baseOptions: Options = {
66
+ data: cells,
67
+ columns: columns,
68
+ layout: 'fitDataFill',
69
+ height: height,
70
+ placeholder: 'No cells to display',
71
+
72
+ // Virtual DOM for performance with large datasets
73
+ renderVertical: virtualDom ? 'virtual' : 'basic',
74
+
75
+ // Interactivity
76
+ resizableColumns: resizableColumns,
77
+ movableColumns: movableColumns,
78
+
79
+ // Sorting
80
+ initialSort: [{ column: 'siteId', dir: 'asc' }],
81
+
82
+ // Row selection
83
+ selectable: selectable ? (multiSelect ? true : 1) : false,
84
+ selectableRangeMode: 'click',
85
+
86
+ // Persistence
87
+ persistence: persistLayout ? {
88
+ sort: true,
89
+ filter: true,
90
+ columns: ['width', 'visible'],
91
+ } : false,
92
+ persistenceID: persistLayout ? storageKey : undefined,
93
+
94
+ // Grouping
95
+ ...(groupBy !== 'none' ? {
96
+ groupBy: groupBy,
97
+ groupStartOpen: true,
98
+ groupHeader: getGroupHeaderFormatter(groupBy),
99
+ groupToggleElement: 'header',
100
+ } : {}),
101
+
102
+ // Pagination (optional, disabled by default for virtual scrolling)
103
+ // pagination: true,
104
+ // paginationSize: 50,
105
+
106
+ // Clipboard
107
+ clipboard: true,
108
+ clipboardCopyRowRange: 'selected',
109
+ };
110
+
111
+ // Merge with custom options
112
+ return { ...baseOptions, ...tabulatorOptions };
113
+ }
114
+
115
+ // Initialize table
116
+ function initTable() {
117
+ if (!tableContainer) return;
118
+
119
+ const options = buildOptions();
120
+ table = new Tabulator(tableContainer, options);
121
+
122
+ // Bind events
123
+ table.on('rowClick', (e, row) => {
124
+ if (onrowclick) {
125
+ onrowclick({
126
+ row: (row as RowComponent).getData() as CellData,
127
+ event: e as MouseEvent
128
+ });
129
+ }
130
+ });
131
+
132
+ table.on('rowDblClick', (e, row) => {
133
+ if (onrowdblclick) {
134
+ onrowdblclick({
135
+ row: (row as RowComponent).getData() as CellData,
136
+ event: e as MouseEvent
137
+ });
138
+ }
139
+ });
140
+
141
+ table.on('rowSelectionChanged', (data, rows) => {
142
+ if (onselectionchange) {
143
+ const cellData = data as CellData[];
144
+ onselectionchange({
145
+ rows: cellData,
146
+ ids: cellData.map(d => d.id)
147
+ });
148
+ }
149
+ });
150
+
151
+ table.on('dataFiltered', (filters, rows) => {
152
+ if (ondatachange) {
153
+ ondatachange({
154
+ type: 'filter',
155
+ rowCount: cells.length,
156
+ filteredCount: (rows as RowComponent[]).length
157
+ });
158
+ }
159
+ });
160
+
161
+ table.on('dataSorted', () => {
162
+ if (ondatachange) {
163
+ ondatachange({
164
+ type: 'sort',
165
+ rowCount: cells.length,
166
+ filteredCount: table?.getDataCount('active') ?? 0
167
+ });
168
+ }
169
+ });
170
+
171
+ // Mark as initialized after table is ready
172
+ table.on('tableBuilt', () => {
173
+ isInitialized = true;
174
+ });
175
+ }
176
+
177
+ // Update table data when cells change
178
+ $effect(() => {
179
+ if (isInitialized && table && cells) {
180
+ table.replaceData(cells);
181
+ if (ondatachange) {
182
+ ondatachange({
183
+ type: 'load',
184
+ rowCount: cells.length,
185
+ filteredCount: cells.length
186
+ });
187
+ }
188
+ }
189
+ });
190
+
191
+ // Update grouping when groupBy changes
192
+ $effect(() => {
193
+ if (isInitialized && table) {
194
+ if (groupBy === 'none') {
195
+ table.setGroupBy(false);
196
+ } else {
197
+ table.setGroupBy(groupBy);
198
+ table.setGroupHeader(getGroupHeaderFormatter(groupBy));
199
+ }
200
+ // Force redraw after grouping change
201
+ table.redraw(true);
202
+ }
203
+ });
204
+
205
+ // Update columns when preset changes
206
+ $effect(() => {
207
+ if (isInitialized && table && columns) {
208
+ table.setColumns(columns);
209
+ table.redraw(true);
210
+ }
211
+ });
212
+
213
+ onMount(() => {
214
+ initTable();
215
+ });
216
+
217
+ onDestroy(() => {
218
+ if (table) {
219
+ table.destroy();
220
+ table = null;
221
+ }
222
+ });
223
+
224
+ // Public API methods
225
+ export function getTable(): Tabulator | null {
226
+ return table;
227
+ }
228
+
229
+ export function getSelectedRows(): CellData[] {
230
+ return table?.getSelectedData() as CellData[] ?? [];
231
+ }
232
+
233
+ export function clearSelection(): void {
234
+ table?.deselectRow();
235
+ }
236
+
237
+ export function selectRow(id: string): void {
238
+ const row = table?.getRow(id);
239
+ if (row) row.select();
240
+ }
241
+
242
+ export function scrollToRow(id: string): void {
243
+ table?.scrollToRow(id, 'top', true);
244
+ }
245
+
246
+ export function downloadCSV(filename: string = 'cells.csv'): void {
247
+ table?.download('csv', filename);
248
+ }
249
+
250
+ export function downloadJSON(filename: string = 'cells.json'): void {
251
+ table?.download('json', filename);
252
+ }
253
+
254
+ export function setFilter(field: string, type: string, value: unknown): void {
255
+ table?.setFilter(field, type as any, value);
256
+ }
257
+
258
+ export function clearFilters(): void {
259
+ table?.clearFilter();
260
+ }
261
+
262
+ export function redraw(): void {
263
+ table?.redraw(true);
264
+ }
265
+ </script>
266
+
267
+ <div class="cell-table-container">
268
+ <div bind:this={tableContainer} class="cell-table"></div>
269
+ </div>
270
+
271
+ <style>
272
+ .cell-table-container {
273
+ width: 100%;
274
+ height: 100%;
275
+ display: flex;
276
+ flex-direction: column;
277
+ }
278
+
279
+ .cell-table {
280
+ flex: 1;
281
+ min-height: 0;
282
+ }
283
+
284
+ /* Bootstrap-aligned Tabulator theme overrides */
285
+ :global(.cell-table-container .tabulator) {
286
+ font-family: var(--bs-body-font-family, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);
287
+ font-size: 0.875rem;
288
+ border: 1px solid var(--bs-border-color, #dee2e6);
289
+ border-radius: var(--bs-border-radius, 0.375rem);
290
+ background-color: var(--bs-body-bg, #fff);
291
+ }
292
+
293
+ /* Header styling */
294
+ :global(.cell-table-container .tabulator-header) {
295
+ background-color: var(--bs-tertiary-bg, #f8f9fa);
296
+ border-bottom: 2px solid var(--bs-border-color, #dee2e6);
297
+ }
298
+
299
+ :global(.cell-table-container .tabulator-col) {
300
+ background-color: var(--bs-tertiary-bg, #f8f9fa);
301
+ border-right: 1px solid var(--bs-border-color, #dee2e6);
302
+ }
303
+
304
+ :global(.cell-table-container .tabulator-col-title) {
305
+ font-weight: 600;
306
+ color: var(--bs-body-color, #212529);
307
+ padding: 0.5rem 0.75rem;
308
+ }
309
+
310
+ :global(.cell-table-container .tabulator-col-sorter) {
311
+ color: var(--bs-secondary-color, #6c757d);
312
+ }
313
+
314
+ /* Header filter inputs */
315
+ :global(.cell-table-container .tabulator-header-filter input) {
316
+ font-size: 0.75rem;
317
+ padding: 0.25rem 0.5rem;
318
+ border: 1px solid var(--bs-border-color, #dee2e6);
319
+ border-radius: var(--bs-border-radius-sm, 0.25rem);
320
+ background-color: var(--bs-body-bg, #fff);
321
+ color: var(--bs-body-color, #212529);
322
+ }
323
+
324
+ :global(.cell-table-container .tabulator-header-filter input:focus) {
325
+ border-color: var(--bs-primary, #0d6efd);
326
+ outline: 0;
327
+ box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
328
+ }
329
+
330
+ /* Row styling */
331
+ :global(.cell-table-container .tabulator-row) {
332
+ border-bottom: 1px solid var(--bs-border-color-translucent, rgba(0, 0, 0, 0.1));
333
+ }
334
+
335
+ :global(.cell-table-container .tabulator-row:hover) {
336
+ background-color: var(--bs-tertiary-bg, #f8f9fa);
337
+ }
338
+
339
+ :global(.cell-table-container .tabulator-row.tabulator-row-even) {
340
+ background-color: var(--bs-body-bg, #fff);
341
+ }
342
+
343
+ :global(.cell-table-container .tabulator-row.tabulator-row-odd) {
344
+ background-color: rgba(var(--bs-tertiary-bg-rgb, 248, 249, 250), 0.5);
345
+ }
346
+
347
+ :global(.cell-table-container .tabulator-row.tabulator-selected) {
348
+ background-color: rgba(var(--bs-primary-rgb, 13, 110, 253), 0.1);
349
+ }
350
+
351
+ :global(.cell-table-container .tabulator-row.tabulator-selected:hover) {
352
+ background-color: rgba(var(--bs-primary-rgb, 13, 110, 253), 0.15);
353
+ }
354
+
355
+ /* Cell styling */
356
+ :global(.cell-table-container .tabulator-cell) {
357
+ padding: 0.5rem 0.75rem;
358
+ border-right: 1px solid var(--bs-border-color-translucent, rgba(0, 0, 0, 0.05));
359
+ color: var(--bs-body-color, #212529);
360
+ }
361
+
362
+ :global(.cell-table-container .tabulator-cell.tabulator-frozen) {
363
+ background-color: var(--bs-tertiary-bg, #f8f9fa);
364
+ border-right: 2px solid var(--bs-border-color, #dee2e6);
365
+ }
366
+
367
+ /* Group header styling */
368
+ :global(.cell-table-container .tabulator-row.tabulator-group) {
369
+ background-color: var(--bs-secondary-bg, #e9ecef);
370
+ border-bottom: 1px solid var(--bs-border-color, #dee2e6);
371
+ font-weight: 500;
372
+ min-height: 36px;
373
+ }
374
+
375
+ :global(.cell-table-container .tabulator-row.tabulator-group:hover) {
376
+ background-color: var(--bs-secondary-bg, #e9ecef);
377
+ cursor: pointer;
378
+ }
379
+
380
+ :global(.cell-table-container .tabulator-row.tabulator-group span) {
381
+ color: var(--bs-body-color, #212529);
382
+ }
383
+
384
+ /* Group toggle arrow */
385
+ :global(.cell-table-container .tabulator-group-toggle) {
386
+ margin-right: 0.5rem;
387
+ }
388
+
389
+ /* Scrollbar styling */
390
+ :global(.cell-table-container .tabulator-tableholder::-webkit-scrollbar) {
391
+ width: 8px;
392
+ height: 8px;
393
+ }
394
+
395
+ :global(.cell-table-container .tabulator-tableholder::-webkit-scrollbar-track) {
396
+ background: var(--bs-tertiary-bg, #f8f9fa);
397
+ }
398
+
399
+ :global(.cell-table-container .tabulator-tableholder::-webkit-scrollbar-thumb) {
400
+ background: var(--bs-secondary-color, #6c757d);
401
+ border-radius: 4px;
402
+ }
403
+
404
+ :global(.cell-table-container .tabulator-tableholder::-webkit-scrollbar-thumb:hover) {
405
+ background: var(--bs-body-color, #212529);
406
+ }
407
+
408
+ /* Placeholder */
409
+ :global(.cell-table-container .tabulator-placeholder) {
410
+ color: var(--bs-secondary-color, #6c757d);
411
+ font-style: italic;
412
+ }
413
+
414
+ /* Resize handle */
415
+ :global(.cell-table-container .tabulator-col-resize-handle) {
416
+ width: 6px;
417
+ right: 0;
418
+ }
419
+
420
+ :global(.cell-table-container .tabulator-col-resize-handle:hover) {
421
+ background-color: var(--bs-primary, #0d6efd);
422
+ }
423
+
424
+ /* Footer/pagination (if enabled) */
425
+ :global(.cell-table-container .tabulator-footer) {
426
+ background-color: var(--bs-tertiary-bg, #f8f9fa);
427
+ border-top: 1px solid var(--bs-border-color, #dee2e6);
428
+ padding: 0.5rem;
429
+ }
430
+
431
+ :global(.cell-table-container .tabulator-page) {
432
+ padding: 0.25rem 0.5rem;
433
+ margin: 0 0.125rem;
434
+ border: 1px solid var(--bs-border-color, #dee2e6);
435
+ border-radius: var(--bs-border-radius-sm, 0.25rem);
436
+ background-color: var(--bs-body-bg, #fff);
437
+ color: var(--bs-body-color, #212529);
438
+ }
439
+
440
+ :global(.cell-table-container .tabulator-page:hover) {
441
+ background-color: var(--bs-tertiary-bg, #f8f9fa);
442
+ }
443
+
444
+ :global(.cell-table-container .tabulator-page.active) {
445
+ background-color: var(--bs-primary, #0d6efd);
446
+ border-color: var(--bs-primary, #0d6efd);
447
+ color: white;
448
+ }
449
+
450
+ /* Badge styling in cells */
451
+ :global(.cell-table-container .badge) {
452
+ font-weight: 500;
453
+ padding: 0.25em 0.5em;
454
+ border-radius: var(--bs-border-radius-sm, 0.25rem);
455
+ }
456
+ </style>
@@ -0,0 +1,27 @@
1
+ import { TabulatorFull as Tabulator } from 'tabulator-tables';
2
+ import 'tabulator-tables/dist/css/tabulator_bootstrap5.min.css';
3
+ import type { CellTableProps, CellData, RowSelectionEvent, RowClickEvent, RowDblClickEvent, DataChangeEvent } from './types';
4
+ interface Props extends CellTableProps {
5
+ /** Row selection change event */
6
+ onselectionchange?: (event: RowSelectionEvent) => void;
7
+ /** Row click event */
8
+ onrowclick?: (event: RowClickEvent) => void;
9
+ /** Row double-click event */
10
+ onrowdblclick?: (event: RowDblClickEvent) => void;
11
+ /** Data change event (filter, sort, etc.) */
12
+ ondatachange?: (event: DataChangeEvent) => void;
13
+ }
14
+ declare const CellTable: import("svelte").Component<Props, {
15
+ getTable: () => Tabulator | null;
16
+ getSelectedRows: () => CellData[];
17
+ clearSelection: () => void;
18
+ selectRow: (id: string) => void;
19
+ scrollToRow: (id: string) => void;
20
+ downloadCSV: (filename?: string) => void;
21
+ downloadJSON: (filename?: string) => void;
22
+ setFilter: (field: string, type: string, value: unknown) => void;
23
+ clearFilters: () => void;
24
+ redraw: () => void;
25
+ }, "">;
26
+ type CellTable = ReturnType<typeof CellTable>;
27
+ export default CellTable;
@@ -0,0 +1,211 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import CellTable from './CellTable.svelte';
4
+ import CellTableToolbar from './CellTableToolbar.svelte';
5
+ import type {
6
+ CellData,
7
+ CellTableGroupField,
8
+ ColumnPreset,
9
+ RowSelectionEvent,
10
+ RowClickEvent,
11
+ RowDblClickEvent,
12
+ DataChangeEvent,
13
+ TechColorMap,
14
+ StatusColorMap
15
+ } from './types';
16
+
17
+ interface Props {
18
+ /** Cell data array to display */
19
+ cells: CellData[];
20
+ /** Initial grouping field */
21
+ groupBy?: CellTableGroupField;
22
+ /** Initial column preset */
23
+ columnPreset?: ColumnPreset;
24
+ /** Enable row selection */
25
+ selectable?: boolean;
26
+ /** Enable multi-row selection */
27
+ multiSelect?: boolean;
28
+ /** Panel height (CSS value) */
29
+ height?: string;
30
+ /** Show toolbar */
31
+ showToolbar?: boolean;
32
+ /** Show export buttons */
33
+ showExport?: boolean;
34
+ /** Technology color mapping */
35
+ techColors?: TechColorMap;
36
+ /** Status color mapping */
37
+ statusColors?: StatusColorMap;
38
+ /** Enable header filters */
39
+ headerFilters?: boolean;
40
+ /** Panel title */
41
+ title?: string;
42
+ /** Row selection change event */
43
+ onselectionchange?: (event: RowSelectionEvent) => void;
44
+ /** Row click event */
45
+ onrowclick?: (event: RowClickEvent) => void;
46
+ /** Row double-click event */
47
+ onrowdblclick?: (event: RowDblClickEvent) => void;
48
+ /** Custom header actions slot */
49
+ headerActions?: Snippet;
50
+ /** Custom footer slot */
51
+ footer?: Snippet<[{ selectedRows: CellData[]; selectedCount: number }]>;
52
+ }
53
+
54
+ let {
55
+ cells = [],
56
+ groupBy = $bindable('none'),
57
+ columnPreset = $bindable('default'),
58
+ selectable = true,
59
+ multiSelect = true,
60
+ height = '100%',
61
+ showToolbar = true,
62
+ showExport = true,
63
+ techColors,
64
+ statusColors,
65
+ headerFilters = true,
66
+ title = 'Cell Data',
67
+ onselectionchange,
68
+ onrowclick,
69
+ onrowdblclick,
70
+ headerActions,
71
+ footer
72
+ }: Props = $props();
73
+
74
+ let cellTable: CellTable;
75
+ let selectedCount = $state(0);
76
+ let selectedRows = $state<CellData[]>([]);
77
+ let filteredCount = $state(cells.length);
78
+
79
+ function handleSelectionChange(event: RowSelectionEvent) {
80
+ selectedCount = event.rows.length;
81
+ selectedRows = event.rows;
82
+ onselectionchange?.(event);
83
+ }
84
+
85
+ function handleDataChange(event: DataChangeEvent) {
86
+ filteredCount = event.filteredCount;
87
+ }
88
+
89
+ function handleGroupChange(group: CellTableGroupField) {
90
+ groupBy = group;
91
+ }
92
+
93
+ function handlePresetChange(preset: ColumnPreset) {
94
+ columnPreset = preset;
95
+ }
96
+
97
+ function handleExportCSV() {
98
+ cellTable?.downloadCSV(`cells-${new Date().toISOString().slice(0, 10)}.csv`);
99
+ }
100
+
101
+ function handleExportJSON() {
102
+ cellTable?.downloadJSON(`cells-${new Date().toISOString().slice(0, 10)}.json`);
103
+ }
104
+
105
+ function handleClearFilters() {
106
+ cellTable?.clearFilters();
107
+ }
108
+
109
+ // Expose table methods
110
+ export function getSelectedRows(): CellData[] {
111
+ return cellTable?.getSelectedRows() ?? [];
112
+ }
113
+
114
+ export function clearSelection(): void {
115
+ cellTable?.clearSelection();
116
+ }
117
+
118
+ export function scrollToRow(id: string): void {
119
+ cellTable?.scrollToRow(id);
120
+ }
121
+
122
+ export function redraw(): void {
123
+ cellTable?.redraw();
124
+ }
125
+ </script>
126
+
127
+ <div class="cell-table-panel d-flex flex-column" style:height>
128
+ <!-- Header -->
129
+ <div class="panel-header d-flex align-items-center justify-content-between px-3 py-2 bg-body-secondary border-bottom">
130
+ <h6 class="mb-0 d-flex align-items-center gap-2">
131
+ <i class="bi bi-table text-primary"></i>
132
+ {title}
133
+ </h6>
134
+ {#if headerActions}
135
+ <div class="header-actions">
136
+ {@render headerActions()}
137
+ </div>
138
+ {/if}
139
+ </div>
140
+
141
+ <!-- Toolbar -->
142
+ {#if showToolbar}
143
+ <CellTableToolbar
144
+ {groupBy}
145
+ {columnPreset}
146
+ totalCount={cells.length}
147
+ {filteredCount}
148
+ {selectedCount}
149
+ {showExport}
150
+ ongroupchange={handleGroupChange}
151
+ onpresetchange={handlePresetChange}
152
+ onexportcsv={handleExportCSV}
153
+ onexportjson={handleExportJSON}
154
+ onclearfilters={handleClearFilters}
155
+ />
156
+ {/if}
157
+
158
+ <!-- Table -->
159
+ <div class="table-wrapper flex-grow-1">
160
+ <CellTable
161
+ bind:this={cellTable}
162
+ {cells}
163
+ {groupBy}
164
+ {columnPreset}
165
+ {selectable}
166
+ {multiSelect}
167
+ height="100%"
168
+ {techColors}
169
+ {statusColors}
170
+ {headerFilters}
171
+ onselectionchange={handleSelectionChange}
172
+ ondatachange={handleDataChange}
173
+ {onrowclick}
174
+ {onrowdblclick}
175
+ />
176
+ </div>
177
+
178
+ <!-- Footer -->
179
+ {#if footer}
180
+ <div class="panel-footer border-top p-2 bg-body-tertiary">
181
+ {@render footer({ selectedRows, selectedCount })}
182
+ </div>
183
+ {/if}
184
+ </div>
185
+
186
+ <style>
187
+ .cell-table-panel {
188
+ background-color: var(--bs-body-bg, #fff);
189
+ border: 1px solid var(--bs-border-color, #dee2e6);
190
+ border-radius: var(--bs-border-radius, 0.375rem);
191
+ overflow: hidden;
192
+ }
193
+
194
+ .panel-header {
195
+ min-height: 48px;
196
+ }
197
+
198
+ .panel-header h6 {
199
+ font-weight: 600;
200
+ color: var(--bs-body-color, #212529);
201
+ }
202
+
203
+ .table-wrapper {
204
+ min-height: 0;
205
+ overflow: hidden;
206
+ }
207
+
208
+ .panel-footer {
209
+ min-height: 48px;
210
+ }
211
+ </style>