@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,94 @@
1
+ /**
2
+ * Tree Store - Svelte 5 Runes Implementation
3
+ * Reactive state management for tree with persistence
4
+ *
5
+ * This is a modernized implementation using Svelte 5 runes ($state, $derived)
6
+ * with SvelteMap and SvelteSet for reactive collections.
7
+ *
8
+ * BREAKING CHANGE from previous version:
9
+ * - createTreeStore() now returns TreeStoreValue directly (not a Svelte store)
10
+ * - Use `treeStore` directly instead of `$treeStore`
11
+ * - Pass `store={treeStore}` instead of `store={$treeStore}`
12
+ */
13
+ import type { TreeConfig, TreeState, TreeStoreValue } from './tree.model';
14
+ /**
15
+ * TreeStore class using Svelte 5 runes for reactive state management
16
+ */
17
+ declare class TreeStore<T = any> {
18
+ #private;
19
+ constructor(config: TreeConfig<T>);
20
+ /** Get current tree state (reactive) */
21
+ get state(): TreeState;
22
+ /** Get config */
23
+ get config(): TreeConfig<T>;
24
+ /**
25
+ * Toggle a node's checked state (with cascading)
26
+ *
27
+ * Logic:
28
+ * 1. Toggle the clicked node
29
+ * 2. Cascade DOWN to all descendants (check/uncheck all children)
30
+ * 3. Propagate UP to all ancestors (update based on their children's states)
31
+ */
32
+ toggle: (path: string) => void;
33
+ /**
34
+ * Toggle expanded/collapsed state
35
+ */
36
+ toggleExpand: (path: string) => void;
37
+ /**
38
+ * Expand all nodes
39
+ */
40
+ expandAll: () => void;
41
+ /**
42
+ * Collapse all nodes
43
+ */
44
+ collapseAll: () => void;
45
+ /**
46
+ * Check all nodes
47
+ */
48
+ checkAll: () => void;
49
+ /**
50
+ * Uncheck all nodes
51
+ */
52
+ uncheckAll: () => void;
53
+ /**
54
+ * Get all checked paths
55
+ */
56
+ getCheckedPaths: () => string[];
57
+ /**
58
+ * Get only checked leaf paths (nodes without children)
59
+ */
60
+ getCheckedLeafPaths: () => string[];
61
+ /**
62
+ * Clear localStorage
63
+ */
64
+ clearStorage: () => void;
65
+ /**
66
+ * Convert to TreeStoreValue for backward compatibility
67
+ * This allows the store to work with existing components expecting the old interface
68
+ */
69
+ toStoreValue(): TreeStoreValue;
70
+ }
71
+ /**
72
+ * Create a tree store with state management and persistence
73
+ *
74
+ * This function maintains backward compatibility with the original API.
75
+ * It returns an object that behaves like the old Svelte store but uses
76
+ * Svelte 5 runes internally for reactivity.
77
+ *
78
+ * @example
79
+ * ```svelte
80
+ * <script>
81
+ * import { createTreeStore } from './';
82
+ *
83
+ * const treeStore = createTreeStore({
84
+ * nodes: [...],
85
+ * namespace: 'my-app',
86
+ * persistState: true
87
+ * });
88
+ * </script>
89
+ *
90
+ * <TreeView store={treeStore} />
91
+ * ```
92
+ */
93
+ export declare function createTreeStore<T = any>(config: TreeConfig<T>): TreeStoreValue;
94
+ export { TreeStore };
@@ -0,0 +1,274 @@
1
+ /**
2
+ * Tree Store - Svelte 5 Runes Implementation
3
+ * Reactive state management for tree with persistence
4
+ *
5
+ * This is a modernized implementation using Svelte 5 runes ($state, $derived)
6
+ * with SvelteMap and SvelteSet for reactive collections.
7
+ *
8
+ * BREAKING CHANGE from previous version:
9
+ * - createTreeStore() now returns TreeStoreValue directly (not a Svelte store)
10
+ * - Use `treeStore` directly instead of `$treeStore`
11
+ * - Pass `store={treeStore}` instead of `store={$treeStore}`
12
+ */
13
+ import { SvelteMap, SvelteSet } from 'svelte/reactivity';
14
+ import { flattenTreeToSvelteMap, buildInitialState, calculateIndeterminateStates, getDescendantPaths, getAncestorPaths, saveStateToStorage, loadStateFromStorage, clearStorageForNamespace } from './tree-utils';
15
+ /**
16
+ * TreeStore class using Svelte 5 runes for reactive state management
17
+ */
18
+ class TreeStore {
19
+ // Reactive state using $state
20
+ #state = $state({
21
+ nodes: new SvelteMap(),
22
+ checkedPaths: new SvelteSet(),
23
+ expandedPaths: new SvelteSet(),
24
+ indeterminatePaths: new SvelteSet(),
25
+ rootPaths: []
26
+ });
27
+ #config;
28
+ #separator;
29
+ constructor(config) {
30
+ this.#config = config;
31
+ this.#separator = config.pathSeparator || ':';
32
+ // Flatten tree structure using SvelteMap
33
+ const nodesMap = flattenTreeToSvelteMap(config.nodes, config);
34
+ // Build initial state
35
+ const initialState = buildInitialState(nodesMap, config);
36
+ // Set initial state
37
+ this.#state = initialState;
38
+ // Load persisted state if enabled
39
+ if (config.persistState && config.namespace) {
40
+ const persistedState = loadStateFromStorage(config.namespace, this.#state);
41
+ if (persistedState.checkedPaths) {
42
+ this.#state.checkedPaths = persistedState.checkedPaths;
43
+ }
44
+ if (persistedState.expandedPaths) {
45
+ this.#state.expandedPaths = persistedState.expandedPaths;
46
+ }
47
+ if (persistedState.indeterminatePaths) {
48
+ this.#state.indeterminatePaths = persistedState.indeterminatePaths;
49
+ }
50
+ }
51
+ }
52
+ /** Get current tree state (reactive) */
53
+ get state() {
54
+ return this.#state;
55
+ }
56
+ /** Get config */
57
+ get config() {
58
+ return this.#config;
59
+ }
60
+ /**
61
+ * Persist state to localStorage if enabled
62
+ */
63
+ #persistState() {
64
+ if (this.#config.persistState && this.#config.namespace) {
65
+ saveStateToStorage(this.#config.namespace, this.#state);
66
+ }
67
+ }
68
+ /**
69
+ * Toggle a node's checked state (with cascading)
70
+ *
71
+ * Logic:
72
+ * 1. Toggle the clicked node
73
+ * 2. Cascade DOWN to all descendants (check/uncheck all children)
74
+ * 3. Propagate UP to all ancestors (update based on their children's states)
75
+ */
76
+ toggle = (path) => {
77
+ const nodeState = this.#state.nodes.get(path);
78
+ if (!nodeState) {
79
+ return;
80
+ }
81
+ const newChecked = !this.#state.checkedPaths.has(path);
82
+ // STEP 0: If singleRootSelect mode and this is a root node being checked, uncheck all other roots
83
+ if (this.#config.singleRootSelect && newChecked && nodeState.level === 0) {
84
+ // Uncheck all root nodes and their descendants
85
+ this.#state.rootPaths.forEach(rootPath => {
86
+ if (rootPath !== path) {
87
+ this.#state.checkedPaths.delete(rootPath);
88
+ // Also uncheck all descendants of this root
89
+ const rootDescendants = getDescendantPaths(rootPath, this.#state.nodes, this.#separator);
90
+ rootDescendants.forEach(descendantPath => {
91
+ this.#state.checkedPaths.delete(descendantPath);
92
+ });
93
+ }
94
+ });
95
+ }
96
+ // STEP 0.5: If singleLevel1Select mode and this is a Level 1 node being checked, uncheck sibling Level 1 nodes
97
+ if (this.#config.singleLevel1Select && newChecked && nodeState.level === 1) {
98
+ const parentPath = nodeState.parentPath;
99
+ // Find and uncheck all Level 1 siblings (same parent, same level, different path)
100
+ this.#state.nodes.forEach((node, nodePath) => {
101
+ if (node.level === 1 &&
102
+ node.parentPath === parentPath &&
103
+ nodePath !== path) {
104
+ this.#state.checkedPaths.delete(nodePath);
105
+ // Also uncheck all descendants of this sibling
106
+ const siblingDescendants = getDescendantPaths(nodePath, this.#state.nodes, this.#separator);
107
+ siblingDescendants.forEach(descendantPath => {
108
+ this.#state.checkedPaths.delete(descendantPath);
109
+ });
110
+ }
111
+ });
112
+ }
113
+ // STEP 1: Update this node
114
+ if (newChecked) {
115
+ this.#state.checkedPaths.add(path);
116
+ }
117
+ else {
118
+ this.#state.checkedPaths.delete(path);
119
+ }
120
+ // STEP 2: CASCADE DOWN - Update all descendants to match
121
+ const descendants = getDescendantPaths(path, this.#state.nodes, this.#separator);
122
+ descendants.forEach(descendantPath => {
123
+ if (newChecked) {
124
+ this.#state.checkedPaths.add(descendantPath);
125
+ }
126
+ else {
127
+ this.#state.checkedPaths.delete(descendantPath);
128
+ }
129
+ });
130
+ // STEP 3: PROPAGATE UP - Update all ancestors based on their children
131
+ const ancestorPaths = getAncestorPaths(path, this.#separator);
132
+ // Process ancestors from deepest to shallowest (reverse order)
133
+ for (let i = ancestorPaths.length - 1; i >= 0; i--) {
134
+ const ancestorPath = ancestorPaths[i];
135
+ const ancestor = this.#state.nodes.get(ancestorPath);
136
+ if (!ancestor)
137
+ continue;
138
+ // Count how many direct children are checked
139
+ const checkedChildrenCount = ancestor.childPaths.filter(childPath => this.#state.checkedPaths.has(childPath)).length;
140
+ const totalChildren = ancestor.childPaths.length;
141
+ // Update ancestor based on children states
142
+ if (checkedChildrenCount === totalChildren) {
143
+ this.#state.checkedPaths.add(ancestorPath);
144
+ }
145
+ else {
146
+ this.#state.checkedPaths.delete(ancestorPath);
147
+ }
148
+ }
149
+ // STEP 4: Recalculate indeterminate states
150
+ const newIndeterminatePaths = calculateIndeterminateStates(this.#state.nodes, this.#state.checkedPaths);
151
+ this.#state.indeterminatePaths.clear();
152
+ newIndeterminatePaths.forEach(p => this.#state.indeterminatePaths.add(p));
153
+ this.#persistState();
154
+ };
155
+ /**
156
+ * Toggle expanded/collapsed state
157
+ */
158
+ toggleExpand = (path) => {
159
+ if (this.#state.expandedPaths.has(path)) {
160
+ this.#state.expandedPaths.delete(path);
161
+ }
162
+ else {
163
+ this.#state.expandedPaths.add(path);
164
+ }
165
+ this.#persistState();
166
+ };
167
+ /**
168
+ * Expand all nodes
169
+ */
170
+ expandAll = () => {
171
+ this.#state.nodes.forEach((nodeState, path) => {
172
+ if (nodeState.childPaths.length > 0) {
173
+ this.#state.expandedPaths.add(path);
174
+ }
175
+ });
176
+ this.#persistState();
177
+ };
178
+ /**
179
+ * Collapse all nodes
180
+ */
181
+ collapseAll = () => {
182
+ this.#state.expandedPaths.clear();
183
+ this.#persistState();
184
+ };
185
+ /**
186
+ * Check all nodes
187
+ */
188
+ checkAll = () => {
189
+ this.#state.nodes.forEach((_, path) => {
190
+ this.#state.checkedPaths.add(path);
191
+ });
192
+ // Clear indeterminate states when all checked
193
+ this.#state.indeterminatePaths.clear();
194
+ this.#persistState();
195
+ };
196
+ /**
197
+ * Uncheck all nodes
198
+ */
199
+ uncheckAll = () => {
200
+ this.#state.checkedPaths.clear();
201
+ this.#state.indeterminatePaths.clear();
202
+ this.#persistState();
203
+ };
204
+ /**
205
+ * Get all checked paths
206
+ */
207
+ getCheckedPaths = () => {
208
+ return Array.from(this.#state.checkedPaths);
209
+ };
210
+ /**
211
+ * Get only checked leaf paths (nodes without children)
212
+ */
213
+ getCheckedLeafPaths = () => {
214
+ return Array.from(this.#state.checkedPaths).filter(path => {
215
+ const node = this.#state.nodes.get(path);
216
+ return node && node.childPaths.length === 0;
217
+ });
218
+ };
219
+ /**
220
+ * Clear localStorage
221
+ */
222
+ clearStorage = () => {
223
+ if (this.#config.namespace) {
224
+ clearStorageForNamespace(this.#config.namespace);
225
+ }
226
+ };
227
+ /**
228
+ * Convert to TreeStoreValue for backward compatibility
229
+ * This allows the store to work with existing components expecting the old interface
230
+ */
231
+ toStoreValue() {
232
+ return {
233
+ state: this.#state,
234
+ config: this.#config,
235
+ toggle: this.toggle,
236
+ toggleExpand: this.toggleExpand,
237
+ expandAll: this.expandAll,
238
+ collapseAll: this.collapseAll,
239
+ checkAll: this.checkAll,
240
+ uncheckAll: this.uncheckAll,
241
+ getCheckedPaths: this.getCheckedPaths,
242
+ getCheckedLeafPaths: this.getCheckedLeafPaths,
243
+ clearStorage: this.clearStorage
244
+ };
245
+ }
246
+ }
247
+ /**
248
+ * Create a tree store with state management and persistence
249
+ *
250
+ * This function maintains backward compatibility with the original API.
251
+ * It returns an object that behaves like the old Svelte store but uses
252
+ * Svelte 5 runes internally for reactivity.
253
+ *
254
+ * @example
255
+ * ```svelte
256
+ * <script>
257
+ * import { createTreeStore } from './';
258
+ *
259
+ * const treeStore = createTreeStore({
260
+ * nodes: [...],
261
+ * namespace: 'my-app',
262
+ * persistState: true
263
+ * });
264
+ * </script>
265
+ *
266
+ * <TreeView store={treeStore} />
267
+ * ```
268
+ */
269
+ export function createTreeStore(config) {
270
+ const store = new TreeStore(config);
271
+ return store.toStoreValue();
272
+ }
273
+ // Also export the class for advanced usage
274
+ export { TreeStore };
@@ -3,4 +3,5 @@ export * from './Charts/index.js';
3
3
  export * from './TreeView/index.js';
4
4
  export * from './Settings/index.js';
5
5
  export * from './logger/index.js';
6
+ export * from './CellTable/index.js';
6
7
  export * from './FeatureRegistry/index.js';
@@ -10,6 +10,8 @@ export * from './TreeView/index.js';
10
10
  export * from './Settings/index.js';
11
11
  // Logger utility for debugging and monitoring
12
12
  export * from './logger/index.js';
13
+ // CellTable - Tabulator-based cell data table with Bootstrap theming
14
+ export * from './CellTable/index.js';
13
15
  // Map component - Mapbox GL + Deck.GL integration
14
16
  // TODO: Moved to top-level src/lib/map module
15
17
  // export * from './Map/index.js';
@@ -11,14 +11,11 @@
11
11
  */
12
12
 
13
13
  import { onMount } from 'svelte';
14
- import type { Writable } from 'svelte/store';
15
14
  import MapControl from '../../../shared/controls/MapControl.svelte';
16
- import TreeView from '../../../../core/TreeView/TreeView.svelte';
17
- import { createTreeStore } from '../../../../core/TreeView/tree.store';
15
+ import { TreeView, createTreeStore, type TreeStoreValue } from '../../../../core/TreeView';
18
16
  import { buildCellTree, getFilteredCells } from '../utils/cellTree';
19
17
  import type { CellStoreContext } from '../stores/cellStoreContext.svelte';
20
18
  import type { CellGroupingField, CellGroupingLabels } from '../types';
21
- import type { TreeStoreValue } from '../../../../core/TreeView/tree.model';
22
19
 
23
20
  interface Props {
24
21
  /** Cell store context */
@@ -53,7 +50,7 @@
53
50
  initiallyCollapsed = true
54
51
  }: Props = $props();
55
52
 
56
- let treeStore = $state<Writable<TreeStoreValue> | null>(null);
53
+ let treeStore = $state<TreeStoreValue | null>(null);
57
54
  let level1 = $state<Exclude<CellGroupingField, 'none'>>(store.groupingConfig.level1);
58
55
  let level2 = $state<CellGroupingField>(store.groupingConfig.level2);
59
56
 
@@ -109,29 +106,21 @@
109
106
  persistState: true,
110
107
  defaultExpandAll: false
111
108
  });
109
+ }
112
110
 
113
- // Subscribe to tree changes and update filtered cells
111
+ // Sync tree selection with cell store (reactive via $effect)
112
+ $effect(() => {
114
113
  if (treeStore) {
115
- // This subscription now only syncs the checkedPaths state
116
- // The $effect above will handle the actual filtering
117
- const unsub = treeStore.subscribe((treeValue: TreeStoreValue) => {
118
- // getCheckedPaths() is expensive, so check if tree is initializing
119
- if (treeValue.isInitializing) return;
120
-
121
- const newCheckedPaths = new Set(treeValue.getCheckedPaths());
122
-
123
- // Avoid unnecessary updates if the set hasn't changed
124
- if (
125
- newCheckedPaths.size !== checkedPaths.size ||
126
- ![...newCheckedPaths].every((path) => checkedPaths.has(path))
127
- ) {
128
- checkedPaths = newCheckedPaths;
129
- }
130
- });
131
-
132
- return () => unsub();
114
+ const newCheckedPaths = new Set(treeStore.getCheckedPaths());
115
+ // Only update if changed to avoid infinite loops
116
+ if (
117
+ newCheckedPaths.size !== checkedPaths.size ||
118
+ ![...newCheckedPaths].every((path) => checkedPaths.has(path))
119
+ ) {
120
+ checkedPaths = newCheckedPaths;
121
+ }
133
122
  }
134
- }
123
+ });
135
124
 
136
125
  onMount(() => {
137
126
  rebuildTree();
@@ -235,9 +224,9 @@
235
224
  </div>
236
225
 
237
226
  <!-- Tree View -->
238
- {#if treeStore && $treeStore}
227
+ {#if treeStore}
239
228
  <div class="cell-filter-tree">
240
- <TreeView store={$treeStore} showControls={false}>
229
+ <TreeView store={treeStore} showControls={false}>
241
230
  {#snippet children({ node, state })}
242
231
  <!-- Color picker for all leaf nodes (nodes with cells) -->
243
232
  {#if node.metadata?.type === 'leafGroup'}
@@ -10,13 +10,10 @@
10
10
  */
11
11
 
12
12
  import { onMount } from 'svelte';
13
- import type { Writable } from 'svelte/store';
14
13
  import MapControl from '../../../shared/controls/MapControl.svelte';
15
- import TreeView from '../../../../core/TreeView/TreeView.svelte';
16
- import { createTreeStore } from '../../../../core/TreeView/tree.store';
14
+ import { TreeView, createTreeStore, type TreeStoreValue } from '../../../../core/TreeView';
17
15
  import { buildRepeaterTree, getFilteredRepeaters } from '../utils/repeaterTree';
18
16
  import type { RepeaterStoreContext } from '../stores/repeaterStoreContext.svelte';
19
- import type { TreeStoreValue } from '../../../../core/TreeView/tree.model';
20
17
 
21
18
  interface Props {
22
19
  /** Repeater store context */
@@ -42,7 +39,7 @@
42
39
  initiallyCollapsed = true
43
40
  }: Props = $props();
44
41
 
45
- let treeStore = $state<Writable<TreeStoreValue> | null>(null);
42
+ let treeStore = $state<TreeStoreValue | null>(null);
46
43
 
47
44
  // Rebuild tree when repeaters change
48
45
  function rebuildTree() {
@@ -56,45 +53,39 @@
56
53
  persistState: true,
57
54
  defaultExpandAll: false
58
55
  });
59
-
60
- // Subscribe to tree changes and update filtered repeaters
56
+ }
57
+
58
+ // Sync tree selection with repeater store (reactive via $effect)
59
+ $effect(() => {
61
60
  if (treeStore) {
62
- const unsub = treeStore.subscribe((treeValue: TreeStoreValue) => {
63
- const checkedPaths = treeValue.getCheckedPaths();
64
-
65
- // Convert string[] to Set<string>
66
- const checkedPathsSet = new Set(checkedPaths);
67
- const selectedTechBands = getFilteredRepeaters(checkedPathsSet);
68
-
69
- // Update visibility for each tech:fband combination
70
- // First, get all tech:fband combinations from repeaters
71
- const allTechBands = new Set<string>();
72
- for (const repeater of store.repeaters) {
73
- const key = `${repeater.tech}:${repeater.fband}`;
74
- allTechBands.add(key);
75
- }
76
-
77
- // If only root checked, show all
78
- if (selectedTechBands.size === 0 && checkedPathsSet.has('root')) {
79
- // All visible - no toggle needed
80
- } else {
81
- // Toggle visibility based on selection
82
- for (const techBand of allTechBands) {
83
- const [tech, fband] = techBand.split(':');
84
- const shouldBeVisible = selectedTechBands.has(techBand);
85
- const isVisible = store.isTechBandVisible(tech, fband);
86
-
87
- // Only toggle if state needs to change
88
- if (shouldBeVisible !== isVisible) {
89
- store.toggleTechBand(tech, fband);
90
- }
61
+ const checkedPaths = treeStore.getCheckedPaths();
62
+ const checkedPathsSet = new Set(checkedPaths);
63
+ const selectedTechBands = getFilteredRepeaters(checkedPathsSet);
64
+
65
+ // Get all tech:fband combinations from repeaters
66
+ const allTechBands = new Set<string>();
67
+ for (const repeater of store.repeaters) {
68
+ const key = `${repeater.tech}:${repeater.fband}`;
69
+ allTechBands.add(key);
70
+ }
71
+
72
+ // If only root checked, show all
73
+ if (selectedTechBands.size === 0 && checkedPathsSet.has('root')) {
74
+ // All visible - no toggle needed
75
+ } else {
76
+ // Toggle visibility based on selection
77
+ for (const techBand of allTechBands) {
78
+ const [tech, fband] = techBand.split(':');
79
+ const shouldBeVisible = selectedTechBands.has(techBand);
80
+ const isVisible = store.isTechBandVisible(tech, fband);
81
+
82
+ if (shouldBeVisible !== isVisible) {
83
+ store.toggleTechBand(tech, fband);
91
84
  }
92
85
  }
93
- });
94
-
95
- return () => unsub();
86
+ }
96
87
  }
97
- }
88
+ });
98
89
 
99
90
  // Handle color changes from tree
100
91
  function handleColorChange(nodeId: string, color: string) {
@@ -117,9 +108,9 @@
117
108
  </script>
118
109
 
119
110
  <MapControl {position} {title} {icon} {iconOnlyWhenCollapsed} collapsible={true} {initiallyCollapsed}>
120
- {#if treeStore && $treeStore}
111
+ {#if treeStore}
121
112
  <div class="repeater-filter-tree">
122
- <TreeView store={$treeStore!} showControls={false}>
113
+ <TreeView store={treeStore} showControls={false}>
123
114
  {#snippet children({ node, state })}
124
115
  <!-- Color picker for leaf nodes (tech:fband combinations) -->
125
116
  {#if node.metadata?.color}
@@ -10,13 +10,10 @@
10
10
  * <SiteFilterControl {store} position="top-left" />
11
11
  */
12
12
  import { onMount } from 'svelte';
13
- import type { Writable } from 'svelte/store';
14
13
  import MapControl from '../../../shared/controls/MapControl.svelte';
15
- import TreeView from '../../../../core/TreeView/TreeView.svelte';
16
- import { createTreeStore } from '../../../../core/TreeView/tree.store';
14
+ import { TreeView, createTreeStore, type TreeStoreValue } from '../../../../core/TreeView';
17
15
  import { buildSiteTree, getFilteredSites } from '../utils/siteTreeUtils';
18
16
  import type { SiteStoreContext } from '../stores/siteStoreContext.svelte';
19
- import type { TreeStoreValue } from '../../../../core/TreeView/tree.model';
20
17
 
21
18
  interface Props {
22
19
  /** Site store instance */
@@ -42,7 +39,7 @@
42
39
  initiallyCollapsed = true
43
40
  }: Props = $props();
44
41
 
45
- let treeStore = $state<Writable<TreeStoreValue> | null>(null);
42
+ let treeStore = $state<TreeStoreValue | null>(null);
46
43
 
47
44
  onMount(() => {
48
45
  if (store.allSites.length > 0) {
@@ -54,19 +51,15 @@
54
51
  persistState: true,
55
52
  defaultExpandAll: false
56
53
  });
54
+ }
55
+ });
57
56
 
58
- // Subscribe to tree changes and update siteStore
59
- if (treeStore) {
60
- const unsub = treeStore.subscribe((treeValue: TreeStoreValue) => {
61
- const checkedPaths = treeValue.getCheckedPaths();
62
- const newFilteredSites = getFilteredSites(checkedPaths, store.allSites);
63
-
64
- // Update the site store directly
65
- store.filteredSites = newFilteredSites;
66
- });
67
-
68
- return () => unsub();
69
- }
57
+ // Sync tree selection with site store (reactive via $effect)
58
+ $effect(() => {
59
+ if (treeStore) {
60
+ const checkedPaths = treeStore.getCheckedPaths();
61
+ const newFilteredSites = getFilteredSites(checkedPaths, store.allSites);
62
+ store.filteredSites = newFilteredSites;
70
63
  }
71
64
  });
72
65
 
@@ -76,9 +69,9 @@
76
69
  </script>
77
70
 
78
71
  <MapControl {position} {title} {icon} {iconOnlyWhenCollapsed} collapsible={true} {initiallyCollapsed}>
79
- {#if treeStore && $treeStore}
72
+ {#if treeStore}
80
73
  <div class="site-filter-tree">
81
- <TreeView store={$treeStore} showControls={false}>
74
+ <TreeView store={treeStore} showControls={false}>
82
75
  {#snippet children({ node, state })}
83
76
  <!-- Custom node rendering with color picker for leaf nodes -->
84
77
  {#if node.metadata?.type === 'featureGroup'}
@@ -73,6 +73,10 @@
73
73
  <div bind:this={mapContainer} class="map-instance"></div>
74
74
  {#if mapStore.loaded}
75
75
  {@render children?.()}
76
+ {:else}
77
+ <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
78
+ Loading map...
79
+ </div>
76
80
  {/if}
77
81
  </div>
78
82
 
@@ -8,11 +8,13 @@ export class MapStore {
8
8
  init(container, options) {
9
9
  if (this.map)
10
10
  return;
11
+ console.log('[MapStore] Initializing map with options:', options);
11
12
  this.map = new mapboxgl.Map({
12
13
  container,
13
14
  ...options
14
15
  });
15
16
  this.map.on('load', () => {
17
+ console.log('[MapStore] Map loaded!');
16
18
  this.loaded = true;
17
19
  });
18
20
  }