@devicechain/widgets 0.14.0-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 (42) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +159 -0
  3. package/dist/basemap-context.d.ts +27 -0
  4. package/dist/chart-options.d.ts +14 -0
  5. package/dist/chunks/natural-earth-data-VMKQ6LY3.js +8 -0
  6. package/dist/chunks/natural-earth-data-VMKQ6LY3.js.map +7 -0
  7. package/dist/connected-widget.d.ts +8 -0
  8. package/dist/dashboard-renderer.d.ts +17 -0
  9. package/dist/definition-options.d.ts +9 -0
  10. package/dist/echart.d.ts +8 -0
  11. package/dist/flash.d.ts +13 -0
  12. package/dist/format.d.ts +3 -0
  13. package/dist/frame.d.ts +25 -0
  14. package/dist/hooks.d.ts +54 -0
  15. package/dist/index.d.ts +29 -0
  16. package/dist/index.js +2671 -0
  17. package/dist/index.js.map +7 -0
  18. package/dist/map-runtime-context.d.ts +91 -0
  19. package/dist/options.d.ts +312 -0
  20. package/dist/registry.d.ts +44 -0
  21. package/dist/theme.d.ts +9 -0
  22. package/dist/vite.d.ts +19 -0
  23. package/dist/vite.js +10 -0
  24. package/dist/vite.js.map +7 -0
  25. package/dist/widget.d.ts +16 -0
  26. package/dist/widgets/alarm-count.d.ts +3 -0
  27. package/dist/widgets/alarm-table.d.ts +3 -0
  28. package/dist/widgets/command-button.d.ts +3 -0
  29. package/dist/widgets/command-params.d.ts +7 -0
  30. package/dist/widgets/command-status.d.ts +3 -0
  31. package/dist/widgets/entity-selector.d.ts +2 -0
  32. package/dist/widgets/gauge.d.ts +2 -0
  33. package/dist/widgets/image.d.ts +2 -0
  34. package/dist/widgets/label.d.ts +2 -0
  35. package/dist/widgets/latest-card.d.ts +2 -0
  36. package/dist/widgets/map-geometry.d.ts +17 -0
  37. package/dist/widgets/map.d.ts +3 -0
  38. package/dist/widgets/natural-earth-data.d.ts +5 -0
  39. package/dist/widgets/severity.d.ts +4 -0
  40. package/dist/widgets/table.d.ts +2 -0
  41. package/dist/widgets/time-series-chart.d.ts +2 -0
  42. package/package.json +77 -0
@@ -0,0 +1,91 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * The bundler-produced runtime a map widget needs from its host.
4
+ *
5
+ * `workerUrl` is the emitted, host-resolvable URL of MapLibre's worker entry
6
+ * (`maplibre-gl/dist/maplibre-gl-worker.mjs`). It is handed to MapLibre's `setWorkerUrl`
7
+ * before the first `Map` is constructed.
8
+ *
9
+ * `loadStyles` is OPTIONAL, and imports MapLibre's stylesheet
10
+ * (`maplibre-gl/dist/maplibre-gl.css`). Omit it and import the stylesheet yourself, the way
11
+ * every map library asks you to β€” that is the ordinary path and nothing here second-guesses
12
+ * it. Supplying it buys one thing: the CSS rides the renderer's lazy chunk instead of your
13
+ * main stylesheet, which is worth **83 KB raw / 10.7 KB gzipped** to a viewer who never
14
+ * opens a board with a map on it.
15
+ *
16
+ * πŸ”΄ The size is measured against maplibre-gl 6.6.0, the version this package peers on. An
17
+ * earlier draft said 70 KB "measured, not estimated" β€” measured, but against a stale
18
+ * `node_modules` carrying 6.2.0. Measuring the right thing in the wrong tree reads exactly
19
+ * like measuring, which is why the version is named here.
20
+ *
21
+ * πŸ”΄ It is a FUNCTION rather than a boolean or a URL because the host's bundler owns its
22
+ * CSS pipeline: only the host can say "load this, lazily, your way".
23
+ */
24
+ export type MapRuntime = {
25
+ workerUrl: string;
26
+ loadStyles?: () => Promise<unknown>;
27
+ };
28
+ /**
29
+ * Supplies the host's MapLibre runtime to every map widget beneath it.
30
+ *
31
+ * Install it ONCE, high in the tree, next to TenantBasemapProvider β€” the console from its
32
+ * TenantProvider, the /dash viewer from the one place it mounts a DashboardRenderer.
33
+ *
34
+ * πŸ”‘ ON VITE, DO NOT WRITE ANY OF THIS β€” import the ready-made runtime:
35
+ *
36
+ * ```tsx
37
+ * import { viteMapRuntime } from '@devicechain/widgets/vite';
38
+ *
39
+ * <MapRuntimeProvider runtime={viteMapRuntime}>{children}</MapRuntimeProvider>
40
+ * ```
41
+ *
42
+ * On any other bundler you supply the URL yourself, and there is ONE REQUIREMENT that
43
+ * decides whether it works: MapLibre loads the URL as a MODULE worker, so whatever it
44
+ * serves must be a module with no unresolved imports left in it.
45
+ * `maplibre-gl/dist/maplibre-gl-worker.mjs` does not satisfy that on its own β€” its first
46
+ * line is `import … from './maplibre-gl-shared.mjs'`.
47
+ *
48
+ * πŸ”΄ SO DO NOT POINT AT A VERBATIM COPY OF THE WORKER FILE, and in particular do not
49
+ * reach for `new URL('maplibre-gl/dist/maplibre-gl-worker.mjs', import.meta.url)`. That
50
+ * looks exactly right and is wrong: webpack treats the target as an ASSET and copies it,
51
+ * the sibling is never emitted, and the worker dies on its own first line. Measured
52
+ * against webpack 5, from a packed tarball: the worker URL answered 200, both maps drew
53
+ * canvases, all markers appeared, tiles loaded, THE BUILD EXITED 0 AND THE CONSOLE WAS
54
+ * EMPTY β€” and the bundled basemap rendered ocean with no land on it.
55
+ *
56
+ * Two recipes that were measured working, in `hack/consumer-proof`:
57
+ *
58
+ * ```js
59
+ * // webpack β€” make the worker a second ENTRY, so its imports are bundled into it.
60
+ * entry: { main: './src/index.tsx', 'maplibre-worker': 'maplibre-gl/dist/maplibre-gl-worker.mjs' }
61
+ * // …then: <MapRuntimeProvider runtime={{ workerUrl: '/maplibre-worker.js' }}>
62
+ * ```
63
+ *
64
+ * ```js
65
+ * // any bundler, or none β€” copy the worker AND ITS SIBLING, under their own names,
66
+ * // into one served directory: maplibre-gl-worker.mjs + maplibre-gl-shared.mjs
67
+ * // …then: <MapRuntimeProvider runtime={{ workerUrl: '/vendor/maplibre-gl-worker.mjs' }}>
68
+ * ```
69
+ *
70
+ * πŸ”΄ Hold the runtime in a MODULE CONSTANT, as above, rather than building it inline in
71
+ * JSX. An object literal in the element is a new identity on every render, and while the
72
+ * widget deliberately keys its effects on `workerUrl` rather than on the object to survive
73
+ * that, a host that also passes it anywhere keyed on identity would tear down and rebuild
74
+ * the map on every parent render. There is nothing per-render in it to justify the risk.
75
+ *
76
+ * πŸ”΄ `maplibre-gl` is a PEER dependency of this package precisely so that the copy the host
77
+ * takes the worker from is the same copy this package renders with. A worker built from one
78
+ * version driving a main thread from another is the blank map again, by a different route.
79
+ */
80
+ export declare function MapRuntimeProvider({ runtime, children, }: {
81
+ runtime: MapRuntime;
82
+ children: ReactNode;
83
+ }): import("react").JSX.Element;
84
+ /**
85
+ * The host's map runtime, or null when no host supplied one.
86
+ *
87
+ * πŸ”΄ Callers MUST treat null as a refusal to render a map, not as a default to paper over.
88
+ * There is no sensible fallback: the only alternative to a host-supplied URL is MapLibre's
89
+ * own runtime derivation, which is the broken behaviour this seam exists to prevent.
90
+ */
91
+ export declare function useMapRuntime(): MapRuntime | null;
@@ -0,0 +1,312 @@
1
+ import { type WidgetType } from '@devicechain/dashboards';
2
+ interface OptionSpecBase {
3
+ doc: string;
4
+ required?: true;
5
+ }
6
+ export interface StringOptionSpec extends OptionSpecBase {
7
+ kind: 'string';
8
+ format?: 'json';
9
+ }
10
+ export interface NumberOptionSpec extends OptionSpecBase {
11
+ kind: 'number';
12
+ min?: number;
13
+ max?: number;
14
+ integer?: true;
15
+ }
16
+ export interface BooleanOptionSpec extends OptionSpecBase {
17
+ kind: 'boolean';
18
+ }
19
+ export interface EnumOptionSpec<V extends string = string> extends OptionSpecBase {
20
+ kind: 'enum';
21
+ values: readonly V[];
22
+ }
23
+ export type OptionSpec = StringOptionSpec | NumberOptionSpec | BooleanOptionSpec | EnumOptionSpec;
24
+ export type WidgetOptionSpecs = Record<string, OptionSpec>;
25
+ export declare const WIDGET_OPTIONS: {
26
+ readonly 'timeseries-chart': {
27
+ readonly title: {
28
+ readonly kind: 'string';
29
+ readonly doc: 'Heading shown in the widget frame. Blank hides the frame heading.';
30
+ };
31
+ readonly window: {
32
+ readonly kind: 'number';
33
+ readonly integer: true;
34
+ readonly min: 1;
35
+ readonly doc: 'Samples retained across ALL of the widget\'s measurements before the oldest are dropped. Bounds memory; only the chart draws them. Default 300.';
36
+ };
37
+ };
38
+ readonly 'latest-card': {
39
+ readonly title: {
40
+ readonly kind: 'string';
41
+ readonly doc: 'Heading shown in the widget frame. Defaults to the displayed measurement name.';
42
+ };
43
+ readonly measurement: {
44
+ readonly kind: 'string';
45
+ readonly doc: 'Which measurement to display. Defaults to the first the datasource selects.';
46
+ };
47
+ readonly unit: {
48
+ readonly kind: 'string';
49
+ readonly doc: 'Unit suffix shown beside the value.';
50
+ };
51
+ readonly precision: {
52
+ readonly kind: 'number';
53
+ readonly integer: true;
54
+ readonly min: 0;
55
+ readonly max: 100;
56
+ readonly doc: 'Decimal places to round displayed values to. Unset shows the raw value.';
57
+ };
58
+ readonly flashOnChange: {
59
+ readonly kind: 'boolean';
60
+ readonly doc: 'Briefly tint a value green on a rise and red on a fall when it changes.';
61
+ };
62
+ readonly window: {
63
+ readonly kind: 'number';
64
+ readonly integer: true;
65
+ readonly min: 1;
66
+ readonly doc: 'Samples retained across ALL of the widget\'s measurements before the oldest are dropped. Bounds memory; only the chart draws them. Default 300.';
67
+ };
68
+ };
69
+ readonly gauge: {
70
+ readonly title: {
71
+ readonly kind: 'string';
72
+ readonly doc: 'Heading shown in the widget frame. Defaults to the displayed measurement name.';
73
+ };
74
+ readonly measurement: {
75
+ readonly kind: 'string';
76
+ readonly doc: 'Which measurement to display. Defaults to the first the datasource selects.';
77
+ };
78
+ readonly min: {
79
+ readonly kind: 'number';
80
+ readonly doc: 'Low end of the gauge scale. Default 0.';
81
+ };
82
+ readonly max: {
83
+ readonly kind: 'number';
84
+ readonly doc: 'High end of the gauge scale. Default 100.';
85
+ };
86
+ readonly unit: {
87
+ readonly kind: 'string';
88
+ readonly doc: 'Unit suffix shown beside the value.';
89
+ };
90
+ readonly flashOnChange: {
91
+ readonly kind: 'boolean';
92
+ readonly doc: 'Briefly tint a value green on a rise and red on a fall when it changes.';
93
+ };
94
+ readonly window: {
95
+ readonly kind: 'number';
96
+ readonly integer: true;
97
+ readonly min: 1;
98
+ readonly doc: 'Samples retained across ALL of the widget\'s measurements before the oldest are dropped. Bounds memory; only the chart draws them. Default 300.';
99
+ };
100
+ };
101
+ readonly table: {
102
+ readonly title: {
103
+ readonly kind: 'string';
104
+ readonly doc: 'Heading shown in the widget frame. Blank hides the frame heading.';
105
+ };
106
+ readonly precision: {
107
+ readonly kind: 'number';
108
+ readonly integer: true;
109
+ readonly min: 0;
110
+ readonly max: 100;
111
+ readonly doc: 'Decimal places to round displayed values to. Unset shows the raw value.';
112
+ };
113
+ readonly flashOnChange: {
114
+ readonly kind: 'boolean';
115
+ readonly doc: 'Briefly tint a value green on a rise and red on a fall when it changes.';
116
+ };
117
+ readonly window: {
118
+ readonly kind: 'number';
119
+ readonly integer: true;
120
+ readonly min: 1;
121
+ readonly doc: 'Samples retained across ALL of the widget\'s measurements before the oldest are dropped. Bounds memory; only the chart draws them. Default 300.';
122
+ };
123
+ };
124
+ readonly label: {
125
+ readonly title: {
126
+ readonly kind: 'string';
127
+ readonly doc: 'Heading shown in the widget frame. Blank hides the frame heading.';
128
+ };
129
+ readonly text: {
130
+ readonly kind: 'string';
131
+ readonly required: true;
132
+ readonly doc: 'The text to show. Rendered as plain text β€” markup is never interpreted.';
133
+ };
134
+ readonly align: {
135
+ readonly kind: 'enum';
136
+ readonly values: readonly ["left", "center", "right"];
137
+ readonly doc: 'Horizontal alignment of the text. Default center.';
138
+ };
139
+ readonly fontSize: {
140
+ readonly kind: 'number';
141
+ readonly min: 1;
142
+ readonly doc: 'Text size in pixels. Default 16.';
143
+ };
144
+ };
145
+ readonly image: {
146
+ readonly title: {
147
+ readonly kind: 'string';
148
+ readonly doc: 'Heading shown in the widget frame. Blank hides the frame heading.';
149
+ };
150
+ readonly url: {
151
+ readonly kind: 'string';
152
+ readonly required: true;
153
+ readonly doc: 'Source URL of the image.';
154
+ };
155
+ readonly alt: {
156
+ readonly kind: 'string';
157
+ readonly doc: 'Alternative text describing the image for assistive technology.';
158
+ };
159
+ readonly fit: {
160
+ readonly kind: 'enum';
161
+ readonly values: readonly ["contain", "cover", "fill"];
162
+ readonly doc: 'How the image fills its box. Default contain.';
163
+ };
164
+ };
165
+ readonly 'alarm-table': {
166
+ readonly title: {
167
+ readonly kind: 'string';
168
+ readonly doc: 'Heading shown in the widget frame. Blank hides the frame heading.';
169
+ };
170
+ readonly state: {
171
+ readonly kind: 'enum';
172
+ readonly values: readonly ["ACTIVE", "CLEARED"];
173
+ readonly doc: 'Show only alarms in this state. Unset shows every state.';
174
+ };
175
+ readonly severity: {
176
+ readonly kind: 'enum';
177
+ readonly values: readonly ["CRITICAL", "MAJOR", "MINOR", "WARNING", "INDETERMINATE"];
178
+ readonly doc: 'Show only alarms at this severity. Unset shows every severity.';
179
+ };
180
+ readonly acknowledged: {
181
+ readonly kind: 'enum';
182
+ readonly values: readonly ["true", "false"];
183
+ readonly doc: "Show only acknowledged ('true') or unacknowledged ('false') alarms. Unset shows both.";
184
+ };
185
+ readonly maxRows: {
186
+ readonly kind: 'number';
187
+ readonly integer: true;
188
+ readonly min: 1;
189
+ readonly doc: 'Alarms loaded into the table. Default 50.';
190
+ };
191
+ readonly precision: {
192
+ readonly kind: 'number';
193
+ readonly integer: true;
194
+ readonly min: 0;
195
+ readonly max: 100;
196
+ readonly doc: 'Decimal places to round displayed values to. Unset shows the raw value.';
197
+ };
198
+ readonly flashOnChange: {
199
+ readonly kind: 'boolean';
200
+ readonly doc: 'Briefly tint a value green on a rise and red on a fall when it changes.';
201
+ };
202
+ readonly selectionTarget: {
203
+ readonly kind: 'string';
204
+ readonly doc: 'Name of the slot this widget re-points when the viewer picks an entity.';
205
+ };
206
+ };
207
+ readonly 'alarm-count': {
208
+ readonly title: {
209
+ readonly kind: 'string';
210
+ readonly doc: 'Heading shown in the widget frame. Blank hides the frame heading.';
211
+ };
212
+ readonly state: {
213
+ readonly kind: 'enum';
214
+ readonly values: readonly ["ACTIVE", "CLEARED"];
215
+ readonly doc: 'Show only alarms in this state. Unset shows every state.';
216
+ };
217
+ readonly severity: {
218
+ readonly kind: 'enum';
219
+ readonly values: readonly ["CRITICAL", "MAJOR", "MINOR", "WARNING", "INDETERMINATE"];
220
+ readonly doc: 'Show only alarms at this severity. Unset shows every severity.';
221
+ };
222
+ readonly acknowledged: {
223
+ readonly kind: 'enum';
224
+ readonly values: readonly ["true", "false"];
225
+ readonly doc: "Show only acknowledged ('true') or unacknowledged ('false') alarms. Unset shows both.";
226
+ };
227
+ };
228
+ readonly 'command-button': {
229
+ readonly title: {
230
+ readonly kind: 'string';
231
+ readonly doc: 'Heading shown in the widget frame. Blank hides the frame heading.';
232
+ };
233
+ readonly commandName: {
234
+ readonly kind: 'string';
235
+ readonly required: true;
236
+ readonly doc: 'Command key issued to the target device. Without it the widget cannot send.';
237
+ };
238
+ readonly commandLabel: {
239
+ readonly kind: 'string';
240
+ readonly doc: 'Text on the send button. Defaults to the command key.';
241
+ };
242
+ readonly parameterSchema: {
243
+ readonly kind: 'string';
244
+ readonly format: 'json';
245
+ readonly doc: "The command's parameter descriptors, baked in as JSON at author time. Drives the typed form.";
246
+ };
247
+ readonly maxRows: {
248
+ readonly kind: 'number';
249
+ readonly integer: true;
250
+ readonly min: 1;
251
+ readonly doc: 'Recent commands shown in the history. Default 20.';
252
+ };
253
+ };
254
+ readonly 'entity-selector': {
255
+ readonly title: {
256
+ readonly kind: 'string';
257
+ readonly doc: 'Heading shown in the widget frame. Blank hides the frame heading.';
258
+ };
259
+ readonly selectionTarget: {
260
+ readonly kind: 'string';
261
+ readonly doc: 'Name of the slot this widget re-points when the viewer picks an entity.';
262
+ readonly required: true;
263
+ };
264
+ };
265
+ readonly map: {
266
+ readonly title: {
267
+ readonly kind: 'string';
268
+ readonly doc: 'Heading shown in the widget frame. Blank hides the frame heading.';
269
+ };
270
+ readonly tileUrl: {
271
+ readonly kind: 'string';
272
+ readonly doc: "Raster tile URL template, e.g. https://tiles.example.com/{z}/{x}/{y}.png. Leave empty to inherit the tenant's basemap; setting one overrides it for this board only.";
273
+ };
274
+ readonly attribution: {
275
+ readonly kind: 'string';
276
+ readonly doc: 'Credit line the tile source requires, shown on the map. Set whatever the provider you chose asks for.';
277
+ };
278
+ };
279
+ };
280
+ type SpecValue<S> = S extends {
281
+ kind: 'enum';
282
+ values: readonly (infer V)[];
283
+ } ? V extends string ? V : never : S extends {
284
+ kind: 'number';
285
+ } ? number : S extends {
286
+ kind: 'boolean';
287
+ } ? boolean : S extends {
288
+ kind: 'string';
289
+ } ? string : never;
290
+ type RequiredOptionKeys<S> = {
291
+ [K in keyof S]: S[K] extends {
292
+ required: true;
293
+ } ? K : never;
294
+ }[keyof S];
295
+ type OptionsFor<T extends WidgetType> = {
296
+ [K in RequiredOptionKeys<(typeof WIDGET_OPTIONS)[T]>]: SpecValue<(typeof WIDGET_OPTIONS)[T][K]>;
297
+ } & {
298
+ [K in Exclude<keyof (typeof WIDGET_OPTIONS)[T], RequiredOptionKeys<(typeof WIDGET_OPTIONS)[T]>>]?: SpecValue<(typeof WIDGET_OPTIONS)[T][K]>;
299
+ };
300
+ export type WidgetOptions<T extends WidgetType> = T extends WidgetType ? OptionsFor<T> : never;
301
+ export type OptionIssueCode = 'unknown' | 'type' | 'enum' | 'range' | 'missing' | 'json' | 'invariant';
302
+ export interface OptionIssue {
303
+ widgetType: WidgetType;
304
+ key: string;
305
+ code: OptionIssueCode;
306
+ message: string;
307
+ }
308
+ export declare function validateWidgetOptions(widgetType: WidgetType, options: Record<string, unknown> | undefined): OptionIssue[];
309
+ export declare function numberOptionSpec(type: WidgetType, key: string): NumberOptionSpec | undefined;
310
+ export declare function clampNumberOption(spec: NumberOptionSpec | undefined, value: number): number | undefined;
311
+ export declare function enumOptionValues(type: WidgetType, key: string): readonly string[] | undefined;
312
+ export {};
@@ -0,0 +1,44 @@
1
+ import type { WidgetType } from '@devicechain/dashboards';
2
+ import type { AlarmStreamState, CommandStreamState, LocationStreamState } from './hooks';
3
+ import type { WidgetComponent } from './widget';
4
+ export type WidgetChannel = 'measurement' | 'alarm' | 'control' | 'selection' | 'location';
5
+ export declare const WIDGET_CHANNEL: {
6
+ readonly 'timeseries-chart': 'measurement';
7
+ readonly 'latest-card': 'measurement';
8
+ readonly gauge: 'measurement';
9
+ readonly table: 'measurement';
10
+ readonly label: 'measurement';
11
+ readonly image: 'measurement';
12
+ readonly 'alarm-table': 'alarm';
13
+ readonly 'alarm-count': 'alarm';
14
+ readonly 'command-button': 'control';
15
+ readonly 'entity-selector': 'selection';
16
+ readonly map: 'location';
17
+ };
18
+ type WidgetTypeOn<C extends WidgetChannel> = {
19
+ [K in WidgetType]: (typeof WIDGET_CHANNEL)[K] extends C ? K : never;
20
+ }[WidgetType];
21
+ type MeasurementWidgetType = WidgetTypeOn<'measurement'>;
22
+ type AlarmWidgetType = WidgetTypeOn<'alarm'>;
23
+ type ControlWidgetType = WidgetTypeOn<'control'>;
24
+ type SelectionWidgetType = WidgetTypeOn<'selection'>;
25
+ type LocationWidgetType = WidgetTypeOn<'location'>;
26
+ export declare const WIDGET_REGISTRY: Record<MeasurementWidgetType, WidgetComponent>;
27
+ export declare const ALARM_WIDGET_REGISTRY: Record<AlarmWidgetType, WidgetComponent<AlarmStreamState>>;
28
+ export declare const CONTROL_WIDGET_REGISTRY: Record<ControlWidgetType, WidgetComponent<CommandStreamState>>;
29
+ export declare const SELECTION_WIDGET_REGISTRY: Record<SelectionWidgetType, WidgetComponent<null>>;
30
+ export declare const LOCATION_WIDGET_REGISTRY: Record<LocationWidgetType, WidgetComponent<LocationStreamState>>;
31
+ export declare const WIDGET_BINDS_DATASOURCE: {
32
+ readonly 'timeseries-chart': true;
33
+ readonly 'latest-card': true;
34
+ readonly gauge: true;
35
+ readonly table: true;
36
+ readonly label: false;
37
+ readonly image: false;
38
+ readonly 'alarm-table': true;
39
+ readonly 'alarm-count': true;
40
+ readonly 'command-button': true;
41
+ readonly 'entity-selector': false;
42
+ readonly map: true;
43
+ };
44
+ export {};
@@ -0,0 +1,9 @@
1
+ export declare function css(name: ThemeVar): string;
2
+ export type ThemeVar = 'background' | 'foreground' | 'card' | 'card-foreground' | 'muted' | 'muted-foreground' | 'primary' | 'border' | 'destructive';
3
+ export interface ChartTheme {
4
+ foreground: string;
5
+ mutedForeground: string;
6
+ border: string;
7
+ series: string[];
8
+ }
9
+ export declare function resolveChartTheme(el: Element): ChartTheme;
package/dist/vite.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { MapRuntime } from './map-runtime-context';
2
+ /**
3
+ * A complete `MapRuntime` for a Vite host.
4
+ *
5
+ * ```tsx
6
+ * import { MapRuntimeProvider } from '@devicechain/widgets';
7
+ * import { viteMapRuntime } from '@devicechain/widgets/vite';
8
+ *
9
+ * <MapRuntimeProvider runtime={viteMapRuntime}>{children}</MapRuntimeProvider>
10
+ * ```
11
+ *
12
+ * A module constant, so it is referentially stable for the life of the page.
13
+ *
14
+ * `loadStyles` keeps MapLibre's 83 KB stylesheet (10.7 KB gzipped) on the renderer's lazy
15
+ * chunk, so a viewer who opens no map downloads none of it. Import the stylesheet yourself
16
+ * instead if you would rather have it eagerly β€” the field is optional and this is only the
17
+ * default that costs a first-time user nothing to accept.
18
+ */
19
+ export declare const viteMapRuntime: MapRuntime;
package/dist/vite.js ADDED
@@ -0,0 +1,10 @@
1
+ // src/vite.ts
2
+ import workerUrl from "maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url";
3
+ var viteMapRuntime = {
4
+ workerUrl,
5
+ loadStyles: () => import("maplibre-gl/dist/maplibre-gl.css")
6
+ };
7
+ export {
8
+ viteMapRuntime
9
+ };
10
+ //# sourceMappingURL=vite.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/vite.ts"],
4
+ "sourcesContent": ["// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// `@devicechain/widgets/vite` \u2014 the ready-made map runtime for hosts built with Vite.\n//\n// \uD83D\uDD34 THIS IS THE ONE FILE IN THIS PACKAGE ALLOWED TO WRITE A BUNDLER'S DIALECT, and the\n// exception is deliberate, bounded, and enforced rather than promised. The main entry\n// (`@devicechain/widgets`) contains no bundler-specific specifier at all \u2014 that is what\n// lets a webpack, Next or Rollup consumer build it \u2014 and the dialect gate proves it by\n// building the two entries SEPARATELY: zero dialect specifiers reachable from `index.ts`,\n// exactly one from here. So the carve-out cannot quietly widen, and it cannot leak into\n// the portable entry, because a consumer only ever gets this module by importing it BY\n// NAME.\n//\n// \uD83D\uDD34 WHY THE EXCEPTION IS WORTH IT. Without it every Vite consumer \u2014 which today means\n// every likely consumer, including this repo's own console and /dash \u2014 must learn that\n// MapLibre needs a worker URL, learn their bundler's idiom for emitting one, and write it\n// correctly, to render a map. That is a lot of ceremony to hand someone who asked for a map\n// widget, and getting it wrong has a famously quiet failure mode. Simplicity for the\n// consumer is worth one carefully fenced file.\n//\n// VERIFIED, not assumed: a package inside `node_modules` writing `?worker&url` is resolved\n// correctly by a CONSUMER's Vite \u2014 tested outside this monorepo against Vite 6.4.3 and\n// 8.2.2, with the worker emitted as its own entry and its `maplibre-gl-shared.mjs` sibling\n// INLINED into it. That last part is why `?worker&url` and not plain `?url`: the plain form\n// copies one file verbatim and leaves the sibling dangling.\n\nimport type { MapRuntime } from './map-runtime-context';\n\n// `?worker&url` makes Vite treat the module as a worker ENTRY \u2014 bundling what it imports\n// along with it \u2014 and hand back the emitted, hashed URL.\nimport workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';\n\n/**\n * A complete `MapRuntime` for a Vite host.\n *\n * ```tsx\n * import { MapRuntimeProvider } from '@devicechain/widgets';\n * import { viteMapRuntime } from '@devicechain/widgets/vite';\n *\n * <MapRuntimeProvider runtime={viteMapRuntime}>{children}</MapRuntimeProvider>\n * ```\n *\n * A module constant, so it is referentially stable for the life of the page.\n *\n * `loadStyles` keeps MapLibre's 83 KB stylesheet (10.7 KB gzipped) on the renderer's lazy\n * chunk, so a viewer who opens no map downloads none of it. Import the stylesheet yourself\n * instead if you would rather have it eagerly \u2014 the field is optional and this is only the\n * default that costs a first-time user nothing to accept.\n */\nexport const viteMapRuntime: MapRuntime = {\n workerUrl,\n loadStyles: () => import('maplibre-gl/dist/maplibre-gl.css'),\n};\n"],
5
+ "mappings": ";AA+BA,OAAO,eAAe;AAmBf,IAAM,iBAA6B;AAAA,EACxC;AAAA,EACA,YAAY,MAAM,OAAO,kCAAkC;AAC7D;",
6
+ "names": []
7
+ }
@@ -0,0 +1,16 @@
1
+ import type { MeasurementSample, WidgetActions, WidgetInstance } from '@devicechain/dashboards';
2
+ import type { ComponentType } from 'react';
3
+ import type { MeasurementStreamState } from './hooks';
4
+ export interface WidgetProps<D = MeasurementStreamState> {
5
+ widget: WidgetInstance;
6
+ data: D;
7
+ actions?: WidgetActions;
8
+ }
9
+ export type WidgetComponent<D = MeasurementStreamState> = ComponentType<WidgetProps<D>>;
10
+ export declare function pickSample(latest: Record<string, MeasurementSample>, name: string | undefined): MeasurementSample | undefined;
11
+ type Options = Record<string, unknown> | undefined;
12
+ export declare function optString(options: Options, key: string): string | undefined;
13
+ export declare function optNumber(options: Options, key: string): number | undefined;
14
+ export declare function optBoolean(options: Options, key: string): boolean;
15
+ export declare function primaryMeasurementName(widget: WidgetInstance): string | undefined;
16
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { AlarmStreamState } from '../hooks';
2
+ import { type WidgetProps } from '../widget';
3
+ export declare function AlarmCount({ widget, data }: WidgetProps<AlarmStreamState>): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import type { AlarmStreamState } from '../hooks';
2
+ import { type WidgetProps } from '../widget';
3
+ export declare function AlarmTable({ widget, data, actions }: WidgetProps<AlarmStreamState>): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import type { CommandStreamState } from '../hooks';
2
+ import { type WidgetProps } from '../widget';
3
+ export declare function CommandButton({ widget, data, actions }: WidgetProps<CommandStreamState>): import("react").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import type { CommandParameter } from '@devicechain/dashboards';
2
+ export declare function parseParameterSchema(schema: string | null | undefined): CommandParameter[];
3
+ export declare function isScalar(param: CommandParameter): boolean;
4
+ export declare function parseBool(raw: string): boolean;
5
+ export declare function defaultValues(params: CommandParameter[]): Record<string, string>;
6
+ export declare function validateParams(params: CommandParameter[], values: Record<string, string>): Record<string, string>;
7
+ export declare function buildPayload(params: CommandParameter[], values: Record<string, string>): string | undefined;
@@ -0,0 +1,3 @@
1
+ export declare function commandStatusColor(status: string): string;
2
+ export declare function isTerminalStatus(status: string): boolean;
3
+ export declare function commandStatusLabel(status: string): string;
@@ -0,0 +1,2 @@
1
+ import { type WidgetProps } from '../widget';
2
+ export declare function EntitySelector({ widget }: WidgetProps<null>): import("react").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { type WidgetProps } from '../widget';
2
+ export declare function Gauge({ widget, data }: WidgetProps): import("react").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { type WidgetProps } from '../widget';
2
+ export declare function Image({ widget }: WidgetProps): import("react").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { type WidgetProps } from '../widget';
2
+ export declare function Label({ widget }: WidgetProps): import("react").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { type WidgetProps } from '../widget';
2
+ export declare function LatestCard({ widget, data }: WidgetProps): import("react").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import type { LocationSample } from '@devicechain/dashboards';
2
+ export interface PlaceableLocation extends LocationSample {
3
+ latitude: number;
4
+ longitude: number;
5
+ }
6
+ export declare function placeable(samples: readonly LocationSample[]): PlaceableLocation[];
7
+ export interface PanelPoint {
8
+ x: number;
9
+ y: number;
10
+ }
11
+ export declare function projectToPanel(positions: readonly PlaceableLocation[]): PanelPoint[];
12
+ export declare function formatDegrees(value: number): string;
13
+ export declare function describePosition(sample: PlaceableLocation): string;
14
+ export declare function rasterStyleFor(tileUrl: string, attribution: string | undefined): unknown;
15
+ export declare const BUNDLED_BASEMAP_ATTRIBUTION = "Made with Natural Earth";
16
+ export declare function landStyleFrom(land: unknown, boundaries: unknown): unknown;
17
+ export declare function loadLandStyle(): Promise<unknown>;
@@ -0,0 +1,3 @@
1
+ import type { LocationStreamState } from '../hooks';
2
+ import { type WidgetProps } from '../widget';
3
+ export declare function MapWidget({ widget, data }: WidgetProps<LocationStreamState>): import("react").JSX.Element;
@@ -0,0 +1,5 @@
1
+ export interface NaturalEarthData {
2
+ land: unknown;
3
+ boundaries: unknown;
4
+ }
5
+ export declare const NATURAL_EARTH: NaturalEarthData;
@@ -0,0 +1,4 @@
1
+ export declare function severityColor(severity: string): string;
2
+ export declare function severityRank(severity: string): number;
3
+ export declare function severityLabel(severity: string): string;
4
+ export declare function highestSeverity(severities: string[]): string | undefined;
@@ -0,0 +1,2 @@
1
+ import { type WidgetProps } from '../widget';
2
+ export declare function Table({ widget, data }: WidgetProps): import("react").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { type WidgetProps } from '../widget';
2
+ export declare function TimeSeriesChart({ widget, data }: WidgetProps): import("react").JSX.Element;