@smartnet360/svelte-components 0.0.134 → 0.0.136

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 (43) hide show
  1. package/dist/core/CellHistory/CellHistoryPanel.svelte +178 -0
  2. package/dist/core/CellHistory/CellHistoryPanel.svelte.d.ts +4 -0
  3. package/dist/core/CellHistory/column-config.d.ts +26 -0
  4. package/dist/core/CellHistory/column-config.js +120 -0
  5. package/dist/core/CellHistory/index.d.ts +9 -0
  6. package/dist/core/CellHistory/index.js +10 -0
  7. package/dist/core/CellHistory/transformers.d.ts +16 -0
  8. package/dist/core/CellHistory/transformers.js +76 -0
  9. package/dist/core/CellHistory/types.d.ts +54 -0
  10. package/dist/core/CellHistory/types.js +6 -0
  11. package/dist/core/{CellTable → CellTableV2}/CellTable.svelte +7 -3
  12. package/dist/core/{CellTable → CellTableV2}/CellTable.svelte.d.ts +3 -0
  13. package/dist/core/{CellTable → CellTableV2}/CellTablePanel.svelte +87 -235
  14. package/dist/core/{CellTable → CellTableV2}/CellTablePanel.svelte.d.ts +16 -2
  15. package/dist/core/{CellTable → CellTableV2}/CellTableToolbar.svelte +0 -1
  16. package/dist/core/{CellTable → CellTableV2}/column-config.d.ts +11 -30
  17. package/dist/core/{CellTable → CellTableV2}/column-config.js +21 -220
  18. package/dist/core/CellTableV2/composables/index.d.ts +12 -0
  19. package/dist/core/CellTableV2/composables/index.js +9 -0
  20. package/dist/core/CellTableV2/composables/useColumnVisibility.svelte.d.ts +45 -0
  21. package/dist/core/CellTableV2/composables/useColumnVisibility.svelte.js +98 -0
  22. package/dist/core/CellTableV2/composables/usePersistence.svelte.d.ts +28 -0
  23. package/dist/core/CellTableV2/composables/usePersistence.svelte.js +101 -0
  24. package/dist/core/CellTableV2/composables/useScrollSpy.svelte.d.ts +44 -0
  25. package/dist/core/CellTableV2/composables/useScrollSpy.svelte.js +91 -0
  26. package/dist/core/CellTableV2/index.d.ts +12 -0
  27. package/dist/core/CellTableV2/index.js +14 -0
  28. package/dist/core/{CellTable → CellTableV2}/types.d.ts +3 -3
  29. package/dist/core/index.d.ts +2 -1
  30. package/dist/core/index.js +3 -1
  31. package/package.json +1 -1
  32. package/dist/core/CellTable/CellHistoryDemo.svelte +0 -240
  33. package/dist/core/CellTable/CellHistoryDemo.svelte.d.ts +0 -3
  34. package/dist/core/CellTable/CellTableDemo.svelte +0 -336
  35. package/dist/core/CellTable/CellTableDemo.svelte.d.ts +0 -3
  36. package/dist/core/CellTable/history-api-helper.d.ts +0 -79
  37. package/dist/core/CellTable/history-api-helper.js +0 -83
  38. package/dist/core/CellTable/index.d.ts +0 -15
  39. package/dist/core/CellTable/index.js +0 -20
  40. /package/dist/core/{CellTable → CellTableV2}/CellTableToolbar.svelte.d.ts +0 -0
  41. /package/dist/core/{CellTable → CellTableV2}/ColumnPicker.svelte +0 -0
  42. /package/dist/core/{CellTable → CellTableV2}/ColumnPicker.svelte.d.ts +0 -0
  43. /package/dist/core/{CellTable → CellTableV2}/types.js +0 -0
@@ -60,8 +60,6 @@ export const COLUMN_GROUPS = {
60
60
  atoll: ['atollET', 'atollMT', 'atollPW', 'atollRS', 'atollBW'],
61
61
  position: ['latitude', 'longitude', 'siteLatitude', 'siteLongitude', 'dx', 'dy'],
62
62
  compare: ['compareET', 'comparePW', 'compareRS', 'compareBW'],
63
- kpi: ['kpiTraffic', 'kpiThroughput', 'kpiAvailability', 'kpiSuccessRate'],
64
- history: ['configDate', 'frequency', 'antennaChange', 'etiltChange', 'mtiltChange', 'powerChange'],
65
63
  };
66
64
  /**
67
65
  * Create a technology badge formatter
@@ -168,98 +166,6 @@ export function createCompareFormatter(atollField, nwtField) {
168
166
  return `<span class="badge" style="background-color: ${bgColor}; color: ${textColor}; font-size: 0.75rem; font-weight: normal;">${atollStr} | ${nwtStr}</span>`;
169
167
  };
170
168
  }
171
- /**
172
- * Create a history change formatter for showing current vs previous values
173
- * Highlights changes in yellow/amber, unchanged values in muted style
174
- *
175
- * @param currentField - Field name for current value
176
- * @param prevField - Field name for previous value
177
- */
178
- export function createHistoryChangeFormatter(currentField, prevField) {
179
- return (cell) => {
180
- const row = cell.getRow().getData();
181
- const currentVal = row[currentField];
182
- const prevVal = row[prevField];
183
- const currentStr = currentVal !== null && currentVal !== undefined ? String(currentVal) : '-';
184
- const prevStr = prevVal !== null && prevVal !== undefined ? String(prevVal) : '-';
185
- const hasChanged = currentVal !== prevVal;
186
- if (hasChanged) {
187
- // Value changed - highlight with amber/warning color
188
- return `<span class="badge bg-warning text-dark" style="font-size: 0.75rem; font-weight: 500;" title="Changed from: ${prevStr}">${currentStr}</span>`;
189
- }
190
- else {
191
- // No change - muted style
192
- return `<span class="text-muted">${currentStr}</span>`;
193
- }
194
- };
195
- }
196
- /**
197
- * Format ISO date string to YYYY.MM.DD format for history display
198
- */
199
- export function historyDateFormatter(cell) {
200
- const value = cell.getValue();
201
- if (!value)
202
- return '-';
203
- try {
204
- const date = new Date(value);
205
- const year = date.getFullYear();
206
- const month = String(date.getMonth() + 1).padStart(2, '0');
207
- const day = String(date.getDate()).padStart(2, '0');
208
- return `${year}-${month}-${day}`;
209
- }
210
- catch {
211
- return value;
212
- }
213
- }
214
- export function createSparklineFormatter(options = {}) {
215
- const { width = 80, height = 24, lineColor = '#0d6efd', fillColor = 'rgba(13,110,253,0.2)', showDots = false, showLastValue = true, unit = '', decimals = 1 } = options;
216
- return (cell) => {
217
- const data = cell.getValue();
218
- if (!data || !Array.isArray(data) || data.length === 0) {
219
- return '<span class="text-muted">—</span>';
220
- }
221
- const values = data.filter(v => typeof v === 'number' && !isNaN(v));
222
- if (values.length === 0) {
223
- return '<span class="text-muted">—</span>';
224
- }
225
- const min = Math.min(...values);
226
- const max = Math.max(...values);
227
- const range = max - min || 1;
228
- const padding = 2;
229
- const chartWidth = showLastValue ? width - 35 : width - 4;
230
- const chartHeight = height - 4;
231
- // Generate SVG path
232
- const points = values.map((v, i) => {
233
- const x = padding + (i / (values.length - 1 || 1)) * (chartWidth - padding * 2);
234
- const y = padding + (1 - (v - min) / range) * (chartHeight - padding * 2);
235
- return { x, y, v };
236
- });
237
- // Line path
238
- const linePath = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x.toFixed(1)} ${p.y.toFixed(1)}`).join(' ');
239
- // Fill path (closed polygon)
240
- const fillPath = `${linePath} L ${points[points.length - 1].x.toFixed(1)} ${chartHeight - padding} L ${padding} ${chartHeight - padding} Z`;
241
- // Dots
242
- const dots = showDots
243
- ? points.map(p => `<circle cx="${p.x.toFixed(1)}" cy="${p.y.toFixed(1)}" r="1.5" fill="${lineColor}"/>`).join('')
244
- : '';
245
- // Last value text
246
- const lastValue = values[values.length - 1];
247
- const valueText = showLastValue
248
- ? `<text x="${width - 2}" y="${height / 2 + 4}" text-anchor="end" font-size="10" fill="#333">${lastValue.toFixed(decimals)}${unit}</text>`
249
- : '';
250
- // Trend indicator (comparing last vs first)
251
- const trend = values.length > 1 ? values[values.length - 1] - values[0] : 0;
252
- const trendColor = trend >= 0 ? '#198754' : '#dc3545';
253
- return `
254
- <svg width="${width}" height="${height}" style="vertical-align: middle;">
255
- <path d="${fillPath}" fill="${fillColor}" />
256
- <path d="${linePath}" fill="none" stroke="${lineColor}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
257
- ${dots}
258
- ${valueText}
259
- </svg>
260
- `.trim().replace(/\s+/g, ' ');
261
- };
262
- }
263
169
  /**
264
170
  * Custom sorter for fband - extracts numeric portion and sorts numerically
265
171
  * Examples: LTE700 → 700, GSM900 → 900, LTE1800 → 1800, 5G-3500 → 3500
@@ -365,49 +271,6 @@ export function getAllColumns(techColors = DEFAULT_TECH_COLORS, statusColors = D
365
271
  width: 120,
366
272
  ...headerFilterParams,
367
273
  },
368
- {
369
- title: 'Config Date',
370
- field: 'configDate',
371
- width: 120,
372
- formatter: historyDateFormatter,
373
- ...headerFilterParams,
374
- },
375
- {
376
- title: 'Freq (MHz)',
377
- field: 'frequency',
378
- width: 100,
379
- hozAlign: 'right',
380
- ...headerFilterParams,
381
- },
382
- // History change columns (current vs previous, highlights changes)
383
- {
384
- title: 'Antenna',
385
- field: 'antennaChange',
386
- width: 160,
387
- formatter: createHistoryChangeFormatter('antenna', 'prevAntenna'),
388
- ...headerFilterParams,
389
- },
390
- {
391
- title: 'E-Tilt',
392
- field: 'etiltChange',
393
- width: 80,
394
- hozAlign: 'center',
395
- formatter: createHistoryChangeFormatter('electricalTilt', 'prevElectricalTilt'),
396
- },
397
- {
398
- title: 'M-Tilt',
399
- field: 'mtiltChange',
400
- width: 80,
401
- hozAlign: 'center',
402
- formatter: createHistoryChangeFormatter('mechanicalTilt', 'prevMechanicalTilt'),
403
- },
404
- {
405
- title: 'Power',
406
- field: 'powerChange',
407
- width: 80,
408
- hozAlign: 'center',
409
- formatter: createHistoryChangeFormatter('power', 'prevPower'),
410
- },
411
274
  // Physical columns
412
275
  {
413
276
  title: 'Antenna',
@@ -589,63 +452,6 @@ export function getAllColumns(techColors = DEFAULT_TECH_COLORS, statusColors = D
589
452
  formatter: createCompareFormatter('atollBW', 'nwBW'),
590
453
  headerTooltip: 'Atoll BW | Network BW',
591
454
  },
592
- // KPI Sparkline columns
593
- {
594
- title: 'Traffic',
595
- field: 'kpiTraffic',
596
- width: 120,
597
- hozAlign: 'center',
598
- formatter: createSparklineFormatter({
599
- unit: '',
600
- lineColor: '#0d6efd',
601
- fillColor: 'rgba(13,110,253,0.15)',
602
- decimals: 0
603
- }),
604
- headerTooltip: 'Traffic volume trend (GB)',
605
- headerSort: false,
606
- },
607
- {
608
- title: 'Throughput',
609
- field: 'kpiThroughput',
610
- width: 120,
611
- hozAlign: 'center',
612
- formatter: createSparklineFormatter({
613
- unit: '',
614
- lineColor: '#6f42c1',
615
- fillColor: 'rgba(111,66,193,0.15)',
616
- decimals: 1
617
- }),
618
- headerTooltip: 'Throughput trend (Mbps)',
619
- headerSort: false,
620
- },
621
- {
622
- title: 'Avail %',
623
- field: 'kpiAvailability',
624
- width: 120,
625
- hozAlign: 'center',
626
- formatter: createSparklineFormatter({
627
- unit: '%',
628
- lineColor: '#198754',
629
- fillColor: 'rgba(25,135,84,0.15)',
630
- decimals: 1
631
- }),
632
- headerTooltip: 'Availability trend (%)',
633
- headerSort: false,
634
- },
635
- {
636
- title: 'Success %',
637
- field: 'kpiSuccessRate',
638
- width: 120,
639
- hozAlign: 'center',
640
- formatter: createSparklineFormatter({
641
- unit: '%',
642
- lineColor: '#fd7e14',
643
- fillColor: 'rgba(253,126,20,0.15)',
644
- decimals: 1
645
- }),
646
- headerTooltip: 'Success rate trend (%)',
647
- headerSort: false,
648
- },
649
455
  // Position columns
650
456
  {
651
457
  title: 'Latitude',
@@ -740,13 +546,6 @@ export function getColumnsForPreset(preset, techColors = DEFAULT_TECH_COLORS, st
740
546
  case 'compare':
741
547
  visibleFields = [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.compare];
742
548
  break;
743
- case 'kpi':
744
- visibleFields = [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.kpi];
745
- break;
746
- case 'history':
747
- // Simplified view for config history - just cellName, date, and config fields
748
- visibleFields = ['cellName', ...COLUMN_GROUPS.history];
749
- break;
750
549
  case 'default':
751
550
  default:
752
551
  visibleFields = [
@@ -778,16 +577,16 @@ export function getGroupHeaderFormatter(groupField) {
778
577
  }
779
578
  /**
780
579
  * Get column metadata for the column picker UI
580
+ * @param options Filter options for including/excluding column groups
781
581
  */
782
- export function getColumnMetadata() {
783
- return [
582
+ export function getColumnMetadata(options) {
583
+ const allColumns = [
784
584
  // Core
785
585
  { field: 'siteId', title: 'Site ID', group: 'Core' },
786
586
  { field: 'txId', title: 'TX ID', group: 'Core' },
787
587
  { field: 'cellName', title: 'Cell Name', group: 'Core' },
788
588
  { field: 'tech', title: 'Technology', group: 'Core' },
789
589
  { field: 'fband', title: 'Band', group: 'Core' },
790
- { field: 'rru', title: 'RRU', group: 'Core' },
791
590
  { field: 'frq', title: 'Frequency', group: 'Core' },
792
591
  { field: 'status', title: 'Status', group: 'Core' },
793
592
  { field: 'onAirDate', title: 'On Air Date', group: 'Core' },
@@ -816,19 +615,10 @@ export function getColumnMetadata() {
816
615
  { field: 'dlEarfn', title: 'DL EARFCN', group: 'Network' },
817
616
  { field: 'bcch', title: 'BCCH', group: 'Network' },
818
617
  { field: 'pci', title: 'PCI', group: 'Network' },
618
+ { field: 'rru', title: 'RRU', group: 'Network' },
619
+ { field: 'cellID', title: 'Cell ID', group: 'Network' },
620
+ { field: 'cellId2G', title: 'Cell ID 2G', group: 'Network' },
819
621
  { field: 'ctrlid', title: 'Ctrl ID', group: 'Network' },
820
- // History
821
- { field: 'configDate', title: 'Config Date', group: 'History' },
822
- { field: 'frequency', title: 'Freq (MHz)', group: 'History' },
823
- { field: 'antennaChange', title: 'Antenna (Δ)', group: 'History' },
824
- { field: 'etiltChange', title: 'E-Tilt (Δ)', group: 'History' },
825
- { field: 'mtiltChange', title: 'M-Tilt (Δ)', group: 'History' },
826
- { field: 'powerChange', title: 'Power (Δ)', group: 'History' },
827
- // KPI Trends
828
- { field: 'kpiTraffic', title: 'Traffic', group: 'KPI' },
829
- { field: 'kpiThroughput', title: 'Throughput', group: 'KPI' },
830
- { field: 'kpiAvailability', title: 'Availability', group: 'KPI' },
831
- { field: 'kpiSuccessRate', title: 'Success Rate', group: 'KPI' },
832
622
  // Position
833
623
  // { field: 'latitude', title: 'Latitude', group: 'Position' },
834
624
  // { field: 'longitude', title: 'Longitude', group: 'Position' },
@@ -841,6 +631,21 @@ export function getColumnMetadata() {
841
631
  { field: 'comment', title: 'Comment', group: 'Planning' },
842
632
  // { field: 'customSubgroup', title: 'Subgroup', group: 'Planning' },
843
633
  ];
634
+ // Apply filtering if options provided
635
+ const { include, exclude } = options ?? {};
636
+ return allColumns.filter(col => {
637
+ // If include is specified, only include those groups
638
+ if (include && include.length > 0) {
639
+ if (!include.includes(col.group)) {
640
+ return false;
641
+ }
642
+ }
643
+ // Apply exclude filter
644
+ if (exclude && exclude.includes(col.group)) {
645
+ return false;
646
+ }
647
+ return true;
648
+ });
844
649
  }
845
650
  /**
846
651
  * Get default visible columns for a preset
@@ -859,10 +664,6 @@ export function getPresetVisibleFields(preset) {
859
664
  return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.planning];
860
665
  case 'compare':
861
666
  return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.compare];
862
- case 'kpi':
863
- return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.kpi];
864
- case 'history':
865
- return ['cellName', ...COLUMN_GROUPS.history];
866
667
  case 'default':
867
668
  default:
868
669
  return ['siteId', 'txId', 'cellName', 'tech', 'fband', 'frq', 'status', 'azimuth', 'height', 'antenna'];
@@ -0,0 +1,12 @@
1
+ /**
2
+ * CellTableV2 Composables
3
+ *
4
+ * Reusable logic hooks for cell table functionality.
5
+ * These composables use Svelte 5 runes and can be shared across different panel types.
6
+ */
7
+ export { usePersistence } from './usePersistence.svelte';
8
+ export type { UsePersistenceOptions, UsePersistenceReturn } from './usePersistence.svelte';
9
+ export { useColumnVisibility } from './useColumnVisibility.svelte';
10
+ export type { UseColumnVisibilityOptions, UseColumnVisibilityReturn } from './useColumnVisibility.svelte';
11
+ export { useScrollSpy } from './useScrollSpy.svelte';
12
+ export type { UseScrollSpyOptions, UseScrollSpyReturn, ScrollSpyGroup, CellTableRef } from './useScrollSpy.svelte';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * CellTableV2 Composables
3
+ *
4
+ * Reusable logic hooks for cell table functionality.
5
+ * These composables use Svelte 5 runes and can be shared across different panel types.
6
+ */
7
+ export { usePersistence } from './usePersistence.svelte';
8
+ export { useColumnVisibility } from './useColumnVisibility.svelte';
9
+ export { useScrollSpy } from './useScrollSpy.svelte';
@@ -0,0 +1,45 @@
1
+ /**
2
+ * useColumnVisibility - Column visibility management composable
3
+ *
4
+ * Manages column preset selection and per-preset column visibility customization.
5
+ * Uses Svelte 5 runes for reactive state.
6
+ */
7
+ import type { ColumnPreset } from '../types';
8
+ import type { ColumnMeta } from '../column-config';
9
+ export interface UseColumnVisibilityOptions {
10
+ /** Base storage key for persistence */
11
+ storageKey: string;
12
+ /** Column metadata for the column picker */
13
+ columnMeta: ColumnMeta[];
14
+ /** Initial column preset */
15
+ initialPreset?: ColumnPreset;
16
+ /** Whether to persist settings to localStorage */
17
+ persistSettings?: boolean;
18
+ }
19
+ export interface UseColumnVisibilityReturn {
20
+ /** Current column preset (reactive) */
21
+ readonly columnPreset: ColumnPreset;
22
+ /** Currently visible column fields (reactive) */
23
+ readonly visibleColumns: string[];
24
+ /** Column metadata */
25
+ readonly columnMeta: ColumnMeta[];
26
+ /** Load saved columns for a preset (or default if none saved) */
27
+ loadColumnsForPreset: (preset: ColumnPreset) => string[];
28
+ /** Set the column preset and load its columns */
29
+ setPreset: (preset: ColumnPreset) => void;
30
+ /** Toggle a single column's visibility */
31
+ toggleColumn: (field: string, visible: boolean) => void;
32
+ /** Reset current preset to its default columns */
33
+ resetToDefaults: () => void;
34
+ /** Apply column visibility to a CellTable instance */
35
+ applyToTable: (table: {
36
+ showColumn: (f: string) => void;
37
+ hideColumn: (f: string) => void;
38
+ } | undefined) => void;
39
+ /** Save current visibility state */
40
+ saveVisibility: () => void;
41
+ }
42
+ /**
43
+ * Create column visibility management for a cell table
44
+ */
45
+ export declare function useColumnVisibility(options: UseColumnVisibilityOptions): UseColumnVisibilityReturn;
@@ -0,0 +1,98 @@
1
+ /**
2
+ * useColumnVisibility - Column visibility management composable
3
+ *
4
+ * Manages column preset selection and per-preset column visibility customization.
5
+ * Uses Svelte 5 runes for reactive state.
6
+ */
7
+ import { getPresetVisibleFields } from '../column-config';
8
+ import { usePersistence } from './usePersistence.svelte';
9
+ /**
10
+ * Create column visibility management for a cell table
11
+ */
12
+ export function useColumnVisibility(options) {
13
+ const { storageKey, columnMeta, initialPreset = 'default', persistSettings = true } = options;
14
+ // Persistence utilities
15
+ const persistence = usePersistence({ storageKey, enabled: persistSettings });
16
+ // Storage key for per-preset column visibility
17
+ function getColumnsKey(preset) {
18
+ return `visibleColumns-${preset}`;
19
+ }
20
+ /**
21
+ * Load saved columns for a preset (or default if none saved)
22
+ */
23
+ function loadColumnsForPreset(preset) {
24
+ const saved = persistence.load(getColumnsKey(preset), null);
25
+ if (saved && Array.isArray(saved)) {
26
+ return saved;
27
+ }
28
+ return getPresetVisibleFields(preset);
29
+ }
30
+ // Load initial preset from storage
31
+ const savedPreset = persistence.loadString('columnPreset', initialPreset);
32
+ // Reactive state
33
+ let _columnPreset = $state(savedPreset);
34
+ let _visibleColumns = $state(loadColumnsForPreset(savedPreset));
35
+ /**
36
+ * Save current column visibility for current preset
37
+ */
38
+ function saveVisibility() {
39
+ persistence.save(getColumnsKey(_columnPreset), _visibleColumns);
40
+ }
41
+ /**
42
+ * Set the column preset and load its saved columns
43
+ */
44
+ function setPreset(preset) {
45
+ _columnPreset = preset;
46
+ _visibleColumns = loadColumnsForPreset(preset);
47
+ persistence.saveString('columnPreset', preset);
48
+ }
49
+ /**
50
+ * Toggle a single column's visibility
51
+ */
52
+ function toggleColumn(field, visible) {
53
+ if (visible) {
54
+ if (!_visibleColumns.includes(field)) {
55
+ _visibleColumns = [..._visibleColumns, field];
56
+ }
57
+ }
58
+ else {
59
+ _visibleColumns = _visibleColumns.filter(f => f !== field);
60
+ }
61
+ saveVisibility();
62
+ }
63
+ /**
64
+ * Reset current preset to its default columns
65
+ */
66
+ function resetToDefaults() {
67
+ _visibleColumns = getPresetVisibleFields(_columnPreset);
68
+ // Remove saved customization
69
+ persistence.remove(getColumnsKey(_columnPreset));
70
+ }
71
+ /**
72
+ * Apply column visibility to a CellTable instance
73
+ */
74
+ function applyToTable(table) {
75
+ if (!table)
76
+ return;
77
+ columnMeta.forEach(col => {
78
+ if (_visibleColumns.includes(col.field)) {
79
+ table.showColumn(col.field);
80
+ }
81
+ else {
82
+ table.hideColumn(col.field);
83
+ }
84
+ });
85
+ }
86
+ // Return with getters for reactivity
87
+ return {
88
+ get columnPreset() { return _columnPreset; },
89
+ get visibleColumns() { return _visibleColumns; },
90
+ columnMeta,
91
+ loadColumnsForPreset,
92
+ setPreset,
93
+ toggleColumn,
94
+ resetToDefaults,
95
+ applyToTable,
96
+ saveVisibility
97
+ };
98
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * usePersistence - localStorage persistence utility
3
+ *
4
+ * Provides namespaced read/write/remove functions for persisting UI state.
5
+ * Does not use reactive state - just utility functions.
6
+ */
7
+ export interface UsePersistenceOptions {
8
+ /** Base storage key prefix for namespacing */
9
+ storageKey: string;
10
+ /** Whether persistence is enabled */
11
+ enabled?: boolean;
12
+ }
13
+ export interface UsePersistenceReturn {
14
+ /** Load a value from localStorage */
15
+ load: <T>(key: string, defaultValue: T) => T;
16
+ /** Save a value to localStorage */
17
+ save: <T>(key: string, value: T) => void;
18
+ /** Remove a value from localStorage */
19
+ remove: (key: string) => void;
20
+ /** Load a string value (no JSON parsing) */
21
+ loadString: (key: string, defaultValue: string) => string;
22
+ /** Save a string value (no JSON stringifying) */
23
+ saveString: (key: string, value: string) => void;
24
+ }
25
+ /**
26
+ * Create persistence utilities for a given storage namespace
27
+ */
28
+ export declare function usePersistence(options: UsePersistenceOptions): UsePersistenceReturn;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * usePersistence - localStorage persistence utility
3
+ *
4
+ * Provides namespaced read/write/remove functions for persisting UI state.
5
+ * Does not use reactive state - just utility functions.
6
+ */
7
+ /**
8
+ * Create persistence utilities for a given storage namespace
9
+ */
10
+ export function usePersistence(options) {
11
+ const { storageKey, enabled = true } = options;
12
+ /**
13
+ * Get full storage key with namespace
14
+ */
15
+ function getKey(key) {
16
+ return `${storageKey}-${key}`;
17
+ }
18
+ /**
19
+ * Load a JSON value from localStorage
20
+ */
21
+ function load(key, defaultValue) {
22
+ if (!enabled || typeof localStorage === 'undefined') {
23
+ return defaultValue;
24
+ }
25
+ try {
26
+ const saved = localStorage.getItem(getKey(key));
27
+ if (saved !== null) {
28
+ return JSON.parse(saved);
29
+ }
30
+ }
31
+ catch (e) {
32
+ console.warn(`Failed to load ${key}:`, e);
33
+ }
34
+ return defaultValue;
35
+ }
36
+ /**
37
+ * Save a JSON value to localStorage
38
+ */
39
+ function save(key, value) {
40
+ if (!enabled || typeof localStorage === 'undefined') {
41
+ return;
42
+ }
43
+ try {
44
+ localStorage.setItem(getKey(key), JSON.stringify(value));
45
+ }
46
+ catch (e) {
47
+ console.warn(`Failed to save ${key}:`, e);
48
+ }
49
+ }
50
+ /**
51
+ * Remove a value from localStorage
52
+ */
53
+ function remove(key) {
54
+ if (!enabled || typeof localStorage === 'undefined') {
55
+ return;
56
+ }
57
+ try {
58
+ localStorage.removeItem(getKey(key));
59
+ }
60
+ catch (e) {
61
+ console.warn(`Failed to remove ${key}:`, e);
62
+ }
63
+ }
64
+ /**
65
+ * Load a string value (no JSON parsing)
66
+ */
67
+ function loadString(key, defaultValue) {
68
+ if (!enabled || typeof localStorage === 'undefined') {
69
+ return defaultValue;
70
+ }
71
+ try {
72
+ const saved = localStorage.getItem(getKey(key));
73
+ return saved ?? defaultValue;
74
+ }
75
+ catch (e) {
76
+ console.warn(`Failed to load string ${key}:`, e);
77
+ return defaultValue;
78
+ }
79
+ }
80
+ /**
81
+ * Save a string value (no JSON stringifying)
82
+ */
83
+ function saveString(key, value) {
84
+ if (!enabled || typeof localStorage === 'undefined') {
85
+ return;
86
+ }
87
+ try {
88
+ localStorage.setItem(getKey(key), value);
89
+ }
90
+ catch (e) {
91
+ console.warn(`Failed to save string ${key}:`, e);
92
+ }
93
+ }
94
+ return {
95
+ load,
96
+ save,
97
+ remove,
98
+ loadString,
99
+ saveString
100
+ };
101
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * useScrollSpy - ScrollSpy navigation composable
3
+ *
4
+ * Manages group-based scroll navigation for grouped tables.
5
+ * Uses Svelte 5 runes for reactive state.
6
+ */
7
+ export interface ScrollSpyGroup {
8
+ key: string;
9
+ count: number;
10
+ }
11
+ export interface CellTableRef {
12
+ getGroups: () => ScrollSpyGroup[];
13
+ scrollToGroup: (key: string) => void;
14
+ }
15
+ export interface UseScrollSpyOptions {
16
+ /** Base storage key for persistence */
17
+ storageKey: string;
18
+ /** Initial enabled state */
19
+ initialEnabled?: boolean;
20
+ /** Whether to persist settings */
21
+ persistSettings?: boolean;
22
+ }
23
+ export interface UseScrollSpyReturn {
24
+ /** ScrollSpy groups (reactive) */
25
+ readonly groups: ScrollSpyGroup[];
26
+ /** Whether scrollspy is enabled (reactive) */
27
+ readonly enabled: boolean;
28
+ /** Toggle scrollspy on/off */
29
+ toggle: () => void;
30
+ /** Enable scrollspy */
31
+ enable: () => void;
32
+ /** Disable scrollspy */
33
+ disable: () => void;
34
+ /** Update groups from table data */
35
+ updateGroups: (table: CellTableRef | undefined) => void;
36
+ /** Scroll to a specific group */
37
+ scrollToGroup: (table: CellTableRef | undefined, key: string) => void;
38
+ /** Clear groups */
39
+ clearGroups: () => void;
40
+ }
41
+ /**
42
+ * Create scrollspy navigation for a grouped table
43
+ */
44
+ export declare function useScrollSpy(options: UseScrollSpyOptions): UseScrollSpyReturn;