@tellegen/svelte 0.3.0 → 0.4.0

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 (67) hide show
  1. package/README.md +233 -0
  2. package/dist/Sparkline.svelte +2 -2
  3. package/dist/TellegenMap.svelte +201 -47
  4. package/dist/TellegenMap.svelte.d.ts +45 -0
  5. package/dist/TellegenProvider.svelte +36 -4
  6. package/dist/TellegenShell.svelte +14 -42
  7. package/dist/TellegenViewer.svelte +12 -2
  8. package/dist/api.d.ts +10 -2
  9. package/dist/api.js +2 -0
  10. package/dist/basemap.d.ts +192 -0
  11. package/dist/basemap.js +259 -0
  12. package/dist/colors.d.ts +18 -0
  13. package/dist/colors.js +26 -0
  14. package/dist/components/AppFooter.svelte +3 -2
  15. package/dist/components/AppHeader.svelte +21 -8
  16. package/dist/components/BindingLines.svelte +1 -1
  17. package/dist/components/BusPicker.svelte +3 -3
  18. package/dist/components/DemandSlider.svelte +16 -7
  19. package/dist/components/DiagramCanvas.svelte +1 -1
  20. package/dist/components/DisplayControls.svelte +5 -1
  21. package/dist/components/DropZone.svelte +1 -1
  22. package/dist/components/FormulationSelector.svelte +1 -1
  23. package/dist/components/LocalCaseDetails.svelte +6 -3
  24. package/dist/components/McResults.svelte +98 -35
  25. package/dist/components/McResults.svelte.d.ts +8 -2
  26. package/dist/components/ModelDetails.svelte +5 -5
  27. package/dist/components/MulticonductorDetails.svelte +9 -9
  28. package/dist/components/NotificationCenter.svelte +4 -2
  29. package/dist/components/PanelCard.svelte +72 -7
  30. package/dist/components/PanelHost.svelte +59 -34
  31. package/dist/components/PanelHost.svelte.d.ts +4 -1
  32. package/dist/components/PlacementCue.svelte +1 -1
  33. package/dist/components/PowerFlowDetails.svelte +1 -1
  34. package/dist/components/RatingSlider.svelte +14 -5
  35. package/dist/components/RestoreDefaultsButton.svelte +1 -1
  36. package/dist/components/SavedNetworkDetails.svelte +3 -3
  37. package/dist/components/SensitivityReadout.svelte +2 -2
  38. package/dist/components/ShellEnvironment.svelte +51 -0
  39. package/dist/components/ShellEnvironment.svelte.d.ts +18 -0
  40. package/dist/components/SizeLegend.svelte +2 -2
  41. package/dist/components/SolveCard.svelte +3 -3
  42. package/dist/components/TopMovers.svelte +1 -1
  43. package/dist/components.d.ts +3 -0
  44. package/dist/components.js +3 -0
  45. package/dist/context.svelte.d.ts +8 -1
  46. package/dist/context.svelte.js +8 -3
  47. package/dist/controller.svelte.d.ts +65 -5
  48. package/dist/controller.svelte.js +262 -76
  49. package/dist/format.d.ts +9 -0
  50. package/dist/format.js +12 -0
  51. package/dist/index.d.ts +5 -1
  52. package/dist/index.js +2 -0
  53. package/dist/map.d.ts +4 -2
  54. package/dist/map.js +2 -1
  55. package/dist/maplibre-worker.d.ts +5 -0
  56. package/dist/maplibre-worker.dev.d.ts +11 -0
  57. package/dist/maplibre-worker.dev.js +15 -0
  58. package/dist/maplibre-worker.js +8 -0
  59. package/dist/notices.svelte.js +5 -1
  60. package/dist/panels.svelte.d.ts +6 -0
  61. package/dist/panels.svelte.js +31 -1
  62. package/dist/slider.d.ts +12 -0
  63. package/dist/slider.js +31 -0
  64. package/dist/state.svelte.d.ts +19 -2
  65. package/dist/state.svelte.js +12 -0
  66. package/dist/styles.css +59 -6
  67. package/package.json +13 -8
package/dist/map.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import TellegenMap from './TellegenMap.svelte';
2
2
  export { default as TellegenMap } from './TellegenMap.svelte';
3
- export { branchColor, branchWidth, busNeutral, busRadius, priceColor, priceDomain, priceGradient, scalarDomain, sensColor, sensFlatColor, sensGradient, sensNeutral, sensitivityDomain } from './colors.js';
3
+ export { CARTO_STYLES, OPENFREEMAP_STYLES, attachBasemapFallback, cartoStyleUrl, defaultBasemap, isOpenFreeMapStyle, openFreeMapEdits, resolveBasemap } from './basemap.js';
4
+ export { MAP_PALETTE, branchColor, branchWidth, busNeutral, busRadius, priceColor, priceDomain, priceGradient, scalarDomain, sensColor, sensFlatColor, sensGradient, sensNeutral, sensitivityDomain } from './colors.js';
4
5
  export { caseDeltas, displayMetaFor, displaySeriesFor } from './display.js';
@@ -0,0 +1,5 @@
1
+ /** The URL of MapLibre's worker, which the host's Vite build bundles with its
2
+ * shared chunk. `TellegenMap` hands it to `setWorkerUrl` before it creates a
3
+ * map. Reached through the `@tellegen/svelte/maplibre-worker` export; see
4
+ * `maplibre-worker.dev.ts` for the dev server. */
5
+ export declare function maplibreWorkerUrl(): Promise<string>;
@@ -0,0 +1,11 @@
1
+ /** The dev server's `@tellegen/svelte/maplibre-worker`, chosen by the
2
+ * `development` export condition.
3
+ *
4
+ * Vite's dev server pre-bundles this package with Rolldown, which cannot load
5
+ * the `?worker&url` import in `maplibre-worker.ts`, so a static import of that
6
+ * module would stop the dev server at startup. Here it is imported at run time
7
+ * by URL instead, outside the pre-bundle, and the dev server resolves the
8
+ * query itself. Vite rewrites the `new URL` in a pre-bundled file to point at
9
+ * the original. A production build takes the default condition and imports
10
+ * `maplibre-worker.ts` directly. */
11
+ export declare function maplibreWorkerUrl(): Promise<string>;
@@ -0,0 +1,15 @@
1
+ /** The dev server's `@tellegen/svelte/maplibre-worker`, chosen by the
2
+ * `development` export condition.
3
+ *
4
+ * Vite's dev server pre-bundles this package with Rolldown, which cannot load
5
+ * the `?worker&url` import in `maplibre-worker.ts`, so a static import of that
6
+ * module would stop the dev server at startup. Here it is imported at run time
7
+ * by URL instead, outside the pre-bundle, and the dev server resolves the
8
+ * query itself. Vite rewrites the `new URL` in a pre-bundled file to point at
9
+ * the original. A production build takes the default condition and imports
10
+ * `maplibre-worker.ts` directly. */
11
+ export async function maplibreWorkerUrl() {
12
+ const url = new URL('./maplibre-worker.js', import.meta.url).href;
13
+ const module = await import(/* @vite-ignore */ url);
14
+ return module.maplibreWorkerUrl();
15
+ }
@@ -0,0 +1,8 @@
1
+ import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
2
+ /** The URL of MapLibre's worker, which the host's Vite build bundles with its
3
+ * shared chunk. `TellegenMap` hands it to `setWorkerUrl` before it creates a
4
+ * map. Reached through the `@tellegen/svelte/maplibre-worker` export; see
5
+ * `maplibre-worker.dev.ts` for the dev server. */
6
+ export async function maplibreWorkerUrl() {
7
+ return workerUrl;
8
+ }
@@ -70,11 +70,15 @@ export function getNoticeCenter() {
70
70
  export function errorNoticeTitle(details) {
71
71
  if (/rate limit/i.test(details))
72
72
  return 'Too many requests';
73
+ // MapLibre's WebGL failure includes "Read more"; classify our map errors
74
+ // before the generic file/read fallback so it does not blame a case file.
75
+ if (/^map failed to load:|^the map lost its graphics context/i.test(details))
76
+ return 'Map unavailable';
73
77
  if (/storage|quota|space|indexeddb/i.test(details))
74
78
  return 'Could not save locally';
75
79
  if (/sensitivity|derivative|singular/i.test(details))
76
80
  return 'Sensitivity unavailable';
77
- if (/infeasib|converg|solver|solving|calculation|compute|webassembly/i.test(details))
81
+ if (/infeasib|converg|solver|solving|calculation|compute|webassembly|power flow/i.test(details))
78
82
  return 'Calculation did not complete';
79
83
  if (/parse|read|file|format/i.test(details))
80
84
  return 'Could not read this file';
@@ -49,6 +49,9 @@ export declare class PanelLayout {
49
49
  position(panel: PanelRegistration): PanelPosition;
50
50
  ordered(side?: PanelSide): PanelRegistration[];
51
51
  toggle(panel: PanelRegistration): void;
52
+ /** The control that had focus when the panel last opened, while it is still
53
+ * in the document: where focus returns when the panel closes. */
54
+ opener(panel: PanelRegistration): HTMLElement | SVGElement | null;
52
55
  close(panel: PanelRegistration): void;
53
56
  dock(panel: PanelRegistration, side?: PanelSide): void;
54
57
  float(panel: PanelRegistration, bounds?: PanelBounds): void;
@@ -60,6 +63,9 @@ export declare class PanelLayout {
60
63
  initialize(storage?: Storage): void;
61
64
  save(): void;
62
65
  }
66
+ /** Focus the first candidate that takes focus. A detached or hidden element
67
+ * does not, so the next one gets its turn. */
68
+ export declare function focusFirst(candidates: Array<HTMLElement | SVGElement | null | undefined>): HTMLElement | SVGElement | null;
63
69
  export declare const setPanelLayout: (layout: PanelLayout) => PanelLayout;
64
70
  export declare const getPanelLayout: () => PanelLayout;
65
71
  export {};
@@ -18,6 +18,7 @@ export class PanelLayout {
18
18
  bottom = $state(88);
19
19
  storageError = $state(null);
20
20
  #storage;
21
+ #openers = new Map();
21
22
  #gesture = null;
22
23
  beginGesture(panel, kind, x, y, bounds) {
23
24
  this.#gesture = { panel, kind, x, y, bounds, moved: false };
@@ -60,6 +61,7 @@ export class PanelLayout {
60
61
  return;
61
62
  this.panels = this.panels.map((p) => (p.id === id ? { ...p, open, title, width } : p));
62
63
  if (open && !previous.open) {
64
+ this.#rememberOpener(id);
63
65
  this.activate(previous);
64
66
  if (this.compact)
65
67
  this.drawer = id;
@@ -91,19 +93,35 @@ export class PanelLayout {
91
93
  if (this.compact) {
92
94
  this.drawer = this.drawer === panel.id ? null : panel.id;
93
95
  if (this.drawer === panel.id) {
96
+ this.#rememberOpener(panel.id);
94
97
  this.activate(panel);
95
98
  panel.setOpen(true);
96
99
  panel.onopen?.();
97
100
  }
98
101
  }
99
102
  else {
100
- if (!panel.open)
103
+ if (!panel.open) {
104
+ this.#rememberOpener(panel.id);
101
105
  this.activate(panel);
106
+ }
102
107
  panel.setOpen(!panel.open);
103
108
  if (!panel.open)
104
109
  panel.onopen?.();
105
110
  }
106
111
  }
112
+ /** The control that had focus when the panel last opened, while it is still
113
+ * in the document: where focus returns when the panel closes. */
114
+ opener(panel) {
115
+ const element = this.#openers.get(panel.id);
116
+ return element?.isConnected ? element : null;
117
+ }
118
+ #rememberOpener(id) {
119
+ const active = typeof document === 'undefined' ? null : document.activeElement;
120
+ if ((active instanceof HTMLElement || active instanceof SVGElement) && active !== document.body)
121
+ this.#openers.set(id, active);
122
+ else
123
+ this.#openers.delete(id);
124
+ }
107
125
  close(panel) {
108
126
  panel.setOpen(false);
109
127
  if (this.drawer === panel.id)
@@ -206,6 +224,18 @@ export class PanelLayout {
206
224
  }
207
225
  }
208
226
  }
227
+ /** Focus the first candidate that takes focus. A detached or hidden element
228
+ * does not, so the next one gets its turn. */
229
+ export function focusFirst(candidates) {
230
+ for (const candidate of candidates) {
231
+ if (!candidate?.isConnected)
232
+ continue;
233
+ candidate.focus();
234
+ if (candidate.ownerDocument.activeElement === candidate)
235
+ return candidate;
236
+ }
237
+ return null;
238
+ }
209
239
  export const setPanelLayout = (layout) => setContext(KEY, layout);
210
240
  export const getPanelLayout = () => {
211
241
  const layout = getContext(KEY);
@@ -0,0 +1,12 @@
1
+ /** Smallest demand or rating edit that counts: a slider released closer than
2
+ * this to the committed value commits nothing and starts no solve. */
3
+ export declare const DEAD_ZONE_MW = 0.25;
4
+ /** Arrow-key step of a demand or rating slider spanning `span` MW: about 1%
5
+ * of the span, rounded up to 1, 2 or 5 times a power of ten. It is at least
6
+ * twice the dead zone, so one press always leaves it, rounding error
7
+ * included. The native step of a `step="any"` range is 1% of the span, which
8
+ * on a small bus never leaves the dead zone. */
9
+ export declare function sliderKeyStep(span: number): number;
10
+ /** The value an arrow key moves a slider to, kept within [min, max], or null
11
+ * for any other key. Right and up raise it. */
12
+ export declare function sliderKeyValue(key: string, value: number, min: number, max: number): number | null;
package/dist/slider.js ADDED
@@ -0,0 +1,31 @@
1
+ /** Smallest demand or rating edit that counts: a slider released closer than
2
+ * this to the committed value commits nothing and starts no solve. */
3
+ export const DEAD_ZONE_MW = 0.25;
4
+ const KEY_DIRECTIONS = {
5
+ ArrowRight: 1,
6
+ ArrowUp: 1,
7
+ ArrowLeft: -1,
8
+ ArrowDown: -1
9
+ };
10
+ /** Arrow-key step of a demand or rating slider spanning `span` MW: about 1%
11
+ * of the span, rounded up to 1, 2 or 5 times a power of ten. It is at least
12
+ * twice the dead zone, so one press always leaves it, rounding error
13
+ * included. The native step of a `step="any"` range is 1% of the span, which
14
+ * on a small bus never leaves the dead zone. */
15
+ export function sliderKeyStep(span) {
16
+ const target = Math.max(span / 100, 2 * DEAD_ZONE_MW);
17
+ const power = 10 ** Math.floor(Math.log10(target));
18
+ for (const factor of [1, 2, 5]) {
19
+ if (factor * power >= target)
20
+ return factor * power;
21
+ }
22
+ return 10 * power;
23
+ }
24
+ /** The value an arrow key moves a slider to, kept within [min, max], or null
25
+ * for any other key. Right and up raise it. */
26
+ export function sliderKeyValue(key, value, min, max) {
27
+ const direction = KEY_DIRECTIONS[key];
28
+ if (direction === undefined)
29
+ return null;
30
+ return Math.min(max, Math.max(min, value + direction * sliderKeyStep(max - min)));
31
+ }
@@ -1,5 +1,5 @@
1
1
  import type { CaseSummary, DemandDeltas, Network, NetworkBranch, NetworkBus, SensitivityColumn, Solution, SolveIteration } from './api.js';
2
- import { type StudyView, type BranchRatingDeltas, type BrowserMcPfSession, type CaseFileSummary, type DistGraph, type Formulation, type IngestedDistCase, type McPfResult, type McLoadBranchState, type McLoadPowerEdit, type McStudySnapshot, type SensTarget, type Topology } from '@tellegen/engine';
2
+ import { type StudyView, type BranchRatingDeltas, type BrowserMcPfSession, type CaseFileSummary, type DistGraph, type Formulation, type IngestedDistCase, type McPfCallTiming, type McPfResult, type McPfSummary, type McLoadBranchState, type McLoadPowerEdit, type McStudySnapshot, type SensTarget, type Topology } from '@tellegen/engine';
3
3
  import type { MultiView } from './multiconductor.js';
4
4
  export type SolveBackend = 'clarabel-wasm' | 'clarabel-wasm-server-sensitivity' | 'rust-server';
5
5
  /** A map framing request: a case id, 'all', or one branch to center. */
@@ -174,6 +174,12 @@ export type SolvableCase = CaseState | LocalCase;
174
174
  export type MultiCaseSummary = Omit<IngestedDistCase, 'graph'>;
175
175
  /** Geographic coordinates use the map; other positions use the diagram canvas. */
176
176
  export type MultiCoordsKind = 'geographic' | 'planar' | 'synthetic';
177
+ /** Where one interactive load edit spent its time, in milliseconds: engine
178
+ * (solve and summary), transfer, and parsing as recorded by the session, and
179
+ * the total from the start of the solve until the result state is updated. */
180
+ export interface McEditTiming extends McPfCallTiming {
181
+ total_ms: number;
182
+ }
177
183
  /** A conductor-resolved case with retained electrical inputs and terminal results. */
178
184
  export declare class MulticonductorCase {
179
185
  readonly id: string;
@@ -182,7 +188,14 @@ export declare class MulticonductorCase {
182
188
  moduleJson: string | null;
183
189
  geoLayer: string | null;
184
190
  geoWarnings: string[];
185
- result: McPfResult | null;
191
+ /** Summary of the displayed operating point: from the live session after
192
+ * each solve or load edit, or derived from a stored full result. */
193
+ result: McPfSummary | null;
194
+ /** The complete result when no live session holds the operating point: a
195
+ * saved Study, a solve without sessions, or after coordinates are attached. */
196
+ mcFullResult: McPfResult | null;
197
+ /** Latency breakdown of the latest load-edit solve. */
198
+ mcTiming: McEditTiming | null;
186
199
  mcSnapshot: McStudySnapshot | null;
187
200
  mcSession: BrowserMcPfSession | null;
188
201
  mcLoadBranches: McLoadBranchState[];
@@ -285,6 +298,10 @@ export declare class AppState {
285
298
  /** Re-runs the operation behind the current `error`, when one applies. Every
286
299
  * write to `error` clears it, so a retry op can never outlive its message. */
287
300
  errorRetry: (() => void) | null;
301
+ /** Technical detail behind the current `error`, when the message itself is
302
+ * written for people; notices keep it in their disclosure. Every write to
303
+ * `error` clears it, as it clears `errorRetry`. */
304
+ errorDetail: string | null;
288
305
  get error(): string | null;
289
306
  set error(message: string | null);
290
307
  /** Case files parsed in the browser via the powerio wasm module. */
@@ -122,7 +122,14 @@ export class MulticonductorCase {
122
122
  moduleJson = $state.raw(null);
123
123
  geoLayer = $state.raw(null);
124
124
  geoWarnings = $state.raw([]);
125
+ /** Summary of the displayed operating point: from the live session after
126
+ * each solve or load edit, or derived from a stored full result. */
125
127
  result = $state.raw(null);
128
+ /** The complete result when no live session holds the operating point: a
129
+ * saved Study, a solve without sessions, or after coordinates are attached. */
130
+ mcFullResult = $state.raw(null);
131
+ /** Latency breakdown of the latest load-edit solve. */
132
+ mcTiming = $state.raw(null);
126
133
  mcSnapshot = $state.raw(null);
127
134
  mcSession = $state.raw(null);
128
135
  mcLoadBranches = $state.raw([]);
@@ -251,6 +258,10 @@ export class AppState {
251
258
  /** Re-runs the operation behind the current `error`, when one applies. Every
252
259
  * write to `error` clears it, so a retry op can never outlive its message. */
253
260
  errorRetry = $state.raw(null);
261
+ /** Technical detail behind the current `error`, when the message itself is
262
+ * written for people; notices keep it in their disclosure. Every write to
263
+ * `error` clears it, as it clears `errorRetry`. */
264
+ errorDetail = $state(null);
254
265
  get error() {
255
266
  return this.#error;
256
267
  }
@@ -259,6 +270,7 @@ export class AppState {
259
270
  if (message)
260
271
  this.errorRevision++;
261
272
  this.errorRetry = null;
273
+ this.errorDetail = null;
262
274
  }
263
275
  /** Case files parsed in the browser via the powerio wasm module. */
264
276
  localCases = $state.raw([]);
package/dist/styles.css CHANGED
@@ -32,6 +32,7 @@
32
32
  --surface-panel: var(--panel);
33
33
  --surface-chip: rgb(var(--paper-rgb) / 0.65);
34
34
  --surface-control: rgb(var(--paper-rgb) / 0.55);
35
+ --surface-menu: #fff;
35
36
  --border-default: var(--line);
36
37
  --border-strong: var(--accent);
37
38
  --text-primary: var(--ink);
@@ -47,6 +48,10 @@
47
48
  --data-pos: var(--pos);
48
49
  --data-neg: var(--neg);
49
50
  --focus-ring: var(--accent);
51
+ /* unselected bus outline in the plain diagram view */
52
+ --diagram-bus-stroke: #756a5b;
53
+ /* ground symbol in the multiconductor bus detail */
54
+ --mc-ground-stroke: #3a3a3a;
50
55
 
51
56
  /* type scale, anchored at the 15px body */
52
57
  --fs-display-lg: 33px;
@@ -81,6 +86,11 @@
81
86
  --radius-full: 50%;
82
87
  --elev-1: 0 2px 10px rgb(var(--ink-rgb) / 0.1);
83
88
  --elev-2: 0 4px 24px rgb(var(--ink-rgb) / 0.08);
89
+ /* floating controls that keep their own light shadows; the dark theme maps
90
+ them onto the two steps above */
91
+ --elev-cue: 0 4px 18px rgb(var(--ink-rgb) / 0.1);
92
+ --elev-menu: 0 4px 18px rgb(var(--ink-rgb) / 0.14);
93
+ --elev-tooltip: 0 2px 10px rgb(var(--ink-rgb) / 0.12);
84
94
  --shadow-thumb: 0 1px 4px rgb(var(--ink-rgb) / 0.3);
85
95
  --inset-active: inset 0 -2px 0 var(--accent);
86
96
 
@@ -103,6 +113,49 @@
103
113
  --z-grain: 9999;
104
114
  }
105
115
 
116
+ /* Dark theme: `TellegenProvider theme="dark"` sets the attribute (a host may
117
+ also put it in its template). Contrast ratios are measured against the panel
118
+ composited over #4a4a4a, the darkest grey a dark basemap paints under it:
119
+ every text token clears 7:1. --border-strong marks a panel's edge over the
120
+ map, so it clears the 3:1 non-text minimum against that panel and against
121
+ bare #4a4a4a. The same markup passes WCAG AA on either ground. */
122
+ :root[data-theme='dark'] {
123
+ --bg: #0b1420;
124
+ --paper: #0f1a27;
125
+ --panel: rgba(10, 20, 31, 0.92);
126
+ --line: #34465a; /* decorative separators only */
127
+ --border-strong: #859cb4; /* 6.30:1 against the panel, 3.13:1 against bare #4a4a4a */
128
+ --ink: #e8eef4; /* 15.3:1 */
129
+ --ink-dim: #b4c1cd; /* 9.7:1 */
130
+ --ink-faint: #95a6b6; /* 7.14:1, and 7.02:1 on the opaque --paper of a panel card */
131
+ --accent: #ffb24d;
132
+ --accent-bright: #ffc46e; /* 11.4:1 */
133
+ --accent-soft: rgba(255, 178, 77, 0.14);
134
+ --red: #ff9f8b; /* 9.0:1 */
135
+ --pos: #c9a7e0;
136
+ --neg: #8fd0a4;
137
+ --bg-rgb: 11 20 32;
138
+ --ink-rgb: 232 238 244;
139
+ --accent-rgb: 255 178 77;
140
+ --paper-rgb: 15 26 39;
141
+ --text-primary: var(--ink);
142
+ --text-secondary: var(--ink-dim);
143
+ --text-tertiary: var(--ink-faint);
144
+ --text-accent: var(--accent-bright);
145
+ --text-danger: var(--red);
146
+ --focus-ring: #8de7f7; /* 12.7:1 */
147
+ --surface-menu: var(--paper);
148
+ --diagram-bus-stroke: var(--ink-faint);
149
+ --mc-ground-stroke: var(--ink-dim);
150
+ --elev-1: 0 2px 10px rgb(0 0 0 / 0.45);
151
+ --elev-2: 0 4px 24px rgb(0 0 0 / 0.4);
152
+ --elev-cue: var(--elev-2);
153
+ --elev-menu: var(--elev-2);
154
+ --elev-tooltip: var(--elev-1);
155
+ /* the light form derives from --ink-rgb, which would glow here */
156
+ --shadow-thumb: 0 1px 4px rgb(0 0 0 / 0.5);
157
+ }
158
+
106
159
  * {
107
160
  box-sizing: border-box;
108
161
  }
@@ -225,7 +278,7 @@ a {
225
278
  ControlPanel.svelte; the .mode / .display-mode / @media source order is
226
279
  preserved so the cascade resolves exactly as before. */
227
280
  .region {
228
- font-size: 10px;
281
+ font-size: 12px;
229
282
  font-weight: 400;
230
283
  color: var(--text-secondary);
231
284
  text-transform: uppercase;
@@ -245,7 +298,7 @@ a {
245
298
  before the component split. Scoping this would raise its specificity past that rule. */
246
299
  .mode > button {
247
300
  margin-left: auto;
248
- font-size: 10.5px;
301
+ font-size: 12.5px;
249
302
  padding: 2px 7px;
250
303
  background: none;
251
304
  border: 1px solid var(--line);
@@ -264,7 +317,7 @@ a {
264
317
  }
265
318
 
266
319
  .display-mode .segment button {
267
- font-size: 11px;
320
+ font-size: 13px;
268
321
  padding: 2px 9px;
269
322
  }
270
323
 
@@ -282,7 +335,7 @@ a {
282
335
  .legend-labels {
283
336
  display: flex;
284
337
  justify-content: space-between;
285
- font-size: 10.5px;
338
+ font-size: 12.5px;
286
339
  color: var(--text-tertiary);
287
340
  margin-top: 4px;
288
341
  }
@@ -301,7 +354,7 @@ a {
301
354
  border-radius: 999px;
302
355
  color: var(--text-secondary);
303
356
  background: var(--surface-control);
304
- font-size: 10px;
357
+ font-size: 12px;
305
358
  line-height: 1;
306
359
  cursor: help;
307
360
  }
@@ -334,7 +387,7 @@ a {
334
387
 
335
388
  .reset {
336
389
  margin-top: 10px;
337
- font-size: 10.5px;
390
+ font-size: 12.5px;
338
391
  padding: 3px 10px;
339
392
  background: none;
340
393
  border: 1px solid var(--line);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tellegen/svelte",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Svelte components for tellegen power system maps, local case files, and browser solves.",
5
5
  "keywords": [
6
6
  "svelte",
@@ -53,6 +53,11 @@
53
53
  "svelte": "./dist/map.js",
54
54
  "default": "./dist/map.js"
55
55
  },
56
+ "./maplibre-worker": {
57
+ "types": "./dist/maplibre-worker.d.ts",
58
+ "development": "./dist/maplibre-worker.dev.js",
59
+ "default": "./dist/maplibre-worker.js"
60
+ },
56
61
  "./styles.css": "./dist/styles.css"
57
62
  },
58
63
  "scripts": {
@@ -65,19 +70,19 @@
65
70
  "@deck.gl/core": "^9.4.0",
66
71
  "@deck.gl/layers": "^9.4.0",
67
72
  "@deck.gl/maplibre": "^9.4.0",
68
- "@tellegen/engine": "^0.3.0",
69
- "maplibre-gl": "^6.10.0"
73
+ "@tellegen/engine": "^0.4.0",
74
+ "maplibre-gl": "^6.15.0"
70
75
  },
71
76
  "peerDependencies": {
72
77
  "svelte": ">=5.30 <6"
73
78
  },
74
79
  "devDependencies": {
75
80
  "@sveltejs/package": "^2.3.0",
76
- "@sveltejs/vite-plugin-svelte": "^7.3.0",
77
- "svelte": "^5.57.0",
78
- "svelte-check": "^4.7.6",
81
+ "@sveltejs/vite-plugin-svelte": "^7.3.1",
82
+ "svelte": "^5.57.2",
83
+ "svelte-check": "^4.7.7",
79
84
  "typescript": "^6.0.3",
80
- "vite": "^8.2.2",
81
- "vitest": "^5.0.0"
85
+ "vite": "^8.3.1",
86
+ "vitest": "^5.0.2"
82
87
  }
83
88
  }