@smartnet360/svelte-components 0.0.17 → 0.0.19
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.
- package/dist/core/Charts/ChartCard.svelte +25 -4
- package/dist/core/Charts/editor/ChartLayoutEditor.svelte +281 -0
- package/dist/core/Charts/editor/ChartLayoutEditor.svelte.d.ts +3 -0
- package/dist/core/Charts/editor/GridPreview.svelte +212 -0
- package/dist/core/Charts/editor/GridPreview.svelte.d.ts +3 -0
- package/dist/core/Charts/editor/KPIPicker.svelte +207 -0
- package/dist/core/Charts/editor/KPIPicker.svelte.d.ts +24 -0
- package/dist/core/Charts/editor/LayoutTreeView.svelte +180 -0
- package/dist/core/Charts/editor/LayoutTreeView.svelte.d.ts +3 -0
- package/dist/core/Charts/editor/PropertiesPanel.svelte +286 -0
- package/dist/core/Charts/editor/PropertiesPanel.svelte.d.ts +20 -0
- package/dist/core/Charts/editor/editorState.d.ts +41 -0
- package/dist/core/Charts/editor/editorState.js +320 -0
- package/dist/core/Charts/index.d.ts +3 -0
- package/dist/core/Charts/index.js +3 -0
- package/package.json +1 -1
@@ -0,0 +1,20 @@
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
3
|
+
$$bindings?: Bindings;
|
4
|
+
} & Exports;
|
5
|
+
(internal: unknown, props: {
|
6
|
+
$$events?: Events;
|
7
|
+
$$slots?: Slots;
|
8
|
+
}): Exports & {
|
9
|
+
$set?: any;
|
10
|
+
$on?: any;
|
11
|
+
};
|
12
|
+
z_$$bindings?: Bindings;
|
13
|
+
}
|
14
|
+
declare const PropertiesPanel: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
15
|
+
openkpipicker: CustomEvent<any>;
|
16
|
+
} & {
|
17
|
+
[evt: string]: CustomEvent<any>;
|
18
|
+
}, {}, {}, "">;
|
19
|
+
type PropertiesPanel = InstanceType<typeof PropertiesPanel>;
|
20
|
+
export default PropertiesPanel;
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import type { Layout, Section, Chart, KPI } from '../charts.model.js';
|
2
|
+
export type SelectionType = 'layout' | 'section' | 'chart' | 'kpi' | null;
|
3
|
+
export interface Selection {
|
4
|
+
type: SelectionType;
|
5
|
+
layoutId?: string;
|
6
|
+
sectionId?: string;
|
7
|
+
chartIndex?: number;
|
8
|
+
kpiSide?: 'yLeft' | 'yRight';
|
9
|
+
kpiIndex?: number;
|
10
|
+
}
|
11
|
+
export interface EditorState {
|
12
|
+
currentLayout: Layout | null;
|
13
|
+
savedLayouts: Layout[];
|
14
|
+
selection: Selection;
|
15
|
+
isDirty: boolean;
|
16
|
+
}
|
17
|
+
export declare const editorStore: {
|
18
|
+
subscribe: (this: void, run: import("svelte/store").Subscriber<EditorState>, invalidate?: () => void) => import("svelte/store").Unsubscriber;
|
19
|
+
newLayout: (name?: string) => void;
|
20
|
+
loadLayout: (layout: Layout) => void;
|
21
|
+
updateLayoutName: (name: string) => void;
|
22
|
+
addSection: () => void;
|
23
|
+
updateSection: (sectionId: string, updates: Partial<Section>) => void;
|
24
|
+
deleteSection: (sectionId: string) => void;
|
25
|
+
addChart: (sectionId: string) => void;
|
26
|
+
updateChart: (sectionId: string, chartIndex: number, updates: Partial<Chart>) => void;
|
27
|
+
deleteChart: (sectionId: string, chartIndex: number) => void;
|
28
|
+
addKPI: (sectionId: string, chartIndex: number, side: "yLeft" | "yRight", kpi: KPI) => void;
|
29
|
+
removeKPI: (sectionId: string, chartIndex: number, side: "yLeft" | "yRight", kpiIndex: number) => void;
|
30
|
+
select: (selection: Selection) => void;
|
31
|
+
saveToLibrary: () => void;
|
32
|
+
deleteFromLibrary: (layoutName: string) => void;
|
33
|
+
exportToJSON: () => string;
|
34
|
+
importFromJSON: (json: string) => boolean;
|
35
|
+
reset: () => void;
|
36
|
+
};
|
37
|
+
export declare const currentLayout: import("svelte/store").Readable<Layout | null>;
|
38
|
+
export declare const savedLayouts: import("svelte/store").Readable<Layout[]>;
|
39
|
+
export declare const selection: import("svelte/store").Readable<Selection>;
|
40
|
+
export declare const isDirty: import("svelte/store").Readable<boolean>;
|
41
|
+
export declare const selectedItem: import("svelte/store").Readable<KPI | Chart | Section | Layout | null | undefined>;
|
@@ -0,0 +1,320 @@
|
|
1
|
+
import { writable, derived, get } from 'svelte/store';
|
2
|
+
const STORAGE_KEY = 'chartLayoutEditor:layouts';
|
3
|
+
const CURRENT_LAYOUT_KEY = 'chartLayoutEditor:currentLayout';
|
4
|
+
// Initialize state from localStorage
|
5
|
+
function loadFromStorage() {
|
6
|
+
if (typeof window === 'undefined') {
|
7
|
+
return {
|
8
|
+
currentLayout: null,
|
9
|
+
savedLayouts: [],
|
10
|
+
selection: { type: null },
|
11
|
+
isDirty: false
|
12
|
+
};
|
13
|
+
}
|
14
|
+
const savedLayoutsJson = localStorage.getItem(STORAGE_KEY);
|
15
|
+
const currentLayoutJson = localStorage.getItem(CURRENT_LAYOUT_KEY);
|
16
|
+
return {
|
17
|
+
currentLayout: currentLayoutJson ? JSON.parse(currentLayoutJson) : null,
|
18
|
+
savedLayouts: savedLayoutsJson ? JSON.parse(savedLayoutsJson) : [],
|
19
|
+
selection: { type: null },
|
20
|
+
isDirty: false
|
21
|
+
};
|
22
|
+
}
|
23
|
+
// Create the main store
|
24
|
+
function createEditorStore() {
|
25
|
+
const { subscribe, set, update } = writable(loadFromStorage());
|
26
|
+
return {
|
27
|
+
subscribe,
|
28
|
+
// Layout operations
|
29
|
+
newLayout: (name = 'New Layout') => {
|
30
|
+
const newLayout = {
|
31
|
+
layoutName: name,
|
32
|
+
sections: []
|
33
|
+
};
|
34
|
+
update(state => ({
|
35
|
+
...state,
|
36
|
+
currentLayout: newLayout,
|
37
|
+
selection: { type: 'layout' },
|
38
|
+
isDirty: true
|
39
|
+
}));
|
40
|
+
},
|
41
|
+
loadLayout: (layout) => {
|
42
|
+
// Use JSON parse/stringify to create a clean copy
|
43
|
+
const cleanLayout = JSON.parse(JSON.stringify(layout));
|
44
|
+
update(state => ({
|
45
|
+
...state,
|
46
|
+
currentLayout: cleanLayout,
|
47
|
+
selection: { type: 'layout' },
|
48
|
+
isDirty: false
|
49
|
+
}));
|
50
|
+
if (typeof window !== 'undefined') {
|
51
|
+
localStorage.setItem(CURRENT_LAYOUT_KEY, JSON.stringify(cleanLayout));
|
52
|
+
}
|
53
|
+
},
|
54
|
+
updateLayoutName: (name) => {
|
55
|
+
update(state => {
|
56
|
+
if (!state.currentLayout)
|
57
|
+
return state;
|
58
|
+
const updated = { ...state.currentLayout, layoutName: name };
|
59
|
+
return { ...state, currentLayout: updated, isDirty: true };
|
60
|
+
});
|
61
|
+
},
|
62
|
+
// Section operations
|
63
|
+
addSection: () => {
|
64
|
+
update(state => {
|
65
|
+
if (!state.currentLayout)
|
66
|
+
return state;
|
67
|
+
const newSection = {
|
68
|
+
id: `section-${Date.now()}`,
|
69
|
+
title: 'New Section',
|
70
|
+
charts: [],
|
71
|
+
grid: '2x2'
|
72
|
+
};
|
73
|
+
const updated = {
|
74
|
+
...state.currentLayout,
|
75
|
+
sections: [...state.currentLayout.sections, newSection]
|
76
|
+
};
|
77
|
+
return {
|
78
|
+
...state,
|
79
|
+
currentLayout: updated,
|
80
|
+
selection: { type: 'section', sectionId: newSection.id },
|
81
|
+
isDirty: true
|
82
|
+
};
|
83
|
+
});
|
84
|
+
},
|
85
|
+
updateSection: (sectionId, updates) => {
|
86
|
+
update(state => {
|
87
|
+
if (!state.currentLayout)
|
88
|
+
return state;
|
89
|
+
const sections = state.currentLayout.sections.map(s => s.id === sectionId ? { ...s, ...updates } : s);
|
90
|
+
return {
|
91
|
+
...state,
|
92
|
+
currentLayout: { ...state.currentLayout, sections },
|
93
|
+
isDirty: true
|
94
|
+
};
|
95
|
+
});
|
96
|
+
},
|
97
|
+
deleteSection: (sectionId) => {
|
98
|
+
update(state => {
|
99
|
+
if (!state.currentLayout)
|
100
|
+
return state;
|
101
|
+
const sections = state.currentLayout.sections.filter(s => s.id !== sectionId);
|
102
|
+
return {
|
103
|
+
...state,
|
104
|
+
currentLayout: { ...state.currentLayout, sections },
|
105
|
+
selection: { type: 'layout' },
|
106
|
+
isDirty: true
|
107
|
+
};
|
108
|
+
});
|
109
|
+
},
|
110
|
+
// Chart operations
|
111
|
+
addChart: (sectionId) => {
|
112
|
+
update(state => {
|
113
|
+
if (!state.currentLayout)
|
114
|
+
return state;
|
115
|
+
const newChart = {
|
116
|
+
title: 'New Chart',
|
117
|
+
yLeft: [],
|
118
|
+
yRight: []
|
119
|
+
};
|
120
|
+
const sections = state.currentLayout.sections.map(section => {
|
121
|
+
if (section.id === sectionId) {
|
122
|
+
return {
|
123
|
+
...section,
|
124
|
+
charts: [...section.charts, newChart]
|
125
|
+
};
|
126
|
+
}
|
127
|
+
return section;
|
128
|
+
});
|
129
|
+
return {
|
130
|
+
...state,
|
131
|
+
currentLayout: { ...state.currentLayout, sections },
|
132
|
+
isDirty: true
|
133
|
+
};
|
134
|
+
});
|
135
|
+
},
|
136
|
+
updateChart: (sectionId, chartIndex, updates) => {
|
137
|
+
update(state => {
|
138
|
+
if (!state.currentLayout)
|
139
|
+
return state;
|
140
|
+
const sections = state.currentLayout.sections.map(section => {
|
141
|
+
if (section.id === sectionId) {
|
142
|
+
const charts = section.charts.map((chart, idx) => idx === chartIndex ? { ...chart, ...updates } : chart);
|
143
|
+
return { ...section, charts };
|
144
|
+
}
|
145
|
+
return section;
|
146
|
+
});
|
147
|
+
return {
|
148
|
+
...state,
|
149
|
+
currentLayout: { ...state.currentLayout, sections },
|
150
|
+
isDirty: true
|
151
|
+
};
|
152
|
+
});
|
153
|
+
},
|
154
|
+
deleteChart: (sectionId, chartIndex) => {
|
155
|
+
update(state => {
|
156
|
+
if (!state.currentLayout)
|
157
|
+
return state;
|
158
|
+
const sections = state.currentLayout.sections.map(section => {
|
159
|
+
if (section.id === sectionId) {
|
160
|
+
const charts = section.charts.filter((_, idx) => idx !== chartIndex);
|
161
|
+
return { ...section, charts };
|
162
|
+
}
|
163
|
+
return section;
|
164
|
+
});
|
165
|
+
return {
|
166
|
+
...state,
|
167
|
+
currentLayout: { ...state.currentLayout, sections },
|
168
|
+
selection: { type: 'section', sectionId },
|
169
|
+
isDirty: true
|
170
|
+
};
|
171
|
+
});
|
172
|
+
},
|
173
|
+
// KPI operations
|
174
|
+
addKPI: (sectionId, chartIndex, side, kpi) => {
|
175
|
+
update(state => {
|
176
|
+
if (!state.currentLayout)
|
177
|
+
return state;
|
178
|
+
const sections = state.currentLayout.sections.map(section => {
|
179
|
+
if (section.id === sectionId) {
|
180
|
+
const charts = section.charts.map((chart, idx) => {
|
181
|
+
if (idx === chartIndex) {
|
182
|
+
return {
|
183
|
+
...chart,
|
184
|
+
[side]: [...chart[side], kpi]
|
185
|
+
};
|
186
|
+
}
|
187
|
+
return chart;
|
188
|
+
});
|
189
|
+
return { ...section, charts };
|
190
|
+
}
|
191
|
+
return section;
|
192
|
+
});
|
193
|
+
return {
|
194
|
+
...state,
|
195
|
+
currentLayout: { ...state.currentLayout, sections },
|
196
|
+
isDirty: true
|
197
|
+
};
|
198
|
+
});
|
199
|
+
},
|
200
|
+
removeKPI: (sectionId, chartIndex, side, kpiIndex) => {
|
201
|
+
update(state => {
|
202
|
+
if (!state.currentLayout)
|
203
|
+
return state;
|
204
|
+
const sections = state.currentLayout.sections.map(section => {
|
205
|
+
if (section.id === sectionId) {
|
206
|
+
const charts = section.charts.map((chart, idx) => {
|
207
|
+
if (idx === chartIndex) {
|
208
|
+
return {
|
209
|
+
...chart,
|
210
|
+
[side]: chart[side].filter((_, i) => i !== kpiIndex)
|
211
|
+
};
|
212
|
+
}
|
213
|
+
return chart;
|
214
|
+
});
|
215
|
+
return { ...section, charts };
|
216
|
+
}
|
217
|
+
return section;
|
218
|
+
});
|
219
|
+
return {
|
220
|
+
...state,
|
221
|
+
currentLayout: { ...state.currentLayout, sections },
|
222
|
+
isDirty: true
|
223
|
+
};
|
224
|
+
});
|
225
|
+
},
|
226
|
+
// Selection management
|
227
|
+
select: (selection) => {
|
228
|
+
update(state => ({ ...state, selection }));
|
229
|
+
},
|
230
|
+
// Save/Load operations
|
231
|
+
saveToLibrary: () => {
|
232
|
+
update(state => {
|
233
|
+
if (!state.currentLayout)
|
234
|
+
return state;
|
235
|
+
// Serialize and deserialize to create a clean copy without component references
|
236
|
+
const cleanLayout = JSON.parse(JSON.stringify(state.currentLayout));
|
237
|
+
// Check if layout already exists and update it
|
238
|
+
const existingIndex = state.savedLayouts.findIndex(l => l.layoutName === cleanLayout.layoutName);
|
239
|
+
let savedLayouts;
|
240
|
+
if (existingIndex >= 0) {
|
241
|
+
savedLayouts = state.savedLayouts.map((l, idx) => idx === existingIndex ? cleanLayout : l);
|
242
|
+
}
|
243
|
+
else {
|
244
|
+
savedLayouts = [...state.savedLayouts, cleanLayout];
|
245
|
+
}
|
246
|
+
// Save to localStorage
|
247
|
+
if (typeof window !== 'undefined') {
|
248
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(savedLayouts));
|
249
|
+
localStorage.setItem(CURRENT_LAYOUT_KEY, JSON.stringify(state.currentLayout));
|
250
|
+
}
|
251
|
+
return { ...state, savedLayouts, isDirty: false };
|
252
|
+
});
|
253
|
+
},
|
254
|
+
deleteFromLibrary: (layoutName) => {
|
255
|
+
update(state => {
|
256
|
+
const savedLayouts = state.savedLayouts.filter(l => l.layoutName !== layoutName);
|
257
|
+
if (typeof window !== 'undefined') {
|
258
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(savedLayouts));
|
259
|
+
}
|
260
|
+
return { ...state, savedLayouts };
|
261
|
+
});
|
262
|
+
},
|
263
|
+
// Export/Import
|
264
|
+
exportToJSON: () => {
|
265
|
+
const state = get(editorStore);
|
266
|
+
if (!state.currentLayout)
|
267
|
+
return '';
|
268
|
+
return JSON.stringify(state.currentLayout, null, 2);
|
269
|
+
},
|
270
|
+
importFromJSON: (json) => {
|
271
|
+
try {
|
272
|
+
const layout = JSON.parse(json);
|
273
|
+
update(state => ({
|
274
|
+
...state,
|
275
|
+
currentLayout: layout,
|
276
|
+
selection: { type: 'layout' },
|
277
|
+
isDirty: true
|
278
|
+
}));
|
279
|
+
return true;
|
280
|
+
}
|
281
|
+
catch (error) {
|
282
|
+
console.error('Failed to import layout:', error);
|
283
|
+
return false;
|
284
|
+
}
|
285
|
+
},
|
286
|
+
// Reset
|
287
|
+
reset: () => {
|
288
|
+
set(loadFromStorage());
|
289
|
+
}
|
290
|
+
};
|
291
|
+
}
|
292
|
+
export const editorStore = createEditorStore();
|
293
|
+
// Derived stores for convenience
|
294
|
+
export const currentLayout = derived(editorStore, $state => $state.currentLayout);
|
295
|
+
export const savedLayouts = derived(editorStore, $state => $state.savedLayouts);
|
296
|
+
export const selection = derived(editorStore, $state => $state.selection);
|
297
|
+
export const isDirty = derived(editorStore, $state => $state.isDirty);
|
298
|
+
// Helper to get selected item
|
299
|
+
export const selectedItem = derived(editorStore, $state => {
|
300
|
+
if (!$state.currentLayout || !$state.selection.type)
|
301
|
+
return null;
|
302
|
+
switch ($state.selection.type) {
|
303
|
+
case 'layout':
|
304
|
+
return $state.currentLayout;
|
305
|
+
case 'section':
|
306
|
+
return $state.currentLayout.sections.find(s => s.id === $state.selection.sectionId);
|
307
|
+
case 'chart': {
|
308
|
+
const section = $state.currentLayout.sections.find(s => s.id === $state.selection.sectionId);
|
309
|
+
return section?.charts[$state.selection.chartIndex];
|
310
|
+
}
|
311
|
+
case 'kpi': {
|
312
|
+
const section = $state.currentLayout.sections.find(s => s.id === $state.selection.sectionId);
|
313
|
+
const chart = section?.charts[$state.selection.chartIndex];
|
314
|
+
const side = $state.selection.kpiSide;
|
315
|
+
return chart?.[side][$state.selection.kpiIndex];
|
316
|
+
}
|
317
|
+
default:
|
318
|
+
return null;
|
319
|
+
}
|
320
|
+
});
|
@@ -4,3 +4,6 @@ export type { Layout, Section, Chart, KPI, Mode, Scale, ChartMarker, ChartGrid,
|
|
4
4
|
export { createTimeSeriesTrace, getYAxisTitle, formatValue, processKPIData, createDefaultPlotlyLayout } from './data-utils.js';
|
5
5
|
export { adaptPlotlyLayout, getSizeCategory, createMarkerShapes, createMarkerAnnotations, addMarkersToLayout } from './adapt.js';
|
6
6
|
export type { ContainerSize, ChartInfo, AdaptationConfig } from './adapt.js';
|
7
|
+
export { default as ChartLayoutEditor } from './editor/ChartLayoutEditor.svelte';
|
8
|
+
export { editorStore, currentLayout, savedLayouts, selection, isDirty, selectedItem } from './editor/editorState.js';
|
9
|
+
export type { Selection, SelectionType, EditorState } from './editor/editorState.js';
|
@@ -2,3 +2,6 @@ export { default as ChartComponent } from './ChartComponent.svelte';
|
|
2
2
|
export { default as ChartCard } from './ChartCard.svelte';
|
3
3
|
export { createTimeSeriesTrace, getYAxisTitle, formatValue, processKPIData, createDefaultPlotlyLayout } from './data-utils.js';
|
4
4
|
export { adaptPlotlyLayout, getSizeCategory, createMarkerShapes, createMarkerAnnotations, addMarkersToLayout } from './adapt.js';
|
5
|
+
// Editor exports
|
6
|
+
export { default as ChartLayoutEditor } from './editor/ChartLayoutEditor.svelte';
|
7
|
+
export { editorStore, currentLayout, savedLayouts, selection, isDirty, selectedItem } from './editor/editorState.js';
|