@smartnet360/svelte-components 0.0.22 → 0.0.24

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 (36) hide show
  1. package/dist/apps/antenna-pattern/utils/msi-parser.js +2 -2
  2. package/dist/cellular/CellularChartsView.svelte +293 -0
  3. package/dist/cellular/CellularChartsView.svelte.d.ts +7 -0
  4. package/dist/cellular/HierarchicalTree.svelte +469 -0
  5. package/dist/cellular/HierarchicalTree.svelte.d.ts +9 -0
  6. package/dist/cellular/SiteTree.svelte +286 -0
  7. package/dist/cellular/SiteTree.svelte.d.ts +11 -0
  8. package/dist/cellular/cellular-transforms.d.ts +25 -0
  9. package/dist/cellular/cellular-transforms.js +129 -0
  10. package/dist/cellular/cellular.model.d.ts +63 -0
  11. package/dist/cellular/cellular.model.js +6 -0
  12. package/dist/cellular/index.d.ts +11 -0
  13. package/dist/cellular/index.js +11 -0
  14. package/dist/cellular/mock-cellular-data.d.ts +13 -0
  15. package/dist/cellular/mock-cellular-data.js +241 -0
  16. package/dist/core/TreeChartView/TreeChartView.svelte +208 -0
  17. package/dist/core/TreeChartView/TreeChartView.svelte.d.ts +42 -0
  18. package/dist/core/TreeChartView/index.d.ts +7 -0
  19. package/dist/core/TreeChartView/index.js +7 -0
  20. package/dist/core/TreeView/TreeNode.svelte +173 -0
  21. package/dist/core/TreeView/TreeNode.svelte.d.ts +10 -0
  22. package/dist/core/TreeView/TreeView.svelte +163 -0
  23. package/dist/core/TreeView/TreeView.svelte.d.ts +10 -0
  24. package/dist/core/TreeView/index.d.ts +48 -0
  25. package/dist/core/TreeView/index.js +50 -0
  26. package/dist/core/TreeView/tree-utils.d.ts +56 -0
  27. package/dist/core/TreeView/tree-utils.js +194 -0
  28. package/dist/core/TreeView/tree.model.d.ts +104 -0
  29. package/dist/core/TreeView/tree.model.js +5 -0
  30. package/dist/core/TreeView/tree.store.d.ts +10 -0
  31. package/dist/core/TreeView/tree.store.js +225 -0
  32. package/dist/core/index.d.ts +2 -0
  33. package/dist/core/index.js +4 -0
  34. package/dist/index.d.ts +1 -0
  35. package/dist/index.js +3 -1
  36. package/package.json +1 -1
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Generate realistic time series data for testing
3
+ */
4
+ function generateTimeSeries(startDate, points, baseValue, variance, intervalMinutes = 15) {
5
+ const data = [];
6
+ const current = new Date(startDate);
7
+ for (let i = 0; i < points; i++) {
8
+ const noise = (Math.random() - 0.5) * variance;
9
+ const trend = Math.sin((i / points) * Math.PI * 2) * (variance / 2); // Sinusoidal pattern
10
+ const value = Math.max(0, baseValue + noise + trend);
11
+ data.push({
12
+ timestamp: current.toISOString(),
13
+ value: Math.round(value * 100) / 100 // Round to 2 decimals
14
+ });
15
+ current.setMinutes(current.getMinutes() + intervalMinutes);
16
+ }
17
+ return data;
18
+ }
19
+ /**
20
+ * Get base throughput value for a frequency band (Mbps)
21
+ */
22
+ function getThroughputBase(band) {
23
+ const baseValues = {
24
+ 700: 30,
25
+ 800: 35,
26
+ 900: 40,
27
+ 1800: 60,
28
+ 2100: 80,
29
+ 2600: 100,
30
+ 3500: 150 // C-Band
31
+ };
32
+ return baseValues[band];
33
+ }
34
+ /**
35
+ * Get base timing advance value for a frequency band (microseconds)
36
+ */
37
+ function getTimingAdvanceBase(band) {
38
+ // Lower frequency = larger cell = higher TA
39
+ const baseValues = {
40
+ 700: 8.5,
41
+ 800: 7.8,
42
+ 900: 7.2,
43
+ 1800: 5.5,
44
+ 2100: 4.8,
45
+ 2600: 4.2,
46
+ 3500: 3.5
47
+ };
48
+ return baseValues[band];
49
+ }
50
+ /**
51
+ * Generate a single cell with KPI data
52
+ */
53
+ function generateCell(siteId, sectorId, band, startDate, points = 96 // 24 hours at 15-min intervals
54
+ ) {
55
+ const cellId = `${siteId}-${sectorId}-${band}`;
56
+ return {
57
+ cellId,
58
+ band,
59
+ kpis: {
60
+ throughput: generateTimeSeries(startDate, points, getThroughputBase(band), getThroughputBase(band) * 0.3, // 30% variance
61
+ 15),
62
+ timingAdvance: generateTimeSeries(startDate, points, getTimingAdvanceBase(band), 1.5, // ±1.5 μs variance
63
+ 15)
64
+ }
65
+ };
66
+ }
67
+ /**
68
+ * Generate mock cellular sites for testing
69
+ */
70
+ export function generateMockCellularData() {
71
+ const startDate = new Date('2025-10-09T00:00:00Z');
72
+ const points = 96; // 24 hours of data
73
+ return [
74
+ // Site A - Urban, 3 sectors, multiple bands
75
+ {
76
+ siteId: 'site-a',
77
+ siteName: 'Site A (Urban)',
78
+ sectors: [
79
+ {
80
+ sectorId: 'sec-1',
81
+ sectorName: 'Sector 1',
82
+ azimuth: 0,
83
+ cells: [
84
+ generateCell('site-a', 'sec-1', 700, startDate, points),
85
+ generateCell('site-a', 'sec-1', 2100, startDate, points),
86
+ generateCell('site-a', 'sec-1', 3500, startDate, points)
87
+ ]
88
+ },
89
+ {
90
+ sectorId: 'sec-2',
91
+ sectorName: 'Sector 2',
92
+ azimuth: 120,
93
+ cells: [
94
+ generateCell('site-a', 'sec-2', 700, startDate, points),
95
+ generateCell('site-a', 'sec-2', 1800, startDate, points),
96
+ generateCell('site-a', 'sec-2', 2100, startDate, points)
97
+ ]
98
+ },
99
+ {
100
+ sectorId: 'sec-3',
101
+ sectorName: 'Sector 3',
102
+ azimuth: 240,
103
+ cells: [
104
+ generateCell('site-a', 'sec-3', 1800, startDate, points),
105
+ generateCell('site-a', 'sec-3', 2600, startDate, points),
106
+ generateCell('site-a', 'sec-3', 3500, startDate, points)
107
+ ]
108
+ }
109
+ ]
110
+ },
111
+ // Site B - Suburban, 2 sectors, fewer bands
112
+ {
113
+ siteId: 'site-b',
114
+ siteName: 'Site B (Suburban)',
115
+ sectors: [
116
+ {
117
+ sectorId: 'sec-1',
118
+ sectorName: 'Sector 1',
119
+ azimuth: 0,
120
+ cells: [
121
+ generateCell('site-b', 'sec-1', 800, startDate, points),
122
+ generateCell('site-b', 'sec-1', 2100, startDate, points)
123
+ ]
124
+ },
125
+ {
126
+ sectorId: 'sec-2',
127
+ sectorName: 'Sector 2',
128
+ azimuth: 180,
129
+ cells: [
130
+ generateCell('site-b', 'sec-2', 800, startDate, points),
131
+ generateCell('site-b', 'sec-2', 1800, startDate, points),
132
+ generateCell('site-b', 'sec-2', 2600, startDate, points)
133
+ ]
134
+ }
135
+ ]
136
+ },
137
+ // Site C - Rural, 4 sectors, low-band focus
138
+ {
139
+ siteId: 'site-c',
140
+ siteName: 'Site C (Rural)',
141
+ sectors: [
142
+ {
143
+ sectorId: 'sec-1',
144
+ sectorName: 'Sector 1',
145
+ azimuth: 0,
146
+ cells: [
147
+ generateCell('site-c', 'sec-1', 700, startDate, points),
148
+ generateCell('site-c', 'sec-1', 900, startDate, points)
149
+ ]
150
+ },
151
+ {
152
+ sectorId: 'sec-2',
153
+ sectorName: 'Sector 2',
154
+ azimuth: 90,
155
+ cells: [
156
+ generateCell('site-c', 'sec-2', 700, startDate, points),
157
+ generateCell('site-c', 'sec-2', 1800, startDate, points)
158
+ ]
159
+ },
160
+ {
161
+ sectorId: 'sec-3',
162
+ sectorName: 'Sector 3',
163
+ azimuth: 180,
164
+ cells: [
165
+ generateCell('site-c', 'sec-3', 800, startDate, points),
166
+ generateCell('site-c', 'sec-3', 900, startDate, points)
167
+ ]
168
+ },
169
+ {
170
+ sectorId: 'sec-4',
171
+ sectorName: 'Sector 4',
172
+ azimuth: 270,
173
+ cells: [
174
+ generateCell('site-c', 'sec-4', 700, startDate, points),
175
+ generateCell('site-c', 'sec-4', 2100, startDate, points)
176
+ ]
177
+ }
178
+ ]
179
+ },
180
+ // Site D - Dense Urban, 3 sectors, high-band focus
181
+ {
182
+ siteId: 'site-d',
183
+ siteName: 'Site D (Dense Urban)',
184
+ sectors: [
185
+ {
186
+ sectorId: 'sec-1',
187
+ sectorName: 'Sector 1',
188
+ azimuth: 0,
189
+ cells: [
190
+ generateCell('site-d', 'sec-1', 2100, startDate, points),
191
+ generateCell('site-d', 'sec-1', 2600, startDate, points),
192
+ generateCell('site-d', 'sec-1', 3500, startDate, points)
193
+ ]
194
+ },
195
+ {
196
+ sectorId: 'sec-2',
197
+ sectorName: 'Sector 2',
198
+ azimuth: 120,
199
+ cells: [
200
+ generateCell('site-d', 'sec-2', 1800, startDate, points),
201
+ generateCell('site-d', 'sec-2', 2600, startDate, points),
202
+ generateCell('site-d', 'sec-2', 3500, startDate, points)
203
+ ]
204
+ },
205
+ {
206
+ sectorId: 'sec-3',
207
+ sectorName: 'Sector 3',
208
+ azimuth: 240,
209
+ cells: [
210
+ generateCell('site-d', 'sec-3', 2100, startDate, points),
211
+ generateCell('site-d', 'sec-3', 2600, startDate, points),
212
+ generateCell('site-d', 'sec-3', 3500, startDate, points)
213
+ ]
214
+ }
215
+ ]
216
+ }
217
+ ];
218
+ }
219
+ /**
220
+ * Get color for frequency band (consistent color scheme)
221
+ */
222
+ export function getBandColor(band) {
223
+ const colors = {
224
+ 700: '#e74c3c', // Red
225
+ 800: '#e67e22', // Orange
226
+ 900: '#f39c12', // Yellow-Orange
227
+ 1800: '#3498db', // Blue
228
+ 2100: '#9b59b6', // Purple
229
+ 2600: '#1abc9c', // Teal
230
+ 3500: '#2ecc71' // Green (C-Band)
231
+ };
232
+ return colors[band];
233
+ }
234
+ /**
235
+ * Get label for frequency band
236
+ */
237
+ export function getBandLabel(band) {
238
+ if (band === 3500)
239
+ return `${band} MHz (C-Band)`;
240
+ return `${band} MHz`;
241
+ }
@@ -0,0 +1,208 @@
1
+ <svelte:options runes={true} />
2
+
3
+ <script lang="ts">
4
+ /**
5
+ * TreeChartView - Generic component combining TreeView with ChartComponent
6
+ *
7
+ * This is a layout component that provides:
8
+ * - Left sidebar with TreeView
9
+ * - Right panel with ChartComponent
10
+ * - Empty state handling
11
+ * - Responsive layout
12
+ *
13
+ * All data transformation logic should be done externally by the consumer.
14
+ */
15
+
16
+ import type { Layout } from '../Charts/charts.model.js';
17
+ import type { TreeStoreValue } from '../TreeView/tree.model.js';
18
+ import ChartComponent from '../Charts/ChartComponent.svelte';
19
+ import { TreeView } from '../TreeView/index.js';
20
+
21
+ interface Props {
22
+ /** Tree store (created externally with createTreeStore) */
23
+ treeStore: TreeStoreValue;
24
+
25
+ /** Chart data array (consumer's responsibility to filter based on tree state) */
26
+ chartData: any[];
27
+
28
+ /** Chart layout configuration */
29
+ chartLayout: Layout;
30
+
31
+ /** Number of total selectable items */
32
+ totalItems: number;
33
+
34
+ /** Number of currently visible items */
35
+ visibleItems: number;
36
+
37
+ /** Chart area title */
38
+ title?: string;
39
+
40
+ /** Chart display mode */
41
+ mode?: 'tabs' | 'scrollspy';
42
+
43
+ /** Show global chart controls */
44
+ showGlobalControls?: boolean;
45
+
46
+ /** Enable chart adaptation */
47
+ enableAdaptation?: boolean;
48
+
49
+ /** Show tree controls (expand/collapse all, etc.) */
50
+ showTreeControls?: boolean;
51
+
52
+ /** Tree sidebar width */
53
+ treeWidth?: string;
54
+
55
+ /** Empty state message */
56
+ emptyMessage?: string;
57
+ }
58
+
59
+ let {
60
+ treeStore,
61
+ chartData,
62
+ chartLayout,
63
+ totalItems,
64
+ visibleItems,
65
+ title = 'Charts',
66
+ mode = 'tabs',
67
+ showGlobalControls = true,
68
+ enableAdaptation = true,
69
+ showTreeControls = true,
70
+ treeWidth = '300px',
71
+ emptyMessage = 'No items selected. Select items from the tree on the left to display charts.'
72
+ }: Props = $props();
73
+ </script>
74
+
75
+ <div class="tree-chart-view">
76
+ <!-- Left: Tree Selector -->
77
+ <aside class="tree-sidebar" style:width={treeWidth}>
78
+ <TreeView
79
+ store={treeStore}
80
+ showControls={showTreeControls}
81
+ height="100%"
82
+ />
83
+ </aside>
84
+
85
+ <!-- Right: Charts Area -->
86
+ <main class="charts-area">
87
+ <div class="charts-header">
88
+ <h5 class="mb-0">{title}</h5>
89
+ <div class="stats">
90
+ <span class="badge bg-primary">
91
+ {visibleItems} of {totalItems} selected
92
+ </span>
93
+ </div>
94
+ </div>
95
+
96
+ <div class="charts-container">
97
+ {#if visibleItems === 0}
98
+ <div class="empty-state">
99
+ <div class="empty-state-content">
100
+ <i class="bi bi-info-circle" style="font-size: 3rem; color: #6c757d;"></i>
101
+ <h4 class="mt-3">No Items Selected</h4>
102
+ <p class="text-muted">
103
+ {emptyMessage}
104
+ </p>
105
+ </div>
106
+ </div>
107
+ {:else}
108
+ <ChartComponent
109
+ layout={chartLayout}
110
+ data={chartData}
111
+ {mode}
112
+ {showGlobalControls}
113
+ {enableAdaptation}
114
+ />
115
+ {/if}
116
+ </div>
117
+ </main>
118
+ </div>
119
+
120
+ <style>
121
+ .tree-chart-view {
122
+ width: 100%;
123
+ height: 100%;
124
+ display: flex;
125
+ gap: 0;
126
+ background-color: #fff;
127
+ }
128
+
129
+ .tree-sidebar {
130
+ flex-shrink: 0;
131
+ height: 100%;
132
+ overflow: hidden;
133
+ border-right: 1px solid #dee2e6;
134
+ }
135
+
136
+ .charts-area {
137
+ flex: 1;
138
+ display: flex;
139
+ flex-direction: column;
140
+ min-width: 0;
141
+ height: 100%;
142
+ }
143
+
144
+ .charts-header {
145
+ padding: 1rem;
146
+ border-bottom: 1px solid #dee2e6;
147
+ background-color: #f8f9fa;
148
+ display: flex;
149
+ justify-content: space-between;
150
+ align-items: center;
151
+ flex-shrink: 0;
152
+ }
153
+
154
+ .charts-header h5 {
155
+ margin: 0;
156
+ color: #495057;
157
+ }
158
+
159
+ .stats {
160
+ display: flex;
161
+ gap: 0.5rem;
162
+ }
163
+
164
+ .charts-container {
165
+ flex: 1;
166
+ min-height: 0;
167
+ overflow: hidden;
168
+ }
169
+
170
+ .empty-state {
171
+ display: flex;
172
+ align-items: center;
173
+ justify-content: center;
174
+ height: 100%;
175
+ width: 100%;
176
+ }
177
+
178
+ .empty-state-content {
179
+ text-align: center;
180
+ max-width: 400px;
181
+ padding: 2rem;
182
+ }
183
+
184
+ .empty-state-content h4 {
185
+ color: #495057;
186
+ margin-bottom: 0.5rem;
187
+ }
188
+
189
+ /* Responsive layout */
190
+ @media (max-width: 992px) {
191
+ .tree-sidebar {
192
+ width: 250px !important;
193
+ }
194
+ }
195
+
196
+ @media (max-width: 768px) {
197
+ .tree-chart-view {
198
+ flex-direction: column;
199
+ }
200
+
201
+ .tree-sidebar {
202
+ width: 100% !important;
203
+ height: 300px;
204
+ border-right: none;
205
+ border-bottom: 1px solid #dee2e6;
206
+ }
207
+ }
208
+ </style>
@@ -0,0 +1,42 @@
1
+ /**
2
+ * TreeChartView - Generic component combining TreeView with ChartComponent
3
+ *
4
+ * This is a layout component that provides:
5
+ * - Left sidebar with TreeView
6
+ * - Right panel with ChartComponent
7
+ * - Empty state handling
8
+ * - Responsive layout
9
+ *
10
+ * All data transformation logic should be done externally by the consumer.
11
+ */
12
+ import type { Layout } from '../Charts/charts.model.js';
13
+ import type { TreeStoreValue } from '../TreeView/tree.model.js';
14
+ interface Props {
15
+ /** Tree store (created externally with createTreeStore) */
16
+ treeStore: TreeStoreValue;
17
+ /** Chart data array (consumer's responsibility to filter based on tree state) */
18
+ chartData: any[];
19
+ /** Chart layout configuration */
20
+ chartLayout: Layout;
21
+ /** Number of total selectable items */
22
+ totalItems: number;
23
+ /** Number of currently visible items */
24
+ visibleItems: number;
25
+ /** Chart area title */
26
+ title?: string;
27
+ /** Chart display mode */
28
+ mode?: 'tabs' | 'scrollspy';
29
+ /** Show global chart controls */
30
+ showGlobalControls?: boolean;
31
+ /** Enable chart adaptation */
32
+ enableAdaptation?: boolean;
33
+ /** Show tree controls (expand/collapse all, etc.) */
34
+ showTreeControls?: boolean;
35
+ /** Tree sidebar width */
36
+ treeWidth?: string;
37
+ /** Empty state message */
38
+ emptyMessage?: string;
39
+ }
40
+ declare const TreeChartView: import("svelte").Component<Props, {}, "">;
41
+ type TreeChartView = ReturnType<typeof TreeChartView>;
42
+ export default TreeChartView;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * TreeChartView - Combined Layout Component
3
+ *
4
+ * Provides a split-screen layout combining TreeView (left) with ChartComponent (right).
5
+ * This is a LAYOUT component - all data transformation is the consumer's responsibility.
6
+ */
7
+ export { default as TreeChartView } from './TreeChartView.svelte';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * TreeChartView - Combined Layout Component
3
+ *
4
+ * Provides a split-screen layout combining TreeView (left) with ChartComponent (right).
5
+ * This is a LAYOUT component - all data transformation is the consumer's responsibility.
6
+ */
7
+ export { default as TreeChartView } from './TreeChartView.svelte';
@@ -0,0 +1,173 @@
1
+ <script lang="ts">
2
+ import type { NodeState, TreeStoreValue } from './tree.model';
3
+ import TreeNode from './TreeNode.svelte';
4
+
5
+ interface Props {
6
+ nodeState: NodeState;
7
+ store: TreeStoreValue;
8
+ showIndeterminate?: boolean;
9
+ }
10
+
11
+ let { nodeState, store, showIndeterminate = true }: Props = $props();
12
+
13
+ // Computed states
14
+ let isChecked = $derived(store.state.checkedPaths.has(nodeState.path));
15
+ let isIndeterminate = $derived(
16
+ showIndeterminate && store.state.indeterminatePaths.has(nodeState.path)
17
+ );
18
+ let isExpanded = $derived(store.state.expandedPaths.has(nodeState.path));
19
+ let hasChildren = $derived(nodeState.childPaths.length > 0);
20
+
21
+ // Get child node states
22
+ let childNodes = $derived(
23
+ nodeState.childPaths
24
+ .map(path => store.state.nodes.get(path))
25
+ .filter((node): node is NodeState => node !== undefined)
26
+ );
27
+
28
+ // Indentation based on level
29
+ let indentStyle = $derived(`padding-left: ${nodeState.level * 1.5}rem`);
30
+
31
+ function handleToggle() {
32
+ store.toggle(nodeState.path);
33
+ }
34
+
35
+ function handleExpandToggle() {
36
+ if (hasChildren) {
37
+ store.toggleExpand(nodeState.path);
38
+ }
39
+ }
40
+ </script>
41
+
42
+ <div class="tree-node" style={indentStyle}>
43
+ <div class="tree-node-content">
44
+ <!-- Expand/Collapse Button -->
45
+ {#if hasChildren}
46
+ <button
47
+ type="button"
48
+ class="btn btn-sm btn-link expand-toggle p-0"
49
+ onclick={handleExpandToggle}
50
+ aria-label={isExpanded ? 'Collapse' : 'Expand'}
51
+ >
52
+ {#if isExpanded}
53
+ <i class="bi bi-chevron-down"></i>
54
+ {:else}
55
+ <i class="bi bi-chevron-right"></i>
56
+ {/if}
57
+ </button>
58
+ {:else}
59
+ <span class="expand-placeholder"></span>
60
+ {/if}
61
+
62
+ <!-- Checkbox -->
63
+ <div class="form-check">
64
+ <input
65
+ type="checkbox"
66
+ class="form-check-input"
67
+ class:indeterminate={isIndeterminate}
68
+ checked={isChecked}
69
+ indeterminate={isIndeterminate}
70
+ onchange={handleToggle}
71
+ id={`checkbox-${nodeState.path}`}
72
+ />
73
+ <label class="form-check-label" for={`checkbox-${nodeState.path}`}>
74
+ {#if nodeState.node.icon}
75
+ <span class="node-icon">{nodeState.node.icon}</span>
76
+ {/if}
77
+ <span class="node-label">{nodeState.node.label}</span>
78
+ </label>
79
+ </div>
80
+ </div>
81
+
82
+ <!-- Recursive Children -->
83
+ {#if hasChildren && isExpanded}
84
+ <div class="tree-node-children">
85
+ {#each childNodes as childNode (childNode.path)}
86
+ <TreeNode nodeState={childNode} {store} {showIndeterminate} />
87
+ {/each}
88
+ </div>
89
+ {/if}
90
+ </div>
91
+
92
+ <style>
93
+ .tree-node {
94
+ position: relative;
95
+ }
96
+
97
+ .tree-node-content {
98
+ display: flex;
99
+ align-items: center;
100
+ gap: 0.5rem;
101
+ padding: 0.25rem 0;
102
+ min-height: 2rem;
103
+ }
104
+
105
+ .expand-toggle {
106
+ width: 1.5rem;
107
+ height: 1.5rem;
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ border: none;
112
+ background: none;
113
+ cursor: pointer;
114
+ color: #6c757d;
115
+ text-decoration: none;
116
+ }
117
+
118
+ .expand-toggle:hover {
119
+ color: #495057;
120
+ background-color: #f8f9fa;
121
+ border-radius: 0.25rem;
122
+ }
123
+
124
+ .expand-toggle:focus {
125
+ outline: 2px solid #0d6efd;
126
+ outline-offset: 2px;
127
+ }
128
+
129
+ .expand-placeholder {
130
+ width: 1.5rem;
131
+ height: 1.5rem;
132
+ display: inline-block;
133
+ }
134
+
135
+ .form-check {
136
+ display: flex;
137
+ align-items: center;
138
+ gap: 0.5rem;
139
+ margin: 0;
140
+ }
141
+
142
+ .form-check-input {
143
+ cursor: pointer;
144
+ margin: 0;
145
+ flex-shrink: 0;
146
+ }
147
+
148
+ /* Indeterminate checkbox styling */
149
+ .form-check-input.indeterminate {
150
+ background-color: #0d6efd;
151
+ border-color: #0d6efd;
152
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e");
153
+ }
154
+
155
+ .form-check-label {
156
+ cursor: pointer;
157
+ display: flex;
158
+ align-items: center;
159
+ gap: 0.5rem;
160
+ margin: 0;
161
+ user-select: none;
162
+ }
163
+
164
+ .node-icon {
165
+ font-size: 1.1rem;
166
+ line-height: 1;
167
+ }
168
+
169
+ .node-label {
170
+ font-size: 0.875rem;
171
+ line-height: 1.5;
172
+ }
173
+ </style>
@@ -0,0 +1,10 @@
1
+ import type { NodeState, TreeStoreValue } from './tree.model';
2
+ import TreeNode from './TreeNode.svelte';
3
+ interface Props {
4
+ nodeState: NodeState;
5
+ store: TreeStoreValue;
6
+ showIndeterminate?: boolean;
7
+ }
8
+ declare const TreeNode: import("svelte").Component<Props, {}, "">;
9
+ type TreeNode = ReturnType<typeof TreeNode>;
10
+ export default TreeNode;