@smartnet360/svelte-components 0.0.4 → 0.0.10

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.
@@ -1,26 +1,46 @@
1
1
  <svelte:options runes={true} />
2
2
 
3
3
  <script lang="ts">
4
- import { onMount } from 'svelte';
4
+ import { onMount, createEventDispatcher } from 'svelte';
5
5
  import Plotly from 'plotly.js-dist-min';
6
6
  import type { Chart as ChartModel, ChartMarker } from './charts.model.js';
7
- import { createTimeSeriesTrace, getYAxisTitle } from './data-utils.js';
7
+ import { createTimeSeriesTrace, getYAxisTitle, createDefaultPlotlyLayout } from './data-utils.js';
8
8
  import { adaptPlotlyLayout, addMarkersToLayout, type ContainerSize } from './adapt.js';
9
9
 
10
+ const dispatch = createEventDispatcher<{
11
+ chartcontextmenu: {
12
+ chart: ChartModel;
13
+ sectionId?: string;
14
+ clientX: number;
15
+ clientY: number;
16
+ };
17
+ }>();
18
+
10
19
  interface Props {
11
20
  chart: ChartModel;
12
21
  data: any[];
13
22
  markers?: ChartMarker[]; // Global markers for all charts
14
23
  plotlyLayout?: any; // Optional custom Plotly layout for styling/theming
15
24
  enableAdaptation?: boolean; // Enable size-based adaptations (default: true)
25
+ sectionId?: string;
16
26
  }
17
27
 
18
- let { chart, data, markers, plotlyLayout, enableAdaptation = true }: Props = $props();
28
+ let { chart, data, markers, plotlyLayout, enableAdaptation = true, sectionId }: Props = $props();
19
29
 
20
30
  // Chart container div and state
21
31
  let chartDiv: HTMLElement;
22
32
  let containerSize = $state<ContainerSize>({ width: 0, height: 0 });
23
33
 
34
+ function handleContextMenu(event: MouseEvent) {
35
+ event.preventDefault();
36
+ dispatch('chartcontextmenu', {
37
+ chart,
38
+ sectionId,
39
+ clientX: event.clientX,
40
+ clientY: event.clientY
41
+ });
42
+ }
43
+
24
44
  function renderChart() {
25
45
  if (!chartDiv || !data?.length) return;
26
46
 
@@ -41,63 +61,13 @@
41
61
  colorIndex++;
42
62
  });
43
63
 
44
- // Create default modern layout
45
- const defaultLayout: any = {
46
- title: {
47
- text: chart.title,
48
- font: {
49
- size: 16,
50
- color: '#2c3e50',
51
- weight: 600
52
- },
53
- x: 0.5,
54
- xanchor: 'center'
55
- },
56
- showlegend: true,
57
- legend: {
58
- x: 1,
59
- y: 1,
60
- xanchor: 'right',
61
- yanchor: 'top',
62
- font: {
63
- family: 'Inter, Segoe UI, Tahoma, Geneva, Verdana, sans-serif',
64
- size: 11,
65
- color: '#6B7280'
66
- },
67
- bgcolor: 'rgba(255,255,255,0.9)',
68
- bordercolor: '#6B7280',
69
- borderwidth: 1
70
- },
71
- xaxis: {
72
- showgrid: true,
73
- gridcolor: '#ecf0f1',
74
- linecolor: '#bdc3c7',
75
- tickfont: { size: 11 }
76
- },
77
- yaxis: {
78
- title: {
79
- text: getYAxisTitle(chart.yLeft),
80
- font: { size: 12, color: '#7f8c8d' }
81
- },
82
- showgrid: true,
83
- gridcolor: '#ecf0f1',
84
- linecolor: '#bdc3c7',
85
- tickfont: { size: 11 }
86
- },
87
- margin: { l: 60, r: 60, t: 60, b: 50 },
88
- paper_bgcolor: 'rgba(0,0,0,0)',
89
- plot_bgcolor: 'rgba(0,0,0,0)',
90
- font: { family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif' },
91
- hovermode: 'x unified',
92
- hoverlabel: {
93
- font: {
94
- family: 'Inter, Segoe UI, Tahoma, Geneva, Verdana, sans-serif',
95
- size: 11,
96
- color: '#6B7280'
97
- },
98
- bgcolor: 'rgba(255,255,255,0.9)',
99
- bordercolor: '#6B7280'
100
- }
64
+ // Create default modern layout using the centralized function
65
+ const defaultLayout: any = createDefaultPlotlyLayout(chart.title);
66
+
67
+ // Override specific properties for this chart
68
+ defaultLayout.yaxis.title = {
69
+ text: getYAxisTitle(chart.yLeft),
70
+ font: { size: 12, color: '#7f8c8d' }
101
71
  };
102
72
 
103
73
  // Add second Y-axis if we have right-side KPIs
@@ -187,7 +157,7 @@
187
157
  });
188
158
  </script>
189
159
 
190
- <div class="chart-card">
160
+ <div class="chart-card" role="group" oncontextmenu={handleContextMenu}>
191
161
  <div
192
162
  bind:this={chartDiv}
193
163
  class="chart-container"
@@ -5,7 +5,30 @@ interface Props {
5
5
  markers?: ChartMarker[];
6
6
  plotlyLayout?: any;
7
7
  enableAdaptation?: boolean;
8
+ sectionId?: string;
8
9
  }
9
- declare const ChartCard: import("svelte").Component<Props, {}, "">;
10
- type ChartCard = ReturnType<typeof ChartCard>;
10
+ 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> {
11
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
12
+ $$bindings?: Bindings;
13
+ } & Exports;
14
+ (internal: unknown, props: Props & {
15
+ $$events?: Events;
16
+ $$slots?: Slots;
17
+ }): Exports & {
18
+ $set?: any;
19
+ $on?: any;
20
+ };
21
+ z_$$bindings?: Bindings;
22
+ }
23
+ declare const ChartCard: $$__sveltets_2_IsomorphicComponent<Props, {
24
+ chartcontextmenu: CustomEvent<{
25
+ chart: ChartModel;
26
+ sectionId?: string;
27
+ clientX: number;
28
+ clientY: number;
29
+ }>;
30
+ } & {
31
+ [evt: string]: CustomEvent<any>;
32
+ }, {}, {}, "">;
33
+ type ChartCard = InstanceType<typeof ChartCard>;
11
34
  export default ChartCard;
@@ -1,7 +1,8 @@
1
1
  <svelte:options runes={true} />
2
2
 
3
3
  <script lang="ts">
4
- import type { Layout, Mode, ChartMarker, Section } from './charts.model.js';
4
+ import { onMount } from 'svelte';
5
+ import type { Layout, Mode, ChartMarker, Section, ChartGrid, Chart } from './charts.model.js';
5
6
  import ChartCard from './ChartCard.svelte';
6
7
 
7
8
  interface Props {
@@ -13,25 +14,197 @@
13
14
  enableAdaptation?: boolean; // Enable size-based adaptations
14
15
  }
15
16
 
17
+ const GRID_DIMENSIONS: Record<ChartGrid, { rows: number; columns: number }> = {
18
+ '2x2': { rows: 2, columns: 2 },
19
+ '3x3': { rows: 3, columns: 3 },
20
+ '1x2': { rows: 1, columns: 2 },
21
+ '1x4': { rows: 1, columns: 4 },
22
+ '1x8': { rows: 1, columns: 8 }
23
+ };
24
+
25
+ const DEFAULT_GRID: ChartGrid = '2x2';
26
+
27
+ function getGridConfig(grid: ChartGrid | undefined) {
28
+ const key = grid && GRID_DIMENSIONS[grid] ? grid : DEFAULT_GRID;
29
+ return { key, ...GRID_DIMENSIONS[key] };
30
+ }
31
+
32
+ interface ContextMenuDetail {
33
+ chart: Chart;
34
+ sectionId?: string;
35
+ clientX: number;
36
+ clientY: number;
37
+ }
38
+
39
+ interface ContextMenuState {
40
+ visible: boolean;
41
+ x: number;
42
+ y: number;
43
+ chart: Chart | null;
44
+ section: Section | null;
45
+ }
46
+
47
+ interface ZoomState {
48
+ chart: Chart;
49
+ section: Section;
50
+ }
51
+
16
52
  let { layout, data, mode, markers, plotlyLayout, enableAdaptation = true }: Props = $props();
17
53
 
18
54
  // Internal tab state management
19
55
  let activeTabId = $state(layout.sections[0]?.id || '');
56
+
57
+ let componentElement: HTMLDivElement;
58
+ let contextMenuElement = $state<HTMLDivElement | null>(null);
59
+
60
+ const contextMenu = $state<ContextMenuState>({
61
+ visible: false,
62
+ x: 0,
63
+ y: 0,
64
+ chart: null,
65
+ section: null
66
+ });
67
+
68
+ let zoomedChart = $state<ZoomState | null>(null);
69
+
70
+ const MENU_WIDTH = 168;
71
+ const MENU_HEIGHT = 96;
72
+
73
+ function computeMenuPosition(clientX: number, clientY: number) {
74
+ if (!componentElement) {
75
+ return { x: clientX, y: clientY };
76
+ }
77
+
78
+ const rect = componentElement.getBoundingClientRect();
79
+ let x = clientX - rect.left;
80
+ let y = clientY - rect.top;
81
+
82
+ const maxX = Math.max(0, rect.width - MENU_WIDTH);
83
+ const maxY = Math.max(0, rect.height - MENU_HEIGHT);
84
+
85
+ x = Math.min(Math.max(0, x), maxX);
86
+ y = Math.min(Math.max(0, y), maxY);
87
+
88
+ return { x, y };
89
+ }
90
+
91
+ function closeContextMenu() {
92
+ contextMenu.visible = false;
93
+ contextMenu.chart = null;
94
+ contextMenu.section = null;
95
+ }
96
+
97
+ function handleChartContextMenu(detail: ContextMenuDetail, section: Section) {
98
+ const { x, y } = computeMenuPosition(detail.clientX, detail.clientY);
99
+
100
+ contextMenu.visible = true;
101
+ contextMenu.x = x;
102
+ contextMenu.y = y;
103
+ contextMenu.chart = detail.chart;
104
+ contextMenu.section = section;
105
+ }
106
+
107
+ function zoomSelectedChart() {
108
+ if (contextMenu.chart && contextMenu.section) {
109
+ zoomedChart = { chart: contextMenu.chart, section: contextMenu.section };
110
+ }
111
+ closeContextMenu();
112
+ }
113
+
114
+ function exitZoom() {
115
+ zoomedChart = null;
116
+ closeContextMenu();
117
+ }
118
+
119
+ function handleOverlayKeydown(event: KeyboardEvent) {
120
+ if (event.key === 'Enter' || event.key === ' ') {
121
+ event.preventDefault();
122
+ exitZoom();
123
+ }
124
+ }
125
+
126
+ function handleOverlayClick(event: MouseEvent) {
127
+ if (event.target === event.currentTarget) {
128
+ exitZoom();
129
+ }
130
+ }
131
+
132
+ onMount(() => {
133
+ const handleKeydown = (event: KeyboardEvent) => {
134
+ if (event.key === 'Escape') {
135
+ if (zoomedChart) {
136
+ exitZoom();
137
+ }
138
+ closeContextMenu();
139
+ }
140
+ };
141
+
142
+ const handleGlobalClick = (event: MouseEvent) => {
143
+ if (!contextMenu.visible) return;
144
+ const target = event.target as Node;
145
+ if (contextMenuElement && contextMenuElement.contains(target)) return;
146
+ closeContextMenu();
147
+ };
148
+
149
+ window.addEventListener('keydown', handleKeydown);
150
+ window.addEventListener('click', handleGlobalClick);
151
+
152
+ return () => {
153
+ window.removeEventListener('keydown', handleKeydown);
154
+ window.removeEventListener('click', handleGlobalClick);
155
+ };
156
+ });
20
157
  </script>
21
158
 
22
159
  <!-- Reusable chart grid snippet -->
23
160
  {#snippet chartGrid(section: Section)}
24
- <div class="chart-grid">
161
+ {@const gridConfig = getGridConfig(section.grid)}
162
+ <div
163
+ class="chart-grid"
164
+ data-grid={gridConfig.key}
165
+ style:grid-template-columns={`repeat(${gridConfig.columns}, minmax(0, 1fr))`}
166
+ style:grid-template-rows={`repeat(${gridConfig.rows}, minmax(0, 1fr))`}
167
+ >
25
168
  {#each section.charts as chart}
26
169
  <div class="chart-slot">
27
- <ChartCard {chart} {data} {markers} {plotlyLayout} {enableAdaptation} />
170
+ <ChartCard
171
+ {chart}
172
+ {data}
173
+ {markers}
174
+ {plotlyLayout}
175
+ {enableAdaptation}
176
+ sectionId={section.id}
177
+ on:chartcontextmenu={(event) => handleChartContextMenu(event.detail, section)}
178
+ />
28
179
  </div>
29
180
  {/each}
30
181
  </div>
31
182
  {/snippet}
32
183
 
33
- <div class="chart-component">
34
- {#if mode === 'tabs'}
184
+ <div class="chart-component" bind:this={componentElement}>
185
+ {#if zoomedChart}
186
+ {@const activeZoom = zoomedChart as ZoomState}
187
+ <div
188
+ class="zoom-overlay"
189
+ role="button"
190
+ tabindex="0"
191
+ onclick={handleOverlayClick}
192
+ onkeydown={handleOverlayKeydown}
193
+ >
194
+ <div class="zoom-container">
195
+ <button type="button" class="zoom-close" onclick={exitZoom} aria-label="Exit zoom">×</button>
196
+ <ChartCard
197
+ chart={activeZoom.chart}
198
+ {data}
199
+ {markers}
200
+ {plotlyLayout}
201
+ {enableAdaptation}
202
+ sectionId={activeZoom.section.id}
203
+ on:chartcontextmenu={(event) => handleChartContextMenu(event.detail, activeZoom.section)}
204
+ />
205
+ </div>
206
+ </div>
207
+ {:else if mode === 'tabs'}
35
208
  <!-- Tab Mode with Navigation -->
36
209
  <div class="tabs-container">
37
210
  <!-- Tab Navigation -->
@@ -60,7 +233,7 @@
60
233
  class="tab-section {section.id === activeTabId ? 'active' : 'hidden'}"
61
234
  data-section-id="{section.id}"
62
235
  >
63
- <!-- 2x2 Grid -->
236
+ <!-- Chart Grid -->
64
237
  {@render chartGrid(section)}
65
238
  </div>
66
239
  {/each}
@@ -84,13 +257,33 @@
84
257
  <div class="scrollspy-content">
85
258
  {#each layout.sections as section}
86
259
  <div class="section-content" id="{section.id}">
87
- <!-- 2x2 Grid -->
260
+ <!-- Chart Grid -->
88
261
  {@render chartGrid(section)}
89
262
  </div>
90
263
  {/each}
91
264
  </div>
92
265
  </div>
93
266
  {/if}
267
+
268
+ {#if contextMenu.visible}
269
+ <div
270
+ class="chart-context-menu"
271
+ style:top={`${contextMenu.y}px`}
272
+ style:left={`${contextMenu.x}px`}
273
+ bind:this={contextMenuElement}
274
+ >
275
+ {#if (!zoomedChart || zoomedChart.chart !== contextMenu.chart) && contextMenu.chart && contextMenu.section}
276
+ <button type="button" class="menu-item" onclick={zoomSelectedChart}>
277
+ Zoom to chart
278
+ </button>
279
+ {/if}
280
+ {#if zoomedChart}
281
+ <button type="button" class="menu-item" onclick={exitZoom}>
282
+ Exit zoom
283
+ </button>
284
+ {/if}
285
+ </div>
286
+ {/if}
94
287
  </div>
95
288
 
96
289
  <style>
@@ -100,6 +293,7 @@
100
293
  height: 100%;
101
294
  display: flex;
102
295
  flex-direction: column;
296
+ position: relative;
103
297
  }
104
298
 
105
299
  /* Tab Mode */
@@ -190,16 +384,97 @@
190
384
  margin-bottom: 0.5rem; /* Reduce margin */
191
385
  }
192
386
 
193
- /* 2x2 Chart Grid - responsive to container */
387
+ .chart-context-menu {
388
+ position: absolute;
389
+ display: flex;
390
+ flex-direction: column;
391
+ gap: 0.25rem;
392
+ padding: 0.5rem;
393
+ background: #ffffff;
394
+ border: 1px solid rgba(0, 0, 0, 0.1);
395
+ border-radius: 6px;
396
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
397
+ z-index: 20;
398
+ min-width: 140px;
399
+ }
400
+
401
+ .chart-context-menu .menu-item {
402
+ background: none;
403
+ border: none;
404
+ text-align: left;
405
+ padding: 0.375rem 0.5rem;
406
+ border-radius: 4px;
407
+ font-size: 0.875rem;
408
+ cursor: pointer;
409
+ }
410
+
411
+ .chart-context-menu .menu-item:hover {
412
+ background-color: #f1f3f5;
413
+ }
414
+
415
+ .zoom-overlay {
416
+ position: absolute;
417
+ top: 0;
418
+ left: 0;
419
+ right: 0;
420
+ bottom: 0;
421
+ display: flex;
422
+ align-items: center;
423
+ justify-content: center;
424
+ background: rgba(0, 0, 0, 0.4);
425
+ z-index: 15;
426
+ padding: 1.5rem;
427
+ box-sizing: border-box;
428
+ }
429
+
430
+ .zoom-container {
431
+ position: relative;
432
+ width: 100%;
433
+ height: 100%;
434
+ max-width: 1200px;
435
+ max-height: 100%;
436
+ display: flex;
437
+ flex-direction: column;
438
+ }
439
+
440
+ .zoom-container :global(.chart-card) {
441
+ flex: 1;
442
+ }
443
+
444
+ .zoom-close {
445
+ position: absolute;
446
+ top: 0.5rem;
447
+ right: 0.5rem;
448
+ background: rgba(0, 0, 0, 0.6);
449
+ color: #ffffff;
450
+ border: none;
451
+ width: 2rem;
452
+ height: 2rem;
453
+ border-radius: 50%;
454
+ cursor: pointer;
455
+ font-size: 1.25rem;
456
+ line-height: 1;
457
+ display: flex;
458
+ align-items: center;
459
+ justify-content: center;
460
+ transition: background 0.2s ease;
461
+ z-index: 1;
462
+ }
463
+
464
+ .zoom-close:hover {
465
+ background: rgba(0, 0, 0, 0.75);
466
+ }
467
+
468
+ /* Chart grid adapts to layout configuration */
194
469
  .chart-grid {
195
470
  display: grid;
196
- grid-template-columns: 1fr 1fr;
197
- grid-template-rows: 1fr 1fr;
198
471
  gap: 0.25rem; /* Reduce gap */
199
472
  width: 100%;
200
473
  height: 100%;
201
474
  min-height: 0; /* Remove fixed minimum to allow full flexibility */
202
475
  max-height: 100%; /* Ensure it doesn't exceed container */
476
+ grid-auto-rows: minmax(0, 1fr);
477
+ grid-auto-columns: minmax(0, 1fr);
203
478
  }
204
479
 
205
480
  .chart-slot {
@@ -222,4 +497,4 @@
222
497
  min-height: 80px; /* Even smaller minimum for grid */
223
498
  max-height: 100%; /* Constrain to slot */
224
499
  }
225
- </style>
500
+ </style>
@@ -6,8 +6,10 @@ export interface KPI {
6
6
  unit: string;
7
7
  color?: string;
8
8
  }
9
+ export type ChartPosition = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
10
+ export type ChartGrid = "2x2" | "3x3" | "1x2" | "1x4" | "1x8";
9
11
  export interface Chart {
10
- pos: 1 | 2 | 3 | 4;
12
+ pos?: ChartPosition;
11
13
  title: string;
12
14
  yLeft: KPI[];
13
15
  yRight: KPI[];
@@ -15,7 +17,8 @@ export interface Chart {
15
17
  export interface Section {
16
18
  id: string;
17
19
  title: string;
18
- charts: [Chart, Chart, Chart, Chart];
20
+ charts: Chart[];
21
+ grid?: ChartGrid;
19
22
  }
20
23
  export type Mode = "tabs" | "scrollspy";
21
24
  export interface Layout {
@@ -38,7 +38,7 @@ export function createTimeSeriesTrace(data, kpi, timestampField = 'TIMESTAMP', y
38
38
  smoothing: 0.3,
39
39
  dash: yaxis === 'y1' ? 'solid' : 'dot' // Y1 = solid, Y2 = dotted
40
40
  },
41
- hovertemplate: `<b> ${kpi.name}</b><br>` +
41
+ hovertemplate: `<b>${kpi.name}</b><br>` +
42
42
  `Value: %{y:,.2f} ${kpi.unit}<br>` +
43
43
  '<extra></extra>'
44
44
  };
@@ -91,7 +91,9 @@ export function createDefaultPlotlyLayout(title) {
91
91
  showgrid: true,
92
92
  gridcolor: '#ecf0f1',
93
93
  linecolor: '#bdc3c7',
94
- tickfont: { size: 11 }
94
+ tickfont: { size: 11 },
95
+ tickformat: '%m-%d',
96
+ hoverformat: '%Y-%m-%d'
95
97
  },
96
98
  yaxis: {
97
99
  showgrid: true,
@@ -1,6 +1,6 @@
1
1
  export { default as ChartComponent } from './ChartComponent.svelte';
2
2
  export { default as ChartCard } from './ChartCard.svelte';
3
- export type { Layout, Section, Chart, KPI, Mode, Scale, ChartMarker } from './charts.model.js';
3
+ export type { Layout, Section, Chart, KPI, Mode, Scale, ChartMarker, ChartGrid, ChartPosition } from './charts.model.js';
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';
@@ -4,28 +4,31 @@
4
4
  * Utility functions to help parent applications implement grid launching functionality.
5
5
  * These are optional helpers - parents can implement their own launch logic.
6
6
  */
7
+ const createLaunchKey = () => `grid-viewer-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
8
+ const snapshotComponents = (components) => components.map(({ id, name, icon, description, category }) => ({
9
+ id,
10
+ name,
11
+ icon,
12
+ description,
13
+ category
14
+ }));
15
+ const persistGridConfiguration = (grid, componentConfigs) => {
16
+ const key = createLaunchKey();
17
+ const payload = {
18
+ grid,
19
+ componentConfigs
20
+ };
21
+ localStorage.setItem(key, JSON.stringify(payload));
22
+ return key;
23
+ };
7
24
  /**
8
25
  * Create a launch handler that opens grids in new tabs using localStorage
9
26
  * This recreates the previous built-in behavior as a reusable helper
10
27
  */
11
28
  export function createWindowLauncher(gridViewerUrl, availableComponents) {
29
+ const componentSnapshot = snapshotComponents(availableComponents);
12
30
  return (grid) => {
13
- // Create temporary storage key
14
- const key = `grid-viewer-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
15
- // Store only the grid configuration and component IDs - not the actual components
16
- const data = {
17
- grid,
18
- // Store component configs without the actual component objects
19
- componentConfigs: availableComponents.map(comp => ({
20
- id: comp.id,
21
- name: comp.name,
22
- icon: comp.icon,
23
- description: comp.description,
24
- category: comp.category
25
- }))
26
- };
27
- localStorage.setItem(key, JSON.stringify(data));
28
- // Open new tab with the key parameter
31
+ const key = persistGridConfiguration(grid, componentSnapshot);
29
32
  const url = `${gridViewerUrl}?key=${key}`;
30
33
  const newTab = window.open(url, '_blank');
31
34
  // Focus the new tab if it opened successfully
@@ -49,21 +52,9 @@ export function createTabLauncher(gridViewerUrl, availableComponents) {
49
52
  * Create a launch handler that uses direct URL navigation (same tab)
50
53
  */
51
54
  export function createNavigationLauncher(gridViewerUrl, availableComponents) {
55
+ const componentSnapshot = snapshotComponents(availableComponents);
52
56
  return (grid) => {
53
- // Create temporary storage key
54
- const key = `grid-viewer-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
55
- const data = {
56
- grid,
57
- componentConfigs: availableComponents.map(comp => ({
58
- id: comp.id,
59
- name: comp.name,
60
- icon: comp.icon,
61
- description: comp.description,
62
- category: comp.category
63
- }))
64
- };
65
- localStorage.setItem(key, JSON.stringify(data));
66
- // Navigate to the grid viewer in the same tab
57
+ const key = persistGridConfiguration(grid, componentSnapshot);
67
58
  window.location.href = `${gridViewerUrl}?key=${key}`;
68
59
  };
69
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartnet360/svelte-components",
3
- "version": "0.0.4",
3
+ "version": "0.0.10",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",
@@ -11,9 +11,9 @@
11
11
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
12
12
  "format": "prettier --write .",
13
13
  "lint": "prettier --check . && eslint .",
14
- "release:patch": "npm version patch && npm publish --access public",
15
- "release:minor": "npm version minor && npm publish --access public",
16
- "release:major": "npm version major && npm publish --access public"
14
+ "release:patch": "npm version patch && npm publish --access public --no-browser",
15
+ "release:minor": "npm version minor && npm publish --access public --no-browser",
16
+ "release:major": "npm version major && npm publish --access public --no-browser"
17
17
  },
18
18
  "files": [
19
19
  "dist",
@@ -32,8 +32,8 @@
32
32
  }
33
33
  },
34
34
  "peerDependencies": {
35
- "svelte": "^5.0.0",
36
- "plotly.js-dist-min": "^3.1.0"
35
+ "plotly.js-dist-min": "^3.1.0",
36
+ "svelte": "^5.0.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@eslint/compat": "^1.2.5",