@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,377 @@
1
+ /**
2
+ * Color Schemes
3
+ *
4
+ * This module defines color schemes for coverage visualization.
5
+ * Supports multiple visualization styles:
6
+ * - Heatmap: Gradient from strong to weak signal
7
+ * - Categorical: Discrete quality levels
8
+ * - Single color: Opacity-based (for sector identification)
9
+ *
10
+ * All colors designed to be:
11
+ * - Colorblind-friendly (where possible)
12
+ * - Print-friendly
13
+ * - Intuitive (red = strong, blue = weak for heatmap)
14
+ */
15
+ // ============================================================================
16
+ // PREDEFINED COLOR SCHEMES
17
+ // ============================================================================
18
+ /**
19
+ * Heatmap - Red to Blue gradient
20
+ *
21
+ * Classic heatmap where:
22
+ * - Red = Excellent signal (hot)
23
+ * - Orange/Yellow = Good signal (warm)
24
+ * - Green = Fair signal (cool)
25
+ * - Blue = Poor signal (cold)
26
+ * - Gray = No signal
27
+ *
28
+ * This is intuitive for most users.
29
+ */
30
+ export const HEATMAP_RED_BLUE = {
31
+ name: 'Heatmap (Red → Blue)',
32
+ description: 'Classic heatmap gradient from strong (red) to weak (blue)',
33
+ stops: [
34
+ { value: -60, color: '#FF0000' }, // Excellent (bright red)
35
+ { value: -70, color: '#FF4500' }, // Excellent/Good transition (orange-red)
36
+ { value: -80, color: '#FFA500' }, // Good (orange)
37
+ { value: -90, color: '#FFFF00' }, // Fair (yellow)
38
+ { value: -100, color: '#00FF00' }, // Poor (green)
39
+ { value: -110, color: '#0000FF' } // Edge (blue)
40
+ ],
41
+ noSignalColor: '#CCCCCC' // Gray
42
+ };
43
+ /**
44
+ * Heatmap - Green to Red (inverted)
45
+ *
46
+ * Alternative where:
47
+ * - Green = Excellent (good status)
48
+ * - Yellow = Fair (warning)
49
+ * - Red = Poor (problem)
50
+ *
51
+ * More intuitive for traffic light metaphor.
52
+ */
53
+ export const HEATMAP_GREEN_RED = {
54
+ name: 'Heatmap (Green → Red)',
55
+ description: 'Traffic light style: green (good) to red (bad)',
56
+ stops: [
57
+ { value: -60, color: '#00FF00' }, // Excellent (green)
58
+ { value: -70, color: '#7FFF00' }, // Good (yellow-green)
59
+ { value: -80, color: '#FFFF00' }, // Good/Fair (yellow)
60
+ { value: -90, color: '#FFA500' }, // Fair (orange)
61
+ { value: -100, color: '#FF4500' }, // Poor (orange-red)
62
+ { value: -110, color: '#FF0000' } // Edge (red)
63
+ ],
64
+ noSignalColor: '#CCCCCC'
65
+ };
66
+ /**
67
+ * Categorical - Discrete quality levels
68
+ *
69
+ * Uses distinct colors for each quality level.
70
+ * No gradients - clear boundaries.
71
+ * Good for presentations and reports.
72
+ */
73
+ export const CATEGORICAL = {
74
+ name: 'Categorical',
75
+ description: 'Discrete colors for each quality level',
76
+ stops: [
77
+ { value: -70, color: '#2ECC40' }, // Excellent (green)
78
+ { value: -85, color: '#FFDC00' }, // Good (yellow)
79
+ { value: -95, color: '#FF851B' }, // Fair (orange)
80
+ { value: -105, color: '#FF4136' } // Poor (red)
81
+ ],
82
+ noSignalColor: '#AAAAAA'
83
+ };
84
+ /**
85
+ * Viridis-inspired (colorblind-friendly)
86
+ *
87
+ * Based on matplotlib's viridis colormap.
88
+ * Optimized for colorblind users and grayscale printing.
89
+ */
90
+ export const VIRIDIS = {
91
+ name: 'Viridis (Colorblind-friendly)',
92
+ description: 'Perceptually uniform, colorblind-safe gradient',
93
+ stops: [
94
+ { value: -60, color: '#FDE724' }, // Excellent (yellow)
95
+ { value: -70, color: '#B8DE29' }, // Good (yellow-green)
96
+ { value: -80, color: '#73D055' }, // Good/Fair (green)
97
+ { value: -90, color: '#3CBB75' }, // Fair (teal)
98
+ { value: -100, color: '#20A387' }, // Poor (cyan)
99
+ { value: -110, color: '#287D8E' } // Edge (blue-cyan)
100
+ ],
101
+ noSignalColor: '#CCCCCC'
102
+ };
103
+ /**
104
+ * Plasma-inspired (high contrast)
105
+ *
106
+ * High contrast colormap for visibility.
107
+ */
108
+ export const PLASMA = {
109
+ name: 'Plasma (High Contrast)',
110
+ description: 'High contrast gradient for visibility',
111
+ stops: [
112
+ { value: -60, color: '#F0F921' }, // Excellent (yellow)
113
+ { value: -70, color: '#FCA636' }, // Good (orange)
114
+ { value: -80, color: '#E16462' }, // Good/Fair (salmon)
115
+ { value: -90, color: '#B12A90' }, // Fair (magenta)
116
+ { value: -100, color: '#6A00A8' }, // Poor (purple)
117
+ { value: -110, color: '#0D0887' } // Edge (dark blue)
118
+ ],
119
+ noSignalColor: '#CCCCCC'
120
+ };
121
+ // ============================================================================
122
+ // COLOR SCHEME REGISTRY
123
+ // ============================================================================
124
+ /**
125
+ * All available color schemes
126
+ */
127
+ export const COLOR_SCHEMES = {
128
+ 'heatmap-red-blue': HEATMAP_RED_BLUE,
129
+ 'heatmap-green-red': HEATMAP_GREEN_RED,
130
+ categorical: CATEGORICAL,
131
+ viridis: VIRIDIS,
132
+ plasma: PLASMA
133
+ };
134
+ /**
135
+ * Default color scheme
136
+ */
137
+ export const DEFAULT_COLOR_SCHEME = HEATMAP_RED_BLUE;
138
+ // ============================================================================
139
+ // COLOR INTERPOLATION
140
+ // ============================================================================
141
+ /**
142
+ * Interpolate color for a specific signal strength
143
+ *
144
+ * Uses linear interpolation between color stops to create
145
+ * smooth gradients.
146
+ *
147
+ * Process:
148
+ * 1. Find two nearest color stops
149
+ * 2. Calculate interpolation factor
150
+ * 3. Interpolate RGB components
151
+ * 4. Convert back to hex
152
+ *
153
+ * @param signalDbm - Signal strength in dBm
154
+ * @param scheme - Color scheme to use
155
+ * @returns Hex color string
156
+ *
157
+ * @example
158
+ * const color = interpolateColor(-75, HEATMAP_RED_BLUE);
159
+ * // Returns color between -70 (orange-red) and -80 (orange)
160
+ * // e.g., "#FF7400"
161
+ */
162
+ export function interpolateColor(signalDbm, scheme) {
163
+ const stops = scheme.stops;
164
+ // Handle out-of-range values
165
+ if (signalDbm >= stops[0].value) {
166
+ return stops[0].color; // Strongest signal color
167
+ }
168
+ if (signalDbm <= stops[stops.length - 1].value) {
169
+ return stops[stops.length - 1].color; // Weakest signal color
170
+ }
171
+ // Handle no signal
172
+ if (signalDbm < -120) {
173
+ return scheme.noSignalColor;
174
+ }
175
+ // Find surrounding color stops
176
+ for (let i = 0; i < stops.length - 1; i++) {
177
+ const stop1 = stops[i];
178
+ const stop2 = stops[i + 1];
179
+ if (signalDbm >= stop2.value && signalDbm <= stop1.value) {
180
+ // Calculate interpolation factor (0 to 1)
181
+ const factor = (signalDbm - stop2.value) / (stop1.value - stop2.value);
182
+ // Interpolate between colors
183
+ return interpolateHexColors(stop2.color, stop1.color, factor);
184
+ }
185
+ }
186
+ // Fallback (shouldn't reach here)
187
+ return scheme.noSignalColor;
188
+ }
189
+ /**
190
+ * Get color for categorical quality level
191
+ *
192
+ * Returns discrete color based on quality level without interpolation.
193
+ *
194
+ * @param quality - Signal quality level
195
+ * @param scheme - Color scheme (optional, defaults to categorical)
196
+ * @returns Hex color string
197
+ */
198
+ export function getCategoricalColor(quality, scheme = CATEGORICAL) {
199
+ switch (quality) {
200
+ case 'excellent':
201
+ return scheme.stops[0]?.color || '#00FF00';
202
+ case 'good':
203
+ return scheme.stops[1]?.color || '#FFFF00';
204
+ case 'fair':
205
+ return scheme.stops[2]?.color || '#FFA500';
206
+ case 'poor':
207
+ return scheme.stops[3]?.color || '#FF0000';
208
+ case 'no-signal':
209
+ default:
210
+ return scheme.noSignalColor;
211
+ }
212
+ }
213
+ /**
214
+ * Get color based on signal thresholds
215
+ *
216
+ * Convenience function that combines threshold checking and coloring.
217
+ *
218
+ * @param signalDbm - Signal strength in dBm
219
+ * @param thresholds - Signal quality thresholds
220
+ * @param scheme - Color scheme to use
221
+ * @returns Hex color string
222
+ */
223
+ export function getColorForSignal(signalDbm, thresholds, scheme = DEFAULT_COLOR_SCHEME) {
224
+ // Determine quality
225
+ let quality;
226
+ if (signalDbm >= thresholds.excellent) {
227
+ quality = 'excellent';
228
+ }
229
+ else if (signalDbm >= thresholds.good) {
230
+ quality = 'good';
231
+ }
232
+ else if (signalDbm >= thresholds.fair) {
233
+ quality = 'fair';
234
+ }
235
+ else if (signalDbm >= thresholds.edge) {
236
+ quality = 'poor';
237
+ }
238
+ else {
239
+ quality = 'no-signal';
240
+ }
241
+ // Use interpolation for smooth gradients or categorical for discrete
242
+ if (scheme.name.includes('Heatmap') || scheme.name.includes('friendly')) {
243
+ return interpolateColor(signalDbm, scheme);
244
+ }
245
+ else {
246
+ return getCategoricalColor(quality, scheme);
247
+ }
248
+ }
249
+ // ============================================================================
250
+ // HELPER FUNCTIONS
251
+ // ============================================================================
252
+ /**
253
+ * Interpolate between two hex colors
254
+ *
255
+ * Converts hex to RGB, interpolates, converts back.
256
+ *
257
+ * @param color1 - Start color (hex)
258
+ * @param color2 - End color (hex)
259
+ * @param factor - Interpolation factor (0 to 1)
260
+ * @returns Interpolated color (hex)
261
+ */
262
+ function interpolateHexColors(color1, color2, factor) {
263
+ // Parse hex colors
264
+ const rgb1 = hexToRgb(color1);
265
+ const rgb2 = hexToRgb(color2);
266
+ if (!rgb1 || !rgb2) {
267
+ return color1; // Fallback
268
+ }
269
+ // Interpolate each component
270
+ const r = Math.round(rgb1.r + (rgb2.r - rgb1.r) * factor);
271
+ const g = Math.round(rgb1.g + (rgb2.g - rgb1.g) * factor);
272
+ const b = Math.round(rgb1.b + (rgb2.b - rgb1.b) * factor);
273
+ // Convert back to hex
274
+ return rgbToHex(r, g, b);
275
+ }
276
+ /**
277
+ * Convert hex color to RGB
278
+ *
279
+ * @param hex - Hex color string (e.g., "#FF0000" or "FF0000")
280
+ * @returns RGB object or null
281
+ */
282
+ function hexToRgb(hex) {
283
+ // Remove # if present
284
+ hex = hex.replace(/^#/, '');
285
+ // Parse hex digits
286
+ if (hex.length === 3) {
287
+ // Short form: #RGB → #RRGGBB
288
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
289
+ }
290
+ if (hex.length !== 6) {
291
+ return null;
292
+ }
293
+ const r = parseInt(hex.substring(0, 2), 16);
294
+ const g = parseInt(hex.substring(2, 4), 16);
295
+ const b = parseInt(hex.substring(4, 6), 16);
296
+ if (isNaN(r) || isNaN(g) || isNaN(b)) {
297
+ return null;
298
+ }
299
+ return { r, g, b };
300
+ }
301
+ /**
302
+ * Convert RGB to hex color
303
+ *
304
+ * @param r - Red (0-255)
305
+ * @param g - Green (0-255)
306
+ * @param b - Blue (0-255)
307
+ * @returns Hex color string
308
+ */
309
+ function rgbToHex(r, g, b) {
310
+ // Clamp values to 0-255
311
+ r = Math.max(0, Math.min(255, r));
312
+ g = Math.max(0, Math.min(255, g));
313
+ b = Math.max(0, Math.min(255, b));
314
+ // Convert to hex
315
+ const rHex = r.toString(16).padStart(2, '0');
316
+ const gHex = g.toString(16).padStart(2, '0');
317
+ const bHex = b.toString(16).padStart(2, '0');
318
+ return `#${rHex}${gHex}${bHex}`.toUpperCase();
319
+ }
320
+ /**
321
+ * Add opacity to hex color
322
+ *
323
+ * Converts hex to rgba with specified opacity.
324
+ *
325
+ * @param hex - Hex color
326
+ * @param opacity - Opacity (0-1)
327
+ * @returns RGBA color string
328
+ *
329
+ * @example
330
+ * const semi = addOpacity("#FF0000", 0.5);
331
+ * // Returns: "rgba(255, 0, 0, 0.5)"
332
+ */
333
+ export function addOpacity(hex, opacity) {
334
+ const rgb = hexToRgb(hex);
335
+ if (!rgb) {
336
+ return `rgba(0, 0, 0, ${opacity})`;
337
+ }
338
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${opacity})`;
339
+ }
340
+ /**
341
+ * Create legend entries for a color scheme
342
+ *
343
+ * Generates legend data for UI display.
344
+ *
345
+ * @param scheme - Color scheme
346
+ * @param thresholds - Signal thresholds
347
+ * @returns Array of legend entries
348
+ */
349
+ export function createLegend(scheme, thresholds) {
350
+ return [
351
+ {
352
+ label: 'Excellent',
353
+ color: getColorForSignal(thresholds.excellent, thresholds, scheme),
354
+ range: `≥ ${thresholds.excellent} dBm`
355
+ },
356
+ {
357
+ label: 'Good',
358
+ color: getColorForSignal((thresholds.excellent + thresholds.good) / 2, thresholds, scheme),
359
+ range: `${thresholds.good} to ${thresholds.excellent} dBm`
360
+ },
361
+ {
362
+ label: 'Fair',
363
+ color: getColorForSignal((thresholds.good + thresholds.fair) / 2, thresholds, scheme),
364
+ range: `${thresholds.fair} to ${thresholds.good} dBm`
365
+ },
366
+ {
367
+ label: 'Poor',
368
+ color: getColorForSignal((thresholds.fair + thresholds.edge) / 2, thresholds, scheme),
369
+ range: `${thresholds.edge} to ${thresholds.fair} dBm`
370
+ },
371
+ {
372
+ label: 'No Signal',
373
+ color: scheme.noSignalColor,
374
+ range: `< ${thresholds.edge} dBm`
375
+ }
376
+ ];
377
+ }
@@ -8,7 +8,7 @@
8
8
  * - Indeterminate states for partial selection
9
9
  * - Expand/collapse functionality
10
10
  * - LocalStorage persistence
11
- * - Svelte store for reactive state
11
+ * - Svelte 5 runes for reactive state ($state, SvelteMap, SvelteSet)
12
12
  * - Bootstrap styling
13
13
  *
14
14
  * @example
@@ -34,7 +34,7 @@
34
34
  * const treeStore = createTreeStore(config);
35
35
  *
36
36
  * $effect(() => {
37
- * console.log('Checked paths:', $treeStore.state.checkedPaths);
37
+ * console.log('Checked paths:', treeStore.state.checkedPaths);
38
38
  * });
39
39
  * </script>
40
40
  *
@@ -43,6 +43,6 @@
43
43
  */
44
44
  export { default as TreeView } from './TreeView.svelte';
45
45
  export { default as TreeNodeComponent } from './TreeNode.svelte';
46
- export { createTreeStore } from './tree.store';
46
+ export { createTreeStore, TreeStore } from './tree.store.svelte';
47
47
  export type { TreeNode, TreeConfig, TreeState, NodeState, TreeStoreValue } from './tree.model';
48
- export { getParentPath, getAncestorPaths, isAncestor, getPathLevel, flattenTree, calculateIndeterminateStates, getDescendantPaths, buildInitialState } from './tree-utils';
48
+ export { getParentPath, getAncestorPaths, isAncestor, getPathLevel, flattenTree, flattenTreeToSvelteMap, calculateIndeterminateStates, calculateIndeterminateStatesAsSvelteSet, getDescendantPaths, buildInitialState } from './tree-utils';
@@ -8,7 +8,7 @@
8
8
  * - Indeterminate states for partial selection
9
9
  * - Expand/collapse functionality
10
10
  * - LocalStorage persistence
11
- * - Svelte store for reactive state
11
+ * - Svelte 5 runes for reactive state ($state, SvelteMap, SvelteSet)
12
12
  * - Bootstrap styling
13
13
  *
14
14
  * @example
@@ -34,7 +34,7 @@
34
34
  * const treeStore = createTreeStore(config);
35
35
  *
36
36
  * $effect(() => {
37
- * console.log('Checked paths:', $treeStore.state.checkedPaths);
37
+ * console.log('Checked paths:', treeStore.state.checkedPaths);
38
38
  * });
39
39
  * </script>
40
40
  *
@@ -44,7 +44,7 @@
44
44
  // Components
45
45
  export { default as TreeView } from './TreeView.svelte';
46
46
  export { default as TreeNodeComponent } from './TreeNode.svelte';
47
- // Store
48
- export { createTreeStore } from './tree.store';
47
+ // Store (Svelte 5 runes-based implementation)
48
+ export { createTreeStore, TreeStore } from './tree.store.svelte';
49
49
  // Utilities (for advanced usage)
50
- export { getParentPath, getAncestorPaths, isAncestor, getPathLevel, flattenTree, calculateIndeterminateStates, getDescendantPaths, buildInitialState } from './tree-utils';
50
+ export { getParentPath, getAncestorPaths, isAncestor, getPathLevel, flattenTree, flattenTreeToSvelteMap, calculateIndeterminateStates, calculateIndeterminateStatesAsSvelteSet, getDescendantPaths, buildInitialState } from './tree-utils';
@@ -2,6 +2,7 @@
2
2
  * Tree utility functions
3
3
  * Helper functions for path manipulation, tree flattening, and state management
4
4
  */
5
+ import { SvelteMap, SvelteSet } from 'svelte/reactivity';
5
6
  import type { TreeNode, NodeState, TreeState, TreeConfig } from './tree.model';
6
7
  /**
7
8
  * Get parent path from a node path
@@ -26,6 +27,10 @@ export declare function getPathLevel(path: string, separator?: string): number;
26
27
  * Flatten tree structure into map of NodeState
27
28
  */
28
29
  export declare function flattenTree<T = any>(nodes: TreeNode<T>[], config: TreeConfig<T>, parentPath?: string, level?: number): Map<string, NodeState>;
30
+ /**
31
+ * Flatten tree structure into SvelteMap for reactive state management (Svelte 5)
32
+ */
33
+ export declare function flattenTreeToSvelteMap<T = any>(nodes: TreeNode<T>[], config: TreeConfig<T>, parentPath?: string, level?: number): SvelteMap<string, NodeState>;
29
34
  /**
30
35
  * Calculate which nodes should be indeterminate
31
36
  * A node is indeterminate if:
@@ -33,12 +38,18 @@ export declare function flattenTree<T = any>(nodes: TreeNode<T>[], config: TreeC
33
38
  * - Some (but not all) of its direct children are checked OR indeterminate
34
39
  */
35
40
  export declare function calculateIndeterminateStates(nodes: Map<string, NodeState>, checkedPaths: Set<string>): Set<string>;
41
+ /**
42
+ * Calculate indeterminate states returning SvelteSet for reactive state management
43
+ * Same logic as calculateIndeterminateStates but returns SvelteSet
44
+ */
45
+ export declare function calculateIndeterminateStatesAsSvelteSet(nodes: Map<string, NodeState>, checkedPaths: Set<string>): SvelteSet<string>;
36
46
  /**
37
47
  * Get all descendant paths of a node
38
48
  */
39
49
  export declare function getDescendantPaths(path: string, nodes: Map<string, NodeState>, separator?: string): string[];
40
50
  /**
41
51
  * Build initial TreeState from flattened nodes
52
+ * Works with both regular Map/Set and SvelteMap/SvelteSet
42
53
  */
43
54
  export declare function buildInitialState(nodes: Map<string, NodeState>, config: TreeConfig): TreeState;
44
55
  /**
@@ -51,6 +62,7 @@ export declare function getStorageKey(namespace: string, key: string): string;
51
62
  export declare function saveStateToStorage(namespace: string, state: TreeState): void;
52
63
  /**
53
64
  * Load state from localStorage
65
+ * Returns SvelteSet for reactive state management
54
66
  */
55
67
  export declare function loadStateFromStorage(namespace: string, state: TreeState): Partial<TreeState>;
56
68
  /**
@@ -2,6 +2,7 @@
2
2
  * Tree utility functions
3
3
  * Helper functions for path manipulation, tree flattening, and state management
4
4
  */
5
+ import { SvelteMap, SvelteSet } from 'svelte/reactivity';
5
6
  import { log } from '../logger';
6
7
  /**
7
8
  * Get parent path from a node path
@@ -74,6 +75,70 @@ export function flattenTree(nodes, config, parentPath = '', level = 0) {
74
75
  }
75
76
  return map;
76
77
  }
78
+ /**
79
+ * Flatten tree structure into SvelteMap for reactive state management (Svelte 5)
80
+ */
81
+ export function flattenTreeToSvelteMap(nodes, config, parentPath = '', level = 0) {
82
+ const map = new SvelteMap();
83
+ const separator = config.pathSeparator || ':';
84
+ for (const node of nodes) {
85
+ const path = parentPath ? `${parentPath}${separator}${node.id}` : node.id;
86
+ // Collect child paths
87
+ const childPaths = [];
88
+ if (node.children && node.children.length > 0) {
89
+ for (const child of node.children) {
90
+ childPaths.push(parentPath ? `${path}${separator}${child.id}` : `${path}${separator}${child.id}`);
91
+ }
92
+ }
93
+ const nodeState = {
94
+ path,
95
+ checked: node.defaultChecked ?? true,
96
+ indeterminate: false,
97
+ expanded: node.defaultExpanded ?? (config.defaultExpandAll || false),
98
+ node,
99
+ parentPath,
100
+ childPaths,
101
+ level
102
+ };
103
+ map.set(path, nodeState);
104
+ // Recursively flatten children
105
+ if (node.children && node.children.length > 0) {
106
+ flattenTreeToSvelteMapRecursive(node.children, config, path, level + 1, map);
107
+ }
108
+ }
109
+ return map;
110
+ }
111
+ /**
112
+ * Helper for recursive flattening into existing SvelteMap
113
+ */
114
+ function flattenTreeToSvelteMapRecursive(nodes, config, parentPath, level, map) {
115
+ const separator = config.pathSeparator || ':';
116
+ for (const node of nodes) {
117
+ const path = `${parentPath}${separator}${node.id}`;
118
+ // Collect child paths
119
+ const childPaths = [];
120
+ if (node.children && node.children.length > 0) {
121
+ for (const child of node.children) {
122
+ childPaths.push(`${path}${separator}${child.id}`);
123
+ }
124
+ }
125
+ const nodeState = {
126
+ path,
127
+ checked: node.defaultChecked ?? true,
128
+ indeterminate: false,
129
+ expanded: node.defaultExpanded ?? (config.defaultExpandAll || false),
130
+ node,
131
+ parentPath,
132
+ childPaths,
133
+ level
134
+ };
135
+ map.set(path, nodeState);
136
+ // Recursively flatten children
137
+ if (node.children && node.children.length > 0) {
138
+ flattenTreeToSvelteMapRecursive(node.children, config, path, level + 1, map);
139
+ }
140
+ }
141
+ }
77
142
  /**
78
143
  * Calculate which nodes should be indeterminate
79
144
  * A node is indeterminate if:
@@ -117,6 +182,47 @@ export function calculateIndeterminateStates(nodes, checkedPaths) {
117
182
  }
118
183
  return indeterminate;
119
184
  }
185
+ /**
186
+ * Calculate indeterminate states returning SvelteSet for reactive state management
187
+ * Same logic as calculateIndeterminateStates but returns SvelteSet
188
+ */
189
+ export function calculateIndeterminateStatesAsSvelteSet(nodes, checkedPaths) {
190
+ const indeterminate = new SvelteSet();
191
+ // For each node with children, check from deepest to shallowest
192
+ // This ensures we calculate indeterminate state correctly
193
+ const nodesArray = Array.from(nodes.entries());
194
+ // Sort by level (deepest first) to ensure we process children before parents
195
+ nodesArray.sort((a, b) => b[1].level - a[1].level);
196
+ for (const [path, nodeState] of nodesArray) {
197
+ // Skip leaf nodes - they can't be indeterminate
198
+ if (nodeState.childPaths.length === 0)
199
+ continue;
200
+ // Count direct children that are either checked or indeterminate
201
+ let checkedCount = 0;
202
+ let indeterminateCount = 0;
203
+ for (const childPath of nodeState.childPaths) {
204
+ if (checkedPaths.has(childPath)) {
205
+ checkedCount++;
206
+ }
207
+ else if (indeterminate.has(childPath)) {
208
+ indeterminateCount++;
209
+ }
210
+ }
211
+ const totalChildren = nodeState.childPaths.length;
212
+ const affectedChildren = checkedCount + indeterminateCount;
213
+ // Node is indeterminate if:
214
+ // 1. Some children are checked/indeterminate, but not all
215
+ // 2. At least one child is indeterminate (even if all are checked/indeterminate)
216
+ if (affectedChildren > 0 && affectedChildren < totalChildren) {
217
+ indeterminate.add(path);
218
+ }
219
+ else if (indeterminateCount > 0) {
220
+ // If any child is indeterminate, parent is indeterminate
221
+ indeterminate.add(path);
222
+ }
223
+ }
224
+ return indeterminate;
225
+ }
120
226
  /**
121
227
  * Get all descendant paths of a node
122
228
  */
@@ -131,10 +237,12 @@ export function getDescendantPaths(path, nodes, separator = ':') {
131
237
  }
132
238
  /**
133
239
  * Build initial TreeState from flattened nodes
240
+ * Works with both regular Map/Set and SvelteMap/SvelteSet
134
241
  */
135
242
  export function buildInitialState(nodes, config) {
136
- const checkedPaths = new Set();
137
- const expandedPaths = new Set();
243
+ // Use SvelteSet for reactive collections
244
+ const checkedPaths = new SvelteSet();
245
+ const expandedPaths = new SvelteSet();
138
246
  const rootPaths = [];
139
247
  nodes.forEach((nodeState, path) => {
140
248
  if (nodeState.checked) {
@@ -147,7 +255,7 @@ export function buildInitialState(nodes, config) {
147
255
  rootPaths.push(path);
148
256
  }
149
257
  });
150
- const indeterminatePaths = calculateIndeterminateStates(nodes, checkedPaths);
258
+ const indeterminatePaths = calculateIndeterminateStatesAsSvelteSet(nodes, checkedPaths);
151
259
  return {
152
260
  nodes,
153
261
  checkedPaths,
@@ -186,6 +294,7 @@ export function saveStateToStorage(namespace, state) {
186
294
  }
187
295
  /**
188
296
  * Load state from localStorage
297
+ * Returns SvelteSet for reactive state management
189
298
  */
190
299
  export function loadStateFromStorage(namespace, state) {
191
300
  if (!namespace)
@@ -196,9 +305,9 @@ export function loadStateFromStorage(namespace, state) {
196
305
  const updates = {};
197
306
  if (checkedJson) {
198
307
  const checkedArray = JSON.parse(checkedJson);
199
- updates.checkedPaths = new Set(checkedArray);
308
+ updates.checkedPaths = new SvelteSet(checkedArray);
200
309
  // Recalculate indeterminate states
201
- updates.indeterminatePaths = calculateIndeterminateStates(state.nodes, updates.checkedPaths);
310
+ updates.indeterminatePaths = calculateIndeterminateStatesAsSvelteSet(state.nodes, updates.checkedPaths);
202
311
  log('📂 Loaded checked paths from localStorage', {
203
312
  namespace,
204
313
  checkedCount: checkedArray.length
@@ -206,7 +315,7 @@ export function loadStateFromStorage(namespace, state) {
206
315
  }
207
316
  if (expandedJson) {
208
317
  const expandedArray = JSON.parse(expandedJson);
209
- updates.expandedPaths = new Set(expandedArray);
318
+ updates.expandedPaths = new SvelteSet(expandedArray);
210
319
  log('📂 Loaded expanded paths from localStorage', {
211
320
  namespace,
212
321
  expandedCount: expandedArray.length