@smartnet360/svelte-components 0.0.16 → 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.
@@ -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';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartnet360/svelte-components",
3
- "version": "0.0.16",
3
+ "version": "0.0.19",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",