@glasshome/widget-sdk 1.2.0 → 1.3.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.
package/dist/index.js CHANGED
@@ -1,1413 +1,1290 @@
1
- import { z as A } from "zod";
2
- import { widgetManifestSchema as xn, formatSchemaError as yn } from "@glasshome/widget-contract";
3
- import { effect as W, className as I, style as le, template as x, insert as p, createComponent as k, memo as T, setStyleProperty as ee, addEventListener as K, use as Ce, delegateEvents as Se } from "solid-js/web";
4
- import { createElementSize as Me } from "@solid-primitives/resize-observer";
5
- import { createContext as De, useContext as B, Show as E, createSignal as V, onMount as Te, createMemo as j, splitProps as _e, createEffect as se, on as ge, onCleanup as ce } from "solid-js";
6
- import { clsx as Oe } from "clsx";
7
- import { twMerge as ze } from "tailwind-merge";
8
- import { useService as Ee, useToggle as Ne, useTurnOff as Ae, useTurnOn as Ve } from "@glasshome/sync-layer/solid";
9
- import { byDomain as kn, useArea as Cn, useCamera as Sn, useConnection as Mn, useCurrency as Dn, useEntities as Tn, useEntity as _n, useEntityHistory as On, useEntityStatistics as zn, useForecast as En, useHassConfig as Nn, useLocale as An, useStore as Vn, useTemperatureUnit as Wn, useUnitSystem as Rn } from "@glasshome/sync-layer/solid";
10
- import { getForecasts as Pn, getStream as In, getWebRtcClientConfig as Ln, sendWebRtcCandidate as Un, startWebRtcSession as jn, state as Bn, trackEntityHistory as Fn, untrackEntityHistory as Gn } from "@glasshome/sync-layer";
11
- function me(e) {
12
- return A.toJSONSchema(e, {
13
- override: (t) => {
14
- const i = A.globalRegistry.get(t.zodSchema);
15
- return i && typeof i == "object" && Object.keys(i).length > 0 ? { ...t.jsonSchema, ...i } : t.jsonSchema;
16
- }
17
- });
18
- }
19
- function We(e) {
20
- try {
21
- return e.parse({});
22
- } catch {
23
- return {};
24
- }
25
- }
26
- function Jt(e) {
27
- return e.configSchema && (e.manifest.schema || (e.manifest.schema = me(e.configSchema)), e.manifest.defaultConfig || (e.manifest.defaultConfig = We(e.configSchema))), e;
28
- }
29
- const P = De();
30
- function Qt() {
31
- const e = B(P);
32
- if (!e)
33
- throw new Error("useWidgetContext must be used within a Widget component");
34
- return e;
35
- }
36
- function Re(e) {
37
- const t = Array.isArray(e) ? e[0] : e, i = t?.split(".")[0];
38
- if (!i) throw new Error(`Invalid entity ID: ${String(t)}`);
39
- return i;
40
- }
41
- function G(e, t) {
42
- return (i, r = {}) => e(Re(i), t, r, { entity_id: i });
43
- }
44
- function Zt() {
45
- const e = B(P)?.callService;
46
- return e ? {
47
- callService: e,
48
- turnOn: G(e, "turn_on"),
49
- turnOff: G(e, "turn_off"),
50
- toggle: G(e, "toggle")
51
- } : Ee();
52
- }
53
- function en() {
54
- const e = B(P)?.callService;
55
- return e ? G(e, "turn_on") : Ve();
56
- }
57
- function tn() {
58
- const e = B(P)?.callService;
59
- return e ? G(e, "turn_off") : Ae();
60
- }
61
- function nn() {
62
- const e = B(P)?.callService;
63
- return e ? G(e, "toggle") : Ne();
64
- }
65
- const J = {
66
- /** Background layer (gradients, images, glows) */
67
- BACKGROUND: 0,
68
- /** Main content layer (icon, title, text) */
69
- CONTENT: 10,
70
- /** Overlay layer (loading states, volume indicators) */
71
- OVERLAY: 20,
72
- /** Action layer (buttons, edit controls) */
73
- ACTIONS: 30
74
- }, ve = `/* Authoritative SDK CSS contract. Injected once on first Widget mount
75
- * via framework/theming/tokens.ts.
76
- *
77
- * All widget-internal visual scale is driven from CSS custom properties +
78
- * container queries on the \`.glasshome-widget\` shell (\`container-type: size\`).
79
- * No JS classifier, no size tier enum.
80
- */
81
-
82
- :root {
83
- --tone-success: oklch(0.70 0.18 145);
84
- --tone-warning: oklch(0.80 0.17 75);
85
- --tone-danger: oklch(0.64 0.22 27);
86
- --tone-info: oklch(0.66 0.20 245);
87
- --tone-neutral: oklch(0.65 0.02 250);
88
- --tone-accent: oklch(0.74 0.18 60);
89
-
90
- --widget-grad-strength: 1;
91
- --widget-glow-default: 0.4;
92
- --widget-border-highlight: oklch(0.98 0 0 / 0.4);
93
- }
94
-
95
- .dark {
96
- --tone-success: oklch(0.74 0.18 145);
97
- --tone-warning: oklch(0.82 0.17 75);
98
- --tone-danger: oklch(0.68 0.22 27);
99
- --tone-info: oklch(0.70 0.20 245);
100
- --tone-neutral: oklch(0.69 0.02 250);
101
- --tone-accent: oklch(0.78 0.18 60);
102
-
103
- --widget-grad-strength: 1.1;
104
- --widget-glow-default: 0.5;
105
- --widget-border-highlight: oklch(1 0 0 / 0.08);
106
- }
107
-
108
- @property --widget-color {
109
- syntax: "<color>";
110
- inherits: true;
111
- initial-value: oklch(0.65 0.02 250);
112
- }
113
-
114
- /* === Widget shell ===
115
- * Fluid scale tokens — tied to the shell's own container box (cqmin/cqi/cqb).
116
- * Same input box → same output, so two widgets at the same grid cell match
117
- * exactly. Tune multipliers / clamps to adjust density. */
118
- .glasshome-widget {
119
- --widget-color: var(--tone-neutral);
120
- --widget-glow-strength: var(--widget-glow-default);
121
-
122
- --widget-icon-box: clamp(28px, 22cqmin, 64px);
123
- --widget-icon-glyph: clamp(16px, 13cqmin, 36px);
124
- --widget-pad: clamp(8px, 4cqmin, 24px);
125
- --widget-gap: clamp(6px, 2cqmin, 16px);
126
- --widget-title-size: clamp(12px, 2cqi, 18px);
127
- --widget-subtitle: clamp(12px, 2.5cqi, 20px);
128
- --widget-status-size: clamp(14px, 5cqi, 36px);
129
- --widget-value-size: clamp(18px, 7cqi, 48px);
130
- --widget-badge-size: clamp(11px, 1.6cqi, 14px);
131
- }
132
-
133
- .glasshome-widget {
134
- background: var(--widget-gradient,
135
- linear-gradient(135deg,
136
- color-mix(in oklch, var(--widget-color) calc(22% * var(--widget-grad-strength)), transparent),
137
- color-mix(in oklch, var(--widget-color-to, var(--widget-color)) calc(11% * var(--widget-grad-strength)), transparent)
138
- )
139
- );
140
- box-shadow: inset 0 1px 0 var(--widget-border-highlight);
141
- }
142
-
143
- /* === Slot: content layout === */
144
- /* Default: column. Flip to row only on wide-and-short widgets (matches the
145
- * old contentLayout heuristic: aspect > 1 AND height < 150px). */
146
- .glasshome-widget-content {
147
- position: relative;
148
- display: flex;
149
- flex-direction: column;
150
- justify-content: space-between;
151
- width: 100%;
152
- height: 100%;
153
- padding: var(--widget-pad);
154
- gap: var(--widget-gap);
155
- overflow: hidden;
156
- }
157
- @container widget (min-aspect-ratio: 1) and (max-height: 149px) {
158
- .glasshome-widget-content {
159
- flex-direction: row;
160
- align-items: center;
161
- justify-content: flex-start;
162
- }
163
- }
164
- .glasshome-widget-content [class*="ml-auto"] {
165
- position: relative;
166
- z-index: 30;
167
- }
168
-
169
- /* === Slot: icon === */
170
- .glasshome-widget-icon {
171
- width: var(--widget-icon-box);
172
- height: var(--widget-icon-box);
173
- border-radius: var(--radius-sm, 12px);
174
- background: var(--widget-icon-color, var(--widget-color));
175
- box-shadow: 0 0 calc(var(--widget-glow-strength) * 30px)
176
- color-mix(in oklch, var(--widget-icon-color, var(--widget-color)) 50%, transparent);
177
- color: oklch(from var(--widget-icon-color, var(--widget-color)) calc(0.52 + sign(0.5 - l) * 0.43) calc(c * 0.2) h);
178
- }
179
- .glasshome-widget-icon-glyph {
180
- font-size: var(--widget-icon-glyph);
181
- line-height: 1;
182
- }
183
- .glasshome-widget-icon-stack {
184
- position: absolute;
185
- width: 102%;
186
- height: 102%;
187
- border-radius: var(--radius-sm, 12px);
188
- }
189
- .glasshome-widget-icon-stack-2 { bottom: -14%; right: -10%; opacity: 0.45; z-index: -2; }
190
- .glasshome-widget-icon-stack-3 { bottom: -28%; right: -20%; opacity: 0.20; z-index: -3; }
191
-
192
- /* === Slot: text === */
193
- .glasshome-widget-title {
194
- font-size: var(--widget-title-size);
195
- line-height: 1.2;
196
- color: color-mix(in oklch, var(--color-foreground, currentColor) 60%, transparent);
197
- overflow: hidden;
198
- text-overflow: ellipsis;
199
- white-space: nowrap;
200
- }
201
- .glasshome-widget-subtitle {
202
- font-size: var(--widget-subtitle);
203
- color: color-mix(in oklch, var(--color-foreground, currentColor) 60%, transparent);
204
- }
205
- .glasshome-widget-status {
206
- font-size: var(--widget-status-size);
207
- font-weight: 700;
208
- color: var(--color-foreground, currentColor);
209
- line-height: 1.1;
210
- }
211
- .glasshome-widget-value {
212
- font-size: var(--widget-value-size);
213
- font-weight: 700;
214
- color: var(--color-foreground, currentColor);
215
- line-height: 1.05;
216
- }
217
- .glasshome-widget-badge {
218
- font-size: var(--widget-badge-size);
219
- font-weight: 500;
220
- padding: 0.125rem 0.5rem;
221
- border-radius: 9999px;
222
- background: color-mix(in oklch, var(--color-foreground, currentColor) 20%, transparent);
223
- color: var(--color-foreground, currentColor);
224
- }
225
-
226
- .glasshome-widget-loading {
227
- background: color-mix(in oklch, var(--widget-color) 20%, transparent);
228
- }
229
-
230
- /* === Slider fill ===
231
- * Value flows in via --widget-fill-value (0-100). Vertical orientation auto-
232
- * detected via container query. */
233
- .glasshome-widget-slider-fill {
234
- --widget-fill-value: 0;
235
- background: color-mix(in oklch, var(--widget-icon-color, var(--widget-color)) 30%, transparent);
236
- box-shadow: 0 0 calc(var(--widget-glow-strength) * 40px)
237
- color-mix(in oklch, var(--widget-icon-color, var(--widget-color)) 40%, transparent);
238
- clip-path: inset(0 calc((100 - var(--widget-fill-value)) * 1%) 0 0);
239
- }
240
- @container widget (max-aspect-ratio: 1) {
241
- .glasshome-widget-slider-fill {
242
- clip-path: inset(calc((100 - var(--widget-fill-value)) * 1%) 0 0 0);
243
- }
244
- }
245
- `;
246
- let re = !1, Q;
247
- const he = /* @__PURE__ */ new WeakSet();
248
- function He() {
249
- return Q || (Q = new CSSStyleSheet(), Q.replaceSync(
250
- ve.replace(/:root\b/g, ":host").replace(/^\.dark\b/gm, ":host(.dark)")
251
- )), Q;
252
- }
253
- function Pe(e) {
254
- if (typeof ShadowRoot < "u" && e instanceof ShadowRoot) {
255
- if (he.has(e)) return;
256
- const r = He();
257
- e.adoptedStyleSheets.includes(r) || (e.adoptedStyleSheets = [...e.adoptedStyleSheets, r]), he.add(e);
258
- return;
259
- }
260
- if (re) return;
261
- const t = e ?? (typeof document > "u" ? void 0 : document);
262
- if (!t) return;
263
- if (t.head.querySelector?.("style[data-glasshome-tokens]")) {
264
- re = !0;
265
- return;
266
- }
267
- const i = t.createElement("style");
268
- i.setAttribute("data-glasshome-tokens", ""), i.textContent = ve, t.head.appendChild(i), re = !0;
269
- }
270
- function R(...e) {
271
- return ze(Oe(e));
272
- }
273
- const Ie = {
274
- id: "classic-glass",
275
- name: "Classic Glass",
276
- description: "Default glassmorphism design with blur background and gradient",
277
- styles: {
278
- cssVars: {
279
- "--widget-bg": "rgba(255, 255, 255, 0.1)",
280
- "--widget-border": "rgba(255, 255, 255, 0.2)",
281
- "--widget-blur": "12px",
282
- "--widget-shadow": "0 8px 32px rgba(0, 0, 0, 0.2)",
283
- "--widget-padding": "1.5rem"
284
- },
285
- class: "backdrop-blur-xl"
286
- },
287
- layout: {
288
- type: "flex",
289
- direction: "column",
290
- align: "start",
291
- justify: "start",
292
- gap: "0.75rem"
293
- },
294
- interactions: {
295
- hover: !0,
296
- active: !0,
297
- focus: !0,
298
- hoverScale: 1.02,
299
- activeScale: 0.98
300
- }
301
- }, Le = {
302
- id: "minimal",
303
- name: "Minimal",
304
- description: "Clean, minimal design with no background effects",
305
- styles: {
306
- cssVars: {
307
- "--widget-bg": "transparent",
308
- "--widget-border": "rgba(255, 255, 255, 0.1)",
309
- "--widget-padding": "1rem"
310
- }
311
- },
312
- layout: {
313
- type: "flex",
314
- direction: "column",
315
- align: "start",
316
- justify: "start",
317
- gap: "0.5rem"
318
- },
319
- elements: {
320
- visible: {
321
- background: !1,
322
- decorations: !1
323
- }
324
- },
325
- interactions: {
326
- hover: !1,
327
- active: !1,
328
- focus: !0
329
- }
330
- }, Ue = {
331
- id: "compact-horizontal",
332
- name: "Compact Horizontal",
333
- description: "Horizontal layout for compact widgets",
334
- styles: {
335
- cssVars: {
336
- "--widget-bg": "rgba(255, 255, 255, 0.08)",
337
- "--widget-border": "rgba(255, 255, 255, 0.15)",
338
- "--widget-blur": "10px",
339
- "--widget-padding": "1rem",
340
- "--widget-icon-size": "2.5rem"
341
- },
342
- class: "backdrop-blur-lg"
343
- },
344
- layout: {
345
- type: "flex",
346
- direction: "row",
347
- align: "center",
348
- justify: "start",
349
- gap: "1rem"
350
- },
351
- interactions: {
352
- hover: !0,
353
- active: !0,
354
- focus: !0,
355
- hoverScale: 1.02,
356
- activeScale: 0.98
357
- }
358
- }, je = {
359
- "classic-glass": Ie,
360
- minimal: Le,
361
- "compact-horizontal": Ue
1
+ import { WidgetManifestSchema as e, formatSchemaError as t } from "./schemas.js";
2
+ import { z as n } from "zod";
3
+ import { getForecasts as r, getStream as i, getWebRtcClientConfig as a, hassMediaUrl as o, sendWebRtcCandidate as s, startWebRtcSession as c, state as l, trackEntityHistory as u, untrackEntityHistory as d } from "@glasshome/sync-layer";
4
+ import { byDomain as f, useArea as p, useCamera as m, useConnection as h, useCurrency as g, useEntities as _, useEntity as v, useEntityHistory as y, useEntityStatistics as b, useForecast as x, useHassConfig as ee, useLocale as S, useService as te, useStore as ne, useTemperatureUnit as re, useToggle as C, useTurnOff as ie, useTurnOn as ae, useUnitSystem as oe } from "@glasshome/sync-layer/solid";
5
+ import { Show as w, createContext as se, createEffect as T, createMemo as E, createSignal as D, on as ce, onCleanup as O, onMount as le, splitProps as ue, useContext as k } from "solid-js";
6
+ import { addEventListener as A, className as j, createComponent as M, delegateEvents as de, effect as N, insert as P, memo as F, setStyleProperty as I, style as L, template as R, use as fe } from "solid-js/web";
7
+ import { createElementSize as pe } from "@solid-primitives/resize-observer";
8
+ import { clsx as me } from "clsx";
9
+ import { twMerge as he } from "tailwind-merge";
10
+ //#region src/framework/to-form-schema.ts
11
+ function ge(e) {
12
+ return n.toJSONSchema(e, { override: (e) => {
13
+ let t = n.globalRegistry.get(e.zodSchema);
14
+ return t && typeof t == "object" && Object.keys(t).length > 0 ? {
15
+ ...e.jsonSchema,
16
+ ...t
17
+ } : e.jsonSchema;
18
+ } });
19
+ }
20
+ function _e(e) {
21
+ try {
22
+ return e.parse({});
23
+ } catch {
24
+ return {};
25
+ }
26
+ }
27
+ //#endregion
28
+ //#region src/define-widget.ts
29
+ function ve(e) {
30
+ return e.configSchema && (e.manifest.schema || (e.manifest.schema = ge(e.configSchema)), e.manifest.defaultConfig || (e.manifest.defaultConfig = _e(e.configSchema))), e;
31
+ }
32
+ //#endregion
33
+ //#region src/framework/hooks/use-widget-context.ts
34
+ var z = se();
35
+ function ye() {
36
+ let e = k(z);
37
+ if (!e) throw Error("useWidgetContext must be used within a Widget component");
38
+ return e;
39
+ }
40
+ //#endregion
41
+ //#region src/framework/hooks/use-service.ts
42
+ function be(e) {
43
+ let t = Array.isArray(e) ? e[0] : e, n = t?.split(".")[0];
44
+ if (!n) throw Error(`Invalid entity ID: ${String(t)}`);
45
+ return n;
46
+ }
47
+ function B(e, t) {
48
+ return (n, r = {}) => e(be(n), t, r, { entity_id: n });
49
+ }
50
+ function xe() {
51
+ let e = k(z)?.callService;
52
+ return e ? {
53
+ callService: e,
54
+ turnOn: B(e, "turn_on"),
55
+ turnOff: B(e, "turn_off"),
56
+ toggle: B(e, "toggle")
57
+ } : te();
58
+ }
59
+ function Se() {
60
+ let e = k(z)?.callService;
61
+ return e ? B(e, "turn_on") : ae();
62
+ }
63
+ function Ce() {
64
+ let e = k(z)?.callService;
65
+ return e ? B(e, "turn_off") : ie();
66
+ }
67
+ function we() {
68
+ let e = k(z)?.callService;
69
+ return e ? B(e, "toggle") : C();
70
+ }
71
+ //#endregion
72
+ //#region src/framework/design-system/z-index.ts
73
+ var V = {
74
+ BACKGROUND: 0,
75
+ CONTENT: 10,
76
+ OVERLAY: 20,
77
+ ACTIONS: 30
78
+ }, Te = "/* Authoritative SDK CSS contract. Injected once on first Widget mount\n * via framework/theming/tokens.ts.\n *\n * All widget-internal visual scale is driven from CSS custom properties +\n * container queries on the `.glasshome-widget` shell (`container-type: size`).\n * No JS classifier, no size tier enum.\n */\n\n:root {\n --tone-success: oklch(0.70 0.18 145);\n --tone-warning: oklch(0.80 0.17 75);\n --tone-danger: oklch(0.64 0.22 27);\n --tone-info: oklch(0.66 0.20 245);\n --tone-neutral: oklch(0.65 0.02 250);\n --tone-accent: oklch(0.74 0.18 60);\n\n --widget-grad-strength: 1;\n --widget-glow-default: 0.4;\n --widget-border-highlight: oklch(0.98 0 0 / 0.4);\n}\n\n.dark {\n --tone-success: oklch(0.74 0.18 145);\n --tone-warning: oklch(0.82 0.17 75);\n --tone-danger: oklch(0.68 0.22 27);\n --tone-info: oklch(0.70 0.20 245);\n --tone-neutral: oklch(0.69 0.02 250);\n --tone-accent: oklch(0.78 0.18 60);\n\n --widget-grad-strength: 1.1;\n --widget-glow-default: 0.5;\n --widget-border-highlight: oklch(1 0 0 / 0.08);\n}\n\n@property --widget-color {\n syntax: \"<color>\";\n inherits: true;\n initial-value: oklch(0.65 0.02 250);\n}\n\n/* === Widget shell ===\n * Fluid scale tokens — tied to the shell's own container box (cqmin/cqi/cqb).\n * Same input box → same output, so two widgets at the same grid cell match\n * exactly. Tune multipliers / clamps to adjust density. */\n.glasshome-widget {\n --widget-color: var(--tone-neutral);\n --widget-glow-strength: var(--widget-glow-default);\n\n --widget-icon-box: clamp(28px, 22cqmin, 64px);\n --widget-icon-glyph: clamp(16px, 13cqmin, 36px);\n --widget-pad: clamp(8px, 4cqmin, 24px);\n --widget-gap: clamp(6px, 2cqmin, 16px);\n --widget-title-size: clamp(12px, 2cqi, 18px);\n --widget-subtitle: clamp(12px, 2.5cqi, 20px);\n --widget-status-size: clamp(14px, 5cqi, 36px);\n --widget-value-size: clamp(18px, 7cqi, 48px);\n --widget-badge-size: clamp(11px, 1.6cqi, 14px);\n}\n\n.glasshome-widget {\n background: var(--widget-gradient,\n linear-gradient(135deg,\n color-mix(in oklch, var(--widget-color) calc(22% * var(--widget-grad-strength)), transparent),\n color-mix(in oklch, var(--widget-color-to, var(--widget-color)) calc(11% * var(--widget-grad-strength)), transparent)\n )\n );\n box-shadow: inset 0 1px 0 var(--widget-border-highlight);\n}\n\n/* === Slot: content layout === */\n/* Default: column. Flip to row only on wide-and-short widgets (matches the\n * old contentLayout heuristic: aspect > 1 AND height < 150px). */\n.glasshome-widget-content {\n position: relative;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n width: 100%;\n height: 100%;\n padding: var(--widget-pad);\n gap: var(--widget-gap);\n overflow: hidden;\n}\n@container widget (min-aspect-ratio: 1) and (max-height: 149px) {\n .glasshome-widget-content {\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n }\n}\n.glasshome-widget-content [class*=\"ml-auto\"] {\n position: relative;\n z-index: 30;\n}\n\n/* === Slot: icon === */\n.glasshome-widget-icon {\n width: var(--widget-icon-box);\n height: var(--widget-icon-box);\n border-radius: var(--radius-sm, 12px);\n background: var(--widget-icon-color, var(--widget-color));\n box-shadow: 0 0 calc(var(--widget-glow-strength) * 30px)\n color-mix(in oklch, var(--widget-icon-color, var(--widget-color)) 50%, transparent);\n color: oklch(from var(--widget-icon-color, var(--widget-color)) calc(0.52 + sign(0.5 - l) * 0.43) calc(c * 0.2) h);\n}\n.glasshome-widget-icon-glyph {\n font-size: var(--widget-icon-glyph);\n line-height: 1;\n}\n.glasshome-widget-icon-stack {\n position: absolute;\n width: 102%;\n height: 102%;\n border-radius: var(--radius-sm, 12px);\n}\n.glasshome-widget-icon-stack-2 { bottom: -14%; right: -10%; opacity: 0.45; z-index: -2; }\n.glasshome-widget-icon-stack-3 { bottom: -28%; right: -20%; opacity: 0.20; z-index: -3; }\n\n/* === Slot: text === */\n.glasshome-widget-title {\n font-size: var(--widget-title-size);\n line-height: 1.2;\n color: color-mix(in oklch, var(--color-foreground, currentColor) 60%, transparent);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.glasshome-widget-subtitle {\n font-size: var(--widget-subtitle);\n color: color-mix(in oklch, var(--color-foreground, currentColor) 60%, transparent);\n}\n.glasshome-widget-status {\n font-size: var(--widget-status-size);\n font-weight: 700;\n color: var(--color-foreground, currentColor);\n line-height: 1.1;\n}\n.glasshome-widget-value {\n font-size: var(--widget-value-size);\n font-weight: 700;\n color: var(--color-foreground, currentColor);\n line-height: 1.05;\n}\n.glasshome-widget-badge {\n font-size: var(--widget-badge-size);\n font-weight: 500;\n padding: 0.125rem 0.5rem;\n border-radius: 9999px;\n background: color-mix(in oklch, var(--color-foreground, currentColor) 20%, transparent);\n color: var(--color-foreground, currentColor);\n}\n\n.glasshome-widget-loading {\n background: color-mix(in oklch, var(--widget-color) 20%, transparent);\n}\n\n/* === Slider fill ===\n * Value flows in via --widget-fill-value (0-100). Vertical orientation auto-\n * detected via container query. */\n.glasshome-widget-slider-fill {\n --widget-fill-value: 0;\n background: color-mix(in oklch, var(--widget-icon-color, var(--widget-color)) 30%, transparent);\n box-shadow: 0 0 calc(var(--widget-glow-strength) * 40px)\n color-mix(in oklch, var(--widget-icon-color, var(--widget-color)) 40%, transparent);\n clip-path: inset(0 calc((100 - var(--widget-fill-value)) * 1%) 0 0);\n}\n@container widget (max-aspect-ratio: 1) {\n .glasshome-widget-slider-fill {\n clip-path: inset(calc((100 - var(--widget-fill-value)) * 1%) 0 0 0);\n }\n}\n", Ee = !1, H, De = /* @__PURE__ */ new WeakSet();
79
+ function Oe() {
80
+ return H || (H = new CSSStyleSheet(), H.replaceSync(Te.replace(/:root\b/g, ":host").replace(/^\.dark\b/gm, ":host(.dark)"))), H;
81
+ }
82
+ function ke(e) {
83
+ if (typeof ShadowRoot < "u" && e instanceof ShadowRoot) {
84
+ if (De.has(e)) return;
85
+ let t = Oe();
86
+ e.adoptedStyleSheets.includes(t) || (e.adoptedStyleSheets = [...e.adoptedStyleSheets, t]), De.add(e);
87
+ return;
88
+ }
89
+ if (Ee) return;
90
+ let t = e ?? (typeof document > "u" ? void 0 : document);
91
+ if (!t) return;
92
+ if (t.head.querySelector?.("style[data-glasshome-tokens]")) {
93
+ Ee = !0;
94
+ return;
95
+ }
96
+ let n = t.createElement("style");
97
+ n.setAttribute("data-glasshome-tokens", ""), n.textContent = Te, t.head.appendChild(n), Ee = !0;
98
+ }
99
+ //#endregion
100
+ //#region src/framework/utils/cn.ts
101
+ function U(...e) {
102
+ return he(me(e));
103
+ }
104
+ var Ae = {
105
+ "classic-glass": {
106
+ id: "classic-glass",
107
+ name: "Classic Glass",
108
+ description: "Default glassmorphism design with blur background and gradient",
109
+ styles: {
110
+ cssVars: {
111
+ "--widget-bg": "rgba(255, 255, 255, 0.1)",
112
+ "--widget-border": "rgba(255, 255, 255, 0.2)",
113
+ "--widget-blur": "12px",
114
+ "--widget-shadow": "0 8px 32px rgba(0, 0, 0, 0.2)",
115
+ "--widget-padding": "1.5rem"
116
+ },
117
+ class: "backdrop-blur-xl"
118
+ },
119
+ layout: {
120
+ type: "flex",
121
+ direction: "column",
122
+ align: "start",
123
+ justify: "start",
124
+ gap: "0.75rem"
125
+ },
126
+ interactions: {
127
+ hover: !0,
128
+ active: !0,
129
+ focus: !0,
130
+ hoverScale: 1.02,
131
+ activeScale: .98
132
+ }
133
+ },
134
+ minimal: {
135
+ id: "minimal",
136
+ name: "Minimal",
137
+ description: "Clean, minimal design with no background effects",
138
+ styles: { cssVars: {
139
+ "--widget-bg": "transparent",
140
+ "--widget-border": "rgba(255, 255, 255, 0.1)",
141
+ "--widget-padding": "1rem"
142
+ } },
143
+ layout: {
144
+ type: "flex",
145
+ direction: "column",
146
+ align: "start",
147
+ justify: "start",
148
+ gap: "0.5rem"
149
+ },
150
+ elements: { visible: {
151
+ background: !1,
152
+ decorations: !1
153
+ } },
154
+ interactions: {
155
+ hover: !1,
156
+ active: !1,
157
+ focus: !0
158
+ }
159
+ },
160
+ "compact-horizontal": {
161
+ id: "compact-horizontal",
162
+ name: "Compact Horizontal",
163
+ description: "Horizontal layout for compact widgets",
164
+ styles: {
165
+ cssVars: {
166
+ "--widget-bg": "rgba(255, 255, 255, 0.08)",
167
+ "--widget-border": "rgba(255, 255, 255, 0.15)",
168
+ "--widget-blur": "10px",
169
+ "--widget-padding": "1rem",
170
+ "--widget-icon-size": "2.5rem"
171
+ },
172
+ class: "backdrop-blur-lg"
173
+ },
174
+ layout: {
175
+ type: "flex",
176
+ direction: "row",
177
+ align: "center",
178
+ justify: "start",
179
+ gap: "1rem"
180
+ },
181
+ interactions: {
182
+ hover: !0,
183
+ active: !0,
184
+ focus: !0,
185
+ hoverScale: 1.02,
186
+ activeScale: .98
187
+ }
188
+ }
362
189
  };
363
- function Be(e) {
364
- return je[e];
365
- }
366
- var Fe = /* @__PURE__ */ x("<div>");
367
- function Ge(e) {
368
- return (() => {
369
- var t = Fe();
370
- return W((i) => {
371
- var r = R("glasshome-widget-slider-fill pointer-events-none absolute inset-0", e.isDragging ? "duration-0" : "transition-all duration-300 ease-out", e.class), n = {
372
- "--widget-fill-value": e.value,
373
- "z-index": J.BACKGROUND,
374
- ...e.color ? {
375
- "--widget-icon-color": e.color
376
- } : {}
377
- };
378
- return r !== i.e && I(t, i.e = r), i.t = le(t, n, i.t), i;
379
- }, {
380
- e: void 0,
381
- t: void 0
382
- }), t;
383
- })();
384
- }
385
- var qe = /* @__PURE__ */ x("<div>");
386
- function Ye(e) {
387
- return (() => {
388
- var t = qe();
389
- return p(t, () => e.children), W(() => I(t, R("glasshome-widget-content", e.class))), t;
390
- })();
391
- }
392
- var Ke = /* @__PURE__ */ x('<div class="glasshome-widget-icon glasshome-widget-icon-stack glasshome-widget-icon-stack-2">'), Xe = /* @__PURE__ */ x('<div class="glasshome-widget-icon glasshome-widget-icon-stack glasshome-widget-icon-stack-3">'), Je = /* @__PURE__ */ x('<div><div class="glasshome-widget-icon-glyph flex items-center justify-center">');
393
- function Qe(e) {
394
- const t = () => e.entityCount ?? 1;
395
- return (() => {
396
- var i = Je(), r = i.firstChild;
397
- return p(i, k(E, {
398
- get when() {
399
- return t() >= 2;
400
- },
401
- get children() {
402
- return Ke();
403
- }
404
- }), r), p(i, k(E, {
405
- get when() {
406
- return t() >= 3;
407
- },
408
- get children() {
409
- return Xe();
410
- }
411
- }), r), p(r, () => e.icon), W((n) => {
412
- var o = R("glasshome-widget-icon", "relative flex shrink-0 items-center justify-center pointer-events-none transition-all", e.dimmed && "opacity-50", e.class), u = e.color ? {
413
- "--widget-icon-color": e.color
414
- } : void 0;
415
- return o !== n.e && I(i, n.e = o), n.t = le(i, u, n.t), n;
416
- }, {
417
- e: void 0,
418
- t: void 0
419
- }), i;
420
- })();
421
- }
422
- var Ze = /* @__PURE__ */ x("<p>");
423
- function et(e) {
424
- return (() => {
425
- var t = Ze();
426
- return p(t, (() => {
427
- var i = T(() => !!e.isUnavailable);
428
- return () => i() ? "Unavailable" : e.children;
429
- })()), W((i) => {
430
- var r = R("glasshome-widget-status", "relative", e.dimmed && "opacity-40", e.class), n = J.ACTIONS;
431
- return r !== i.e && I(t, i.e = r), n !== i.t && ee(t, "z-index", i.t = n), i;
432
- }, {
433
- e: void 0,
434
- t: void 0
435
- }), t;
436
- })();
437
- }
438
- var tt = /* @__PURE__ */ x('<span class="glasshome-widget-badge shrink-0">'), nt = /* @__PURE__ */ x("<div><h3 class=glasshome-widget-title>");
439
- function it(e) {
440
- return (() => {
441
- var t = nt(), i = t.firstChild;
442
- return p(i, () => e.children), p(t, k(E, {
443
- get when() {
444
- return T(() => e.badge !== void 0)() && e.badge > 0;
445
- },
446
- get children() {
447
- var r = tt();
448
- return p(r, () => e.badge), r;
449
- }
450
- }), null), W((r) => {
451
- var n = R("relative flex items-center gap-2", e.class), o = J.ACTIONS;
452
- return n !== r.e && I(t, r.e = n), o !== r.t && ee(t, "z-index", r.t = o), r;
453
- }, {
454
- e: void 0,
455
- t: void 0
456
- }), t;
457
- })();
458
- }
459
- function rt(e, t = !1) {
460
- if (e.length === 0)
461
- return {
462
- isGroup: !1,
463
- state: "unknown",
464
- isOn: !1,
465
- isUnavailable: !0,
466
- brightness: 0,
467
- brightnessPercent: 0,
468
- color: "rgb(100, 100, 100)",
469
- onCount: 0,
470
- totalCount: 0,
471
- description: "No entities"
472
- };
473
- const i = e.length > 1;
474
- if (!i) {
475
- const s = e[0], f = s.state === "on", b = s.attributes?.brightness || 0, C = Math.round(b / 255 * 100);
476
- return {
477
- isGroup: !1,
478
- state: s.state,
479
- isOn: f,
480
- isUnavailable: s.state === "unavailable",
481
- brightness: b,
482
- brightnessPercent: C,
483
- color: fe(s),
484
- onCount: f ? 1 : 0,
485
- totalCount: 1,
486
- description: f ? "On" : "Off"
487
- };
488
- }
489
- let r = 0, n = 0, o = 0, u = 0, d = 0, $ = 0;
490
- const m = [];
491
- for (const s of e)
492
- switch (s.state) {
493
- case "on":
494
- r++, s.attributes?.brightness !== void 0 && (d += s.attributes.brightness, $++), s.attributes?.rgb_color && m.push(s.attributes.rgb_color);
495
- break;
496
- case "off":
497
- n++;
498
- break;
499
- case "unknown":
500
- o++;
501
- break;
502
- case "unavailable":
503
- u++;
504
- break;
505
- }
506
- const h = e.length, v = u === h, y = o + u === h, g = r > 0, a = r === h, S = n === h;
507
- let w, M;
508
- t ? v ? (w = "unavailable", M = !1) : o > 0 || u > 0 ? (w = "unknown", M = !1) : n > 0 ? (w = "off", M = !1) : (w = "on", M = !0) : v ? (w = "unavailable", M = !1) : y ? (w = "unknown", M = !1) : g ? (w = "on", M = !0) : (w = "off", M = !1);
509
- const O = $ > 0 ? Math.round(d / $) : 0, L = Math.round(O / 255 * 100);
510
- let F;
511
- if (m.length > 0) {
512
- const s = Math.round(m.reduce((z, D) => z + D[0], 0) / m.length), f = Math.round(m.reduce((z, D) => z + D[1], 0) / m.length), b = Math.round(m.reduce((z, D) => z + D[2], 0) / m.length), C = O / 255;
513
- F = `rgb(${Math.round(s * C)}, ${Math.round(f * C)}, ${Math.round(b * C)})`;
514
- } else
515
- F = fe(e[0]);
516
- let H;
517
- return a ? H = "All on" : S ? H = "All off" : r > 0 ? H = `${r} of ${h} on` : H = "Off", {
518
- isGroup: i,
519
- state: w,
520
- isOn: M,
521
- isUnavailable: w === "unavailable",
522
- brightness: O,
523
- brightnessPercent: L,
524
- color: F,
525
- onCount: r,
526
- totalCount: h,
527
- description: H
528
- };
529
- }
530
- function ot(e, t = "mean", i = !0) {
531
- if (e.length === 0)
532
- return {
533
- isGroup: !1,
534
- state: "unknown",
535
- numericValue: null,
536
- isUnavailable: !0,
537
- description: "No entities"
538
- };
539
- const r = e.length > 1;
540
- if (!r) {
541
- const g = e[0], a = Number.parseFloat(g.state);
542
- let S = g.state;
543
- return Number.isNaN(a) || (S = Number.isInteger(a) ? a.toString() : a.toFixed(1)), {
544
- isGroup: !1,
545
- state: S,
546
- numericValue: Number.isNaN(a) ? null : a,
547
- isUnavailable: g.state === "unavailable",
548
- unit: g.unitOfMeasurement ?? void 0,
549
- description: S
550
- };
551
- }
552
- const n = [], o = [];
553
- let u = 0, d;
554
- for (const g of e) {
555
- if (!d && g.unitOfMeasurement && (d = g.unitOfMeasurement), g.state === "unavailable") {
556
- u++, o.push({
557
- entityId: g.id,
558
- value: "unavailable",
559
- friendly_name: g.friendlyName
560
- });
561
- continue;
562
- }
563
- const a = Number.parseFloat(g.state);
564
- isNaN(a) ? i || o.push({
565
- entityId: g.id,
566
- value: g.state,
567
- friendly_name: g.friendlyName
568
- }) : (n.push(a), o.push({
569
- entityId: g.id,
570
- value: a,
571
- friendly_name: g.friendlyName
572
- }));
573
- }
574
- const $ = u === e.length, m = n.length === 0;
575
- if ($ || m)
576
- return {
577
- isGroup: r,
578
- state: $ ? "unavailable" : "unknown",
579
- numericValue: null,
580
- isUnavailable: $,
581
- unit: d,
582
- description: $ ? "Unavailable" : "No numeric values",
583
- memberValues: o
584
- };
585
- let h, v;
586
- switch (t) {
587
- case "min":
588
- h = Math.min(...n), v = "Minimum";
589
- break;
590
- case "max":
591
- h = Math.max(...n), v = "Maximum";
592
- break;
593
- case "mean":
594
- h = n.reduce((g, a) => g + a, 0) / n.length, v = "Average";
595
- break;
596
- case "median": {
597
- const g = [...n].sort((S, w) => S - w), a = Math.floor(g.length / 2);
598
- h = g.length % 2 === 0 ? (g[a - 1] + g[a]) / 2 : g[a], v = "Median";
599
- break;
600
- }
601
- case "sum":
602
- h = n.reduce((g, a) => g + a, 0), v = "Sum";
603
- break;
604
- case "last":
605
- h = n[n.length - 1], v = "Latest";
606
- break;
607
- case "range":
608
- h = Math.max(...n) - Math.min(...n), v = "Range";
609
- break;
610
- case "product":
611
- h = n.reduce((g, a) => g * a, 1), v = "Product";
612
- break;
613
- case "std_dev": {
614
- const g = n.reduce((S, w) => S + w, 0) / n.length, a = n.reduce((S, w) => S + (w - g) ** 2, 0) / n.length;
615
- h = Math.sqrt(a), v = "Std Dev";
616
- break;
617
- }
618
- default:
619
- h = n.reduce((g, a) => g + a, 0) / n.length, v = "Average";
620
- }
621
- const y = Number.isInteger(h) ? h.toString() : h.toFixed(1);
622
- return {
623
- isGroup: r,
624
- state: y,
625
- numericValue: h,
626
- isUnavailable: !1,
627
- unit: d,
628
- description: `${v} of ${n.length}`,
629
- memberValues: o
630
- };
631
- }
632
- function fe(e) {
633
- if (e.state !== "on") return "rgb(100, 100, 100)";
634
- const i = (e.attributes?.brightness ?? 255) / 255;
635
- if (e.attributes?.rgb_color) {
636
- const [r, n, o] = e.attributes.rgb_color;
637
- return `rgb(${Math.round(r * i)}, ${Math.round(n * i)}, ${Math.round(o * i)})`;
638
- }
639
- if (e.attributes?.color_temp) {
640
- const n = 1e6 / e.attributes.color_temp / 100;
641
- let o, u, d;
642
- return n <= 66 ? (o = 255, u = n <= 19 ? 0 : 99.4708025861 * Math.log(n - 10) - 161.1195681661, d = n <= 19 ? 0 : n <= 66 ? 138.5177312231 * Math.log(n - 10) - 305.0447927307 : 255) : (o = 329.698727446 * (n - 60) ** -0.1332047592, u = 288.1221695283 * (n - 60) ** -0.0755148492, d = 255), o = Math.max(0, Math.min(255, o)) * i, u = Math.max(0, Math.min(255, u)) * i, d = Math.max(0, Math.min(255, d)) * i, `rgb(${Math.round(o)}, ${Math.round(u)}, ${Math.round(d)})`;
643
- }
644
- return `rgb(${Math.round(255 * i)}, ${Math.round(220 * i)}, ${Math.round(180 * i)})`;
645
- }
646
- function at(e) {
647
- if (!e) return !1;
648
- if (["on", "open", "locked", "home", "playing", "active"].includes(e.state))
649
- return !0;
650
- if (e.domain === "sensor") {
651
- const t = Number.parseFloat(e.state);
652
- return !isNaN(t) && t > 0;
653
- }
654
- return !1;
655
- }
656
- function rn(e, t, i) {
657
- return e?.attributes ? e.attributes[t] ?? i : i;
658
- }
659
- function on(e) {
660
- return e.filter(at).length;
661
- }
662
- function st(e, t, i) {
663
- const { decimals: r, scale: n = !0 } = {};
664
- if (typeof e == "string")
665
- return t ? `${e}${t}` : e;
666
- if (e == null || Number.isNaN(e))
667
- return t ? `--${t}` : "--";
668
- let o = e, u = t || "";
669
- n && t && (t === "W" || t === "kW" || t === "MW") && (e >= 1e6 ? (o = e / 1e6, u = "MW") : e >= 1e3 ? (o = e / 1e3, u = "kW") : u = "W"), n && t && (t === "B" || t === "KB" || t === "MB" || t === "GB") && (e >= 1073741824 ? (o = e / 1073741824, u = "GB") : e >= 1048576 ? (o = e / 1048576, u = "MB") : e >= 1024 ? (o = e / 1024, u = "KB") : u = "B");
670
- let d;
671
- return r !== void 0 ? d = o.toFixed(r) : o !== e ? d = o.toFixed(1) : Number.isInteger(e) ? d = e.toString() : d = Number.parseFloat(e.toFixed(2)).toString(), u ? `${d}${u}` : d;
672
- }
673
- function lt(e, t) {
674
- return e == null || isNaN(e) ? null : t === "°C" ? e < 10 ? "Cold" : e < 18 ? "Cool" : e < 24 ? "Comfortable" : e < 28 ? "Warm" : "Hot" : t === "°F" ? e < 50 ? "Cold" : e < 64 ? "Cool" : e < 75 ? "Comfortable" : e < 82 ? "Warm" : "Hot" : t === "%" ? e < 20 ? "Very Low" : e < 40 ? "Low" : e < 60 ? "Medium" : e < 80 ? "High" : "Very High" : t === "ppm" ? e < 400 ? "Excellent" : e < 600 ? "Good" : e < 1e3 ? "Acceptable" : e < 1500 ? "Mediocre" : "Poor" : t === "lx" ? e < 50 ? "Dark" : e < 200 ? "Dim" : e < 500 ? "Moderate" : e < 1e3 ? "Bright" : "Very Bright" : t === "AQI" ? e <= 50 ? "Good" : e <= 100 ? "Moderate" : e <= 150 ? "Unhealthy for Sensitive" : e <= 200 ? "Unhealthy" : e <= 300 ? "Very Unhealthy" : "Hazardous" : t === "dB" ? e < 30 ? "Very Quiet" : e < 50 ? "Quiet" : e < 70 ? "Moderate" : e < 85 ? "Loud" : "Very Loud" : null;
675
- }
676
- var ct = /* @__PURE__ */ x("<div class=glasshome-widget-subtitle>"), dt = /* @__PURE__ */ x("<div><div class=glasshome-widget-value>");
677
- function ut(e) {
678
- return (() => {
679
- var t = dt(), i = t.firstChild;
680
- return p(i, () => st(e.value, e.unit)), p(t, k(E, {
681
- get when() {
682
- return T(() => !!e.interpret)() && typeof e.value == "number";
683
- },
684
- get children() {
685
- var r = ct();
686
- return p(r, () => lt(e.value, e.unit)), r;
687
- }
688
- }), null), W(() => I(t, R("flex flex-col", e.class))), t;
689
- })();
690
- }
691
- var gt = /* @__PURE__ */ x('<div><div class="relative h-full w-full">'), ht = /* @__PURE__ */ x('<div class="glasshome-widget-loading pointer-events-none absolute inset-0 animate-pulse">'), ft = /* @__PURE__ */ x('<div class="flex h-full w-full flex-col items-center justify-center gap-2 text-center">'), mt = /* @__PURE__ */ x('<div class="flex items-center justify-center text-white/30">'), vt = /* @__PURE__ */ x('<h3 class="font-semibold text-sm text-white/60">'), wt = /* @__PURE__ */ x('<p class="text-white/50 text-xs">');
692
- function pt(e) {
693
- const t = B(P), [i, r] = V(), n = Me(i);
694
- Te(() => {
695
- const a = i()?.getRootNode();
696
- Pe(typeof ShadowRoot < "u" && a instanceof ShadowRoot || typeof Document < "u" && a instanceof Document ? a : void 0);
697
- });
698
- const o = {
699
- isEditMode: () => e.isEditMode ?? !1,
700
- updateConfig: t?.updateConfig ?? (() => {
701
- }),
702
- registerDialogOpener: t?.registerDialogOpener,
703
- callService: t?.callService,
704
- dimensions: () => ({
705
- width: n.width ?? 0,
706
- height: n.height ?? 0
707
- })
708
- }, u = j(() => {
709
- if (e.variant)
710
- return typeof e.variant == "string" ? Be(e.variant) : e.variant;
711
- }), d = j(() => ({
712
- "container-type": "size",
713
- "container-name": "widget",
714
- "touch-action": e.gestures && !e.isEditMode ? e.gestures.touchAction() : void 0,
715
- ...u()?.styles?.container,
716
- ...u()?.styles?.cssVars || {},
717
- ...e.tone ? {
718
- "--widget-color": `var(--tone-${e.tone})`
719
- } : {},
720
- ...e.color ? {
721
- "--widget-color": e.color
722
- } : {},
723
- ...e.colorTo ? {
724
- "--widget-color-to": e.colorTo
725
- } : {},
726
- ...e.gradient ? {
727
- "--widget-gradient": e.gradient
728
- } : {}
729
- })), $ = () => !!e.gestures && !e.isEditMode, m = (a) => {
730
- $() && e.gestures?.onPointerEnter(a);
731
- }, h = (a) => {
732
- $() && e.gestures?.onPointerDown(a);
733
- }, v = (a) => {
734
- $() && e.gestures?.onPointerMove(a);
735
- }, y = (a) => {
736
- $() && e.gestures?.onPointerUp(a);
737
- }, g = (a) => {
738
- $() && e.gestures?.onPointerCancel(a);
739
- };
740
- return k(P.Provider, {
741
- value: o,
742
- get children() {
743
- var a = gt(), S = a.firstChild;
744
- return K(a, "pointercancel", g), K(a, "pointerup", y), K(a, "pointermove", v), K(a, "pointerdown", h), K(a, "pointerenter", m), Ce((w) => {
745
- r(w), e.gestures?.bindElement(w);
746
- }, a), p(S, (() => {
747
- var w = T(() => !!e.emptyState);
748
- return () => w() ? k(bt, {
749
- get icon() {
750
- return e.emptyState.icon;
751
- },
752
- get title() {
753
- return e.emptyState.title;
754
- },
755
- get message() {
756
- return e.emptyState.message;
757
- }
758
- }) : e.children;
759
- })()), p(a, (() => {
760
- var w = T(() => !!e.loading);
761
- return () => w() && (() => {
762
- var M = ht();
763
- return W((O) => ee(M, "z-index", J.OVERLAY)), M;
764
- })();
765
- })(), null), W((w) => {
766
- var M = R("glasshome-widget", "relative h-full w-full select-none overflow-hidden rounded-xl border border-border/50", u()?.styles?.class, e.class), O = d(), L = J.CONTENT;
767
- return M !== w.e && I(a, w.e = M), w.t = le(a, O, w.t), L !== w.a && ee(S, "z-index", w.a = L), w;
768
- }, {
769
- e: void 0,
770
- t: void 0,
771
- a: void 0
772
- }), a;
773
- }
774
- });
775
- }
776
- function bt(e) {
777
- return (() => {
778
- var t = ft();
779
- return p(t, (() => {
780
- var i = T(() => !!e.icon);
781
- return () => i() && (() => {
782
- var r = mt();
783
- return p(r, () => e.icon), r;
784
- })();
785
- })(), null), p(t, (() => {
786
- var i = T(() => !!e.title);
787
- return () => i() && (() => {
788
- var r = vt();
789
- return p(r, () => e.title), r;
790
- })();
791
- })(), null), p(t, (() => {
792
- var i = T(() => !!e.message);
793
- return () => i() && (() => {
794
- var r = wt();
795
- return p(r, () => e.message), r;
796
- })();
797
- })(), null), t;
798
- })();
799
- }
800
- const q = pt;
801
- q.Content = Ye;
802
- q.Icon = Qe;
803
- q.Title = it;
804
- q.Status = et;
805
- q.Value = ut;
806
- q.SliderFill = Ge;
807
- var xt = /* @__PURE__ */ x('<span class="inline-flex size-3.5 shrink-0 items-center">'), yt = /* @__PURE__ */ x("<button type=button>"), $t = /* @__PURE__ */ x('<svg xmlns=http://www.w3.org/2000/svg class=size-3.5 fill=none viewBox="0 0 24 24"stroke=currentColor stroke-width=2><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z">'), kt = /* @__PURE__ */ x('<div class="rounded-lg bg-muted/30 p-2 text-center md:p-6"><p class="text-muted-foreground text-sm">No edit options available'), Ct = /* @__PURE__ */ x('<svg xmlns=http://www.w3.org/2000/svg class=size-3.5 fill=none viewBox="0 0 24 24"stroke=currentColor stroke-width=2><line x1=4 y1=21 x2=4 y2=14></line><line x1=4 y1=10 x2=4 y2=3></line><line x1=12 y1=21 x2=12 y2=12></line><line x1=12 y1=8 x2=12 y2=3></line><line x1=20 y1=21 x2=20 y2=16></line><line x1=20 y1=12 x2=20 y2=3></line><line x1=1 y1=14 x2=7 y2=14></line><line x1=9 y1=8 x2=15 y2=8></line><line x1=17 y1=16 x2=23 y2=16>'), St = /* @__PURE__ */ x('<div class="rounded-lg bg-muted/30 p-2 text-center md:p-6"><p class="text-muted-foreground text-sm">No additional controls'), Mt = /* @__PURE__ */ x('<svg xmlns=http://www.w3.org/2000/svg class=size-3.5 fill=none viewBox="0 0 24 24"stroke=currentColor stroke-width=2><path d="m8 2 1.88 1.88"></path><path d="M14.12 3.88 16 2"></path><path d="M9 7.13v-1a3.003 3.003 0 1 1 6 0v1"></path><path d="M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6"></path><path d="M12 20v-9"></path><path d="M6.53 9C4.6 8.8 3 7.1 3 5"></path><path d="M6 13H2"></path><path d="M3 21c0-2.1 1.7-3.9 3.8-4"></path><path d="M20.97 5c0 2.1-1.6 3.8-3.5 4"></path><path d="M22 13h-4"></path><path d="M17.2 17c2.1.1 3.8 1.9 3.8 4">'), Dt = /* @__PURE__ */ x('<div class="rounded-lg bg-muted/30 p-2 text-center md:p-6"><p class="text-muted-foreground text-sm">No debug information available'), Tt = /* @__PURE__ */ x('<div class="min-w-0 shrink-0">'), _t = /* @__PURE__ */ x('<div class="flex items-center gap-2"><div class="flex h-8 items-center rounded-lg border border-border/50 bg-muted/30 p-0.5">'), Ot = /* @__PURE__ */ x('<div class="min-h-0 flex-1 overflow-y-auto [scrollbar-gutter:stable]">'), zt = /* @__PURE__ */ x('<div class="flex shrink-0 items-center justify-end gap-2 border-border/50 border-t pt-3">');
808
- function Et(e) {
809
- return (() => {
810
- var t = yt();
811
- return t.$$click = () => e.onClick(), p(t, k(E, {
812
- get when() {
813
- return e.isActive;
814
- },
815
- get children() {
816
- var i = xt();
817
- return p(i, () => e.icon), i;
818
- }
819
- }), null), p(t, () => e.label, null), W(() => I(t, R("flex cursor-pointer items-center justify-center rounded-md px-3 py-1.5 text-xs transition-all duration-300 ease-in-out", e.isActive ? "gap-1.5 bg-foreground/10 font-semibold text-foreground shadow-sm" : "gap-0 text-muted-foreground hover:bg-foreground/5 hover:text-foreground"))), t;
820
- })();
821
- }
822
- function an(e) {
823
- const [t] = _e(e, ["open", "onOpenChange", "title", "onSave", "hasUnsavedChanges", "onDelete", "editContent", "controlsContent", "debugContent", "debugData", "tabs", "class", "maxWidth", "defaultTab", "activeTab", "onActiveTabChange", "headerActions", "configSchema", "config", "onConfigSave", "ResponsiveDialog", "ResponsiveDialogContent", "ResponsiveDialogHeader", "ResponsiveDialogTitle", "ResponsiveDialogDescription", "Button", "SchemaForm"]), i = () => !!t.configSchema && !!t.config && !!t.onConfigSave && !!t.SchemaForm, [r, n] = V({}), [o, u] = V(null);
824
- se(ge(() => t.config, (c) => {
825
- c && n({
826
- ...c
827
- });
828
- })), se(ge(() => t.configSchema, (c) => {
829
- c && u(me(c));
830
- }));
831
- const d = () => i() && JSON.stringify(r()) !== JSON.stringify(t.config), $ = (c) => {
832
- !c && t.config && n({
833
- ...t.config
834
- }), t.onOpenChange(c);
835
- }, m = () => {
836
- t.onConfigSave?.(r());
837
- }, [h, v] = V(t.defaultTab ?? "controls"), y = () => t.activeTab ?? h(), g = (c) => {
838
- t.onActiveTabChange ? t.onActiveTabChange(c) : v(c);
839
- }, a = () => {
840
- const c = t.maxWidth ?? "3xl";
841
- return {
842
- sm: "max-w-sm",
843
- md: "max-w-md",
844
- lg: "max-w-lg",
845
- xl: "max-w-xl",
846
- "2xl": "max-w-2xl",
847
- "3xl": "max-w-3xl",
848
- "4xl": "max-w-4xl"
849
- }[c];
850
- }, S = () => {
851
- if (t.tabs) return t.tabs;
852
- const c = [];
853
- return c.push({
854
- id: "edit",
855
- label: "Edit",
856
- icon: $t(),
857
- content: t.editContent ?? (i() && o() ? k(b, {
858
- get schema() {
859
- return o();
860
- },
861
- get data() {
862
- return r();
863
- },
864
- onChange: n
865
- }) : kt())
866
- }), c.push({
867
- id: "controls",
868
- label: "Controls",
869
- icon: Ct(),
870
- content: t.controlsContent ?? St()
871
- }), c.push({
872
- id: "debug",
873
- label: "Debug",
874
- icon: Mt(),
875
- content: t.debugContent ?? Dt()
876
- }), c;
877
- }, w = async () => {
878
- if (t.debugData !== void 0)
879
- try {
880
- const c = typeof t.debugData == "string" ? t.debugData : JSON.stringify(t.debugData, null, 2);
881
- await navigator.clipboard.writeText(c);
882
- } catch {
883
- }
884
- }, M = () => {
885
- const c = S();
886
- return c.find((N) => N.id === y())?.content ?? c[0]?.content;
887
- }, O = t.ResponsiveDialog, L = t.ResponsiveDialogContent, F = t.ResponsiveDialogHeader, H = t.ResponsiveDialogTitle, s = t.ResponsiveDialogDescription, f = t.Button, b = t.SchemaForm, C = (c) => i() ? $(c) : t.onOpenChange(c), z = () => i() ? d() : t.hasUnsavedChanges, D = () => i() ? m : t.onSave;
888
- return k(O, {
889
- get open() {
890
- return t.open;
891
- },
892
- onOpenChange: (c) => C(c),
893
- get children() {
894
- return k(L, {
895
- get class() {
896
- return R(a(), t.class);
897
- },
898
- get children() {
899
- return [k(F, {
900
- class: "flex flex-row items-center justify-between gap-3",
901
- get children() {
902
- return [(() => {
903
- var c = Tt();
904
- return p(c, k(H, {
905
- class: "truncate leading-tight",
906
- get children() {
907
- return t.title;
908
- }
909
- }), null), p(c, k(s, {
910
- class: "sr-only",
911
- children: "Widget configuration dialog"
912
- }), null), c;
913
- })(), (() => {
914
- var c = _t(), Y = c.firstChild;
915
- return p(Y, () => S().map((N) => k(Et, {
916
- get icon() {
917
- return N.icon;
918
- },
919
- get label() {
920
- return N.label;
921
- },
922
- get isActive() {
923
- return y() === N.id;
924
- },
925
- onClick: () => g(N.id)
926
- }))), p(c, k(E, {
927
- get when() {
928
- return t.headerActions;
929
- },
930
- get children() {
931
- return t.headerActions;
932
- }
933
- }), null), c;
934
- })()];
935
- }
936
- }), (() => {
937
- var c = Ot();
938
- return p(c, M), c;
939
- })(), k(E, {
940
- get when() {
941
- return T(() => y() === "edit")() && (D() || t.onDelete) || y() === "debug" && t.debugData !== void 0;
942
- },
943
- get children() {
944
- var c = zt();
945
- return p(c, k(E, {
946
- get when() {
947
- return T(() => y() === "edit")() && t.onDelete;
948
- },
949
- get children() {
950
- return k(f, {
951
- size: "sm",
952
- variant: "destructive",
953
- onClick: () => t.onDelete?.(),
954
- children: "Delete"
955
- });
956
- }
957
- }), null), p(c, k(E, {
958
- get when() {
959
- return T(() => y() === "edit")() && D();
960
- },
961
- get children() {
962
- return k(f, {
963
- size: "sm",
964
- get disabled() {
965
- return !z();
966
- },
967
- onClick: () => D()?.(),
968
- children: "Save"
969
- });
970
- }
971
- }), null), p(c, k(E, {
972
- get when() {
973
- return T(() => y() === "debug")() && t.debugData !== void 0;
974
- },
975
- get children() {
976
- return k(f, {
977
- size: "sm",
978
- variant: "outline",
979
- onClick: w,
980
- children: "Copy"
981
- });
982
- }
983
- }), null), c;
984
- }
985
- })];
986
- }
987
- });
988
- }
989
- });
990
- }
991
- Se(["click"]);
992
- function sn(e) {
993
- if (typeof IntersectionObserver > "u")
994
- return () => !1;
995
- const [t, i] = V(!1), r = new IntersectionObserver((n) => {
996
- const o = n[0];
997
- o && i(!o.isIntersecting);
998
- });
999
- return se(() => {
1000
- const n = e();
1001
- r.disconnect(), n && r.observe(n);
1002
- }), ce(() => r.disconnect()), t;
1003
- }
1004
- function ln() {
1005
- if (typeof window > "u" || typeof window.matchMedia != "function")
1006
- return () => !1;
1007
- const e = window.matchMedia("(prefers-reduced-motion: reduce)"), [t, i] = V(e.matches), r = (n) => i(n.matches);
1008
- return e.addEventListener("change", r), ce(() => e.removeEventListener("change", r)), t;
1009
- }
1010
- function cn(e = "controls") {
1011
- const [t, i] = V(!1), [r, n] = V(e), o = (d) => {
1012
- n(d ?? e), i(!0);
1013
- }, u = B(P);
1014
- return u?.registerDialogOpener?.(o), ce(() => u?.registerDialogOpener?.(null)), {
1015
- showDialog: t,
1016
- setShowDialog: i,
1017
- openDialog: o,
1018
- closeDialog: () => i(!1),
1019
- activeTab: r,
1020
- setActiveTab: n,
1021
- dialogProps: {
1022
- get open() {
1023
- return t();
1024
- },
1025
- onOpenChange: i,
1026
- get activeTab() {
1027
- return r();
1028
- },
1029
- onActiveTabChange: n
1030
- }
1031
- };
1032
- }
1033
- function dn(e) {
1034
- const t = e.minEntities ?? 1, i = j(() => e.entities().length), r = j(() => i() >= t), n = j(() => !r() || !e.calculateGroupData ? null : e.calculateGroupData(e.entities())), o = j(() => {
1035
- if (!r()) return;
1036
- const d = e.aggregationMode?.();
1037
- if (!d || d === "none") return;
1038
- const $ = e.entities();
1039
- if (d === "light" || d === "binary-sensor" || d === "switch")
1040
- return rt($, e.allEntitiesMode);
1041
- if (d === "sensor") {
1042
- const m = e.sensorGroupType?.() ?? "mean";
1043
- return ot($, m, !0);
1044
- }
1045
- }), u = j(() => r() ? void 0 : e.emptyStateConfig);
1046
- return {
1047
- entities: e.entities,
1048
- groupData: n,
1049
- aggregatedData: o,
1050
- emptyState: u,
1051
- hasEntities: r,
1052
- count: i
1053
- };
1054
- }
1055
- const X = 32, l = X / 2, _ = "white", te = "rgba(0,0,0,0.4)", de = 2, ne = 3;
1056
- function Nt(e) {
1057
- return `url("data:image/svg+xml,${encodeURIComponent(e)}")`;
1058
- }
1059
- function ie(e) {
1060
- return `<svg xmlns="http://www.w3.org/2000/svg" width="${X}" height="${X}" viewBox="0 0 ${X} ${X}">${e}</svg>`;
1061
- }
1062
- const At = ie(`
190
+ function je(e) {
191
+ return Ae[e];
192
+ }
193
+ //#endregion
194
+ //#region src/framework/backgrounds/WidgetSliderFill.tsx
195
+ var Me = /*#__PURE__*/ R("<div>");
196
+ function Ne(e) {
197
+ return (() => {
198
+ var t = Me();
199
+ return N((n) => {
200
+ var r = U("glasshome-widget-slider-fill pointer-events-none absolute inset-0", e.isDragging ? "duration-0" : "transition-all duration-300 ease-out", e.class), i = {
201
+ "--widget-fill-value": e.value,
202
+ "z-index": V.BACKGROUND,
203
+ ...e.color ? { "--widget-icon-color": e.color } : {}
204
+ };
205
+ return r !== n.e && j(t, n.e = r), n.t = L(t, i, n.t), n;
206
+ }, {
207
+ e: void 0,
208
+ t: void 0
209
+ }), t;
210
+ })();
211
+ }
212
+ //#endregion
213
+ //#region src/framework/components/WidgetContent.tsx
214
+ var Pe = /*#__PURE__*/ R("<div>");
215
+ function Fe(e) {
216
+ return (() => {
217
+ var t = Pe();
218
+ return P(t, () => e.children), N(() => j(t, U("glasshome-widget-content", e.class))), t;
219
+ })();
220
+ }
221
+ //#endregion
222
+ //#region src/framework/components/WidgetIcon.tsx
223
+ var Ie = /*#__PURE__*/ R("<div class=\"glasshome-widget-icon glasshome-widget-icon-stack glasshome-widget-icon-stack-2\">"), Le = /*#__PURE__*/ R("<div class=\"glasshome-widget-icon glasshome-widget-icon-stack glasshome-widget-icon-stack-3\">"), Re = /*#__PURE__*/ R("<div><div class=\"glasshome-widget-icon-glyph flex items-center justify-center\">");
224
+ function ze(e) {
225
+ let t = () => e.entityCount ?? 1;
226
+ return (() => {
227
+ var n = Re(), r = n.firstChild;
228
+ return P(n, M(w, {
229
+ get when() {
230
+ return t() >= 2;
231
+ },
232
+ get children() {
233
+ return Ie();
234
+ }
235
+ }), r), P(n, M(w, {
236
+ get when() {
237
+ return t() >= 3;
238
+ },
239
+ get children() {
240
+ return Le();
241
+ }
242
+ }), r), P(r, () => e.icon), N((t) => {
243
+ var r = U("glasshome-widget-icon", "relative flex shrink-0 items-center justify-center pointer-events-none transition-all", e.dimmed && "opacity-50", e.class), i = e.color ? { "--widget-icon-color": e.color } : void 0;
244
+ return r !== t.e && j(n, t.e = r), t.t = L(n, i, t.t), t;
245
+ }, {
246
+ e: void 0,
247
+ t: void 0
248
+ }), n;
249
+ })();
250
+ }
251
+ //#endregion
252
+ //#region src/framework/components/WidgetStatus.tsx
253
+ var Be = /*#__PURE__*/ R("<p>");
254
+ function Ve(e) {
255
+ return (() => {
256
+ var t = Be();
257
+ return P(t, (() => {
258
+ var t = F(() => !!e.isUnavailable);
259
+ return () => t() ? "Unavailable" : e.children;
260
+ })()), N((n) => {
261
+ var r = U("glasshome-widget-status", "relative", e.dimmed && "opacity-40", e.class), i = V.ACTIONS;
262
+ return r !== n.e && j(t, n.e = r), i !== n.t && I(t, "z-index", n.t = i), n;
263
+ }, {
264
+ e: void 0,
265
+ t: void 0
266
+ }), t;
267
+ })();
268
+ }
269
+ //#endregion
270
+ //#region src/framework/components/WidgetTitle.tsx
271
+ var He = /*#__PURE__*/ R("<span class=\"glasshome-widget-badge shrink-0\">"), Ue = /*#__PURE__*/ R("<div><h3 class=glasshome-widget-title>");
272
+ function We(e) {
273
+ return (() => {
274
+ var t = Ue(), n = t.firstChild;
275
+ return P(n, () => e.children), P(t, M(w, {
276
+ get when() {
277
+ return F(() => e.badge !== void 0)() && e.badge > 0;
278
+ },
279
+ get children() {
280
+ var t = He();
281
+ return P(t, () => e.badge), t;
282
+ }
283
+ }), null), N((n) => {
284
+ var r = U("relative flex items-center gap-2", e.class), i = V.ACTIONS;
285
+ return r !== n.e && j(t, n.e = r), i !== n.t && I(t, "z-index", n.t = i), n;
286
+ }, {
287
+ e: void 0,
288
+ t: void 0
289
+ }), t;
290
+ })();
291
+ }
292
+ //#endregion
293
+ //#region src/framework/utils/entity-aggregation.ts
294
+ function Ge(e, t = !1) {
295
+ if (e.length === 0) return {
296
+ isGroup: !1,
297
+ state: "unknown",
298
+ isOn: !1,
299
+ isUnavailable: !0,
300
+ brightness: 0,
301
+ brightnessPercent: 0,
302
+ color: "rgb(100, 100, 100)",
303
+ onCount: 0,
304
+ totalCount: 0,
305
+ description: "No entities"
306
+ };
307
+ let n = e.length > 1;
308
+ if (!n) {
309
+ let t = e[0], n = t.state === "on", r = t.attributes?.brightness || 0, i = Math.round(r / 255 * 100);
310
+ return {
311
+ isGroup: !1,
312
+ state: t.state,
313
+ isOn: n,
314
+ isUnavailable: t.state === "unavailable",
315
+ brightness: r,
316
+ brightnessPercent: i,
317
+ color: qe(t),
318
+ onCount: +!!n,
319
+ totalCount: 1,
320
+ description: n ? "On" : "Off"
321
+ };
322
+ }
323
+ let r = 0, i = 0, a = 0, o = 0, s = 0, c = 0, l = [];
324
+ for (let t of e) switch (t.state) {
325
+ case "on":
326
+ r++, t.attributes?.brightness !== void 0 && (s += t.attributes.brightness, c++), t.attributes?.rgb_color && l.push(t.attributes.rgb_color);
327
+ break;
328
+ case "off":
329
+ i++;
330
+ break;
331
+ case "unknown":
332
+ a++;
333
+ break;
334
+ case "unavailable":
335
+ o++;
336
+ break;
337
+ }
338
+ let u = e.length, d = o === u, f = a + o === u, p = r > 0, m = r === u, h = i === u, g, _;
339
+ t ? d ? (g = "unavailable", _ = !1) : a > 0 || o > 0 ? (g = "unknown", _ = !1) : i > 0 ? (g = "off", _ = !1) : (g = "on", _ = !0) : d ? (g = "unavailable", _ = !1) : f ? (g = "unknown", _ = !1) : p ? (g = "on", _ = !0) : (g = "off", _ = !1);
340
+ let v = c > 0 ? Math.round(s / c) : 0, y = Math.round(v / 255 * 100), b;
341
+ if (l.length > 0) {
342
+ let e = Math.round(l.reduce((e, t) => e + t[0], 0) / l.length), t = Math.round(l.reduce((e, t) => e + t[1], 0) / l.length), n = Math.round(l.reduce((e, t) => e + t[2], 0) / l.length), r = v / 255;
343
+ b = `rgb(${Math.round(e * r)}, ${Math.round(t * r)}, ${Math.round(n * r)})`;
344
+ } else b = qe(e[0]);
345
+ let x;
346
+ return x = m ? "All on" : h ? "All off" : r > 0 ? `${r} of ${u} on` : "Off", {
347
+ isGroup: n,
348
+ state: g,
349
+ isOn: _,
350
+ isUnavailable: g === "unavailable",
351
+ brightness: v,
352
+ brightnessPercent: y,
353
+ color: b,
354
+ onCount: r,
355
+ totalCount: u,
356
+ description: x
357
+ };
358
+ }
359
+ function Ke(e, t = "mean", n = !0) {
360
+ if (e.length === 0) return {
361
+ isGroup: !1,
362
+ state: "unknown",
363
+ numericValue: null,
364
+ isUnavailable: !0,
365
+ description: "No entities"
366
+ };
367
+ let r = e.length > 1;
368
+ if (!r) {
369
+ let t = e[0], n = Number.parseFloat(t.state), r = t.state;
370
+ return Number.isNaN(n) || (r = Number.isInteger(n) ? n.toString() : n.toFixed(1)), {
371
+ isGroup: !1,
372
+ state: r,
373
+ numericValue: Number.isNaN(n) ? null : n,
374
+ isUnavailable: t.state === "unavailable",
375
+ unit: t.unitOfMeasurement ?? void 0,
376
+ description: r
377
+ };
378
+ }
379
+ let i = [], a = [], o = 0, s;
380
+ for (let t of e) {
381
+ if (!s && t.unitOfMeasurement && (s = t.unitOfMeasurement), t.state === "unavailable") {
382
+ o++, a.push({
383
+ entityId: t.id,
384
+ value: "unavailable",
385
+ friendly_name: t.friendlyName
386
+ });
387
+ continue;
388
+ }
389
+ let e = Number.parseFloat(t.state);
390
+ isNaN(e) ? n || a.push({
391
+ entityId: t.id,
392
+ value: t.state,
393
+ friendly_name: t.friendlyName
394
+ }) : (i.push(e), a.push({
395
+ entityId: t.id,
396
+ value: e,
397
+ friendly_name: t.friendlyName
398
+ }));
399
+ }
400
+ let c = o === e.length, l = i.length === 0;
401
+ if (c || l) return {
402
+ isGroup: r,
403
+ state: c ? "unavailable" : "unknown",
404
+ numericValue: null,
405
+ isUnavailable: c,
406
+ unit: s,
407
+ description: c ? "Unavailable" : "No numeric values",
408
+ memberValues: a
409
+ };
410
+ let u, d;
411
+ switch (t) {
412
+ case "min":
413
+ u = Math.min(...i), d = "Minimum";
414
+ break;
415
+ case "max":
416
+ u = Math.max(...i), d = "Maximum";
417
+ break;
418
+ case "mean":
419
+ u = i.reduce((e, t) => e + t, 0) / i.length, d = "Average";
420
+ break;
421
+ case "median": {
422
+ let e = [...i].sort((e, t) => e - t), t = Math.floor(e.length / 2);
423
+ u = e.length % 2 == 0 ? (e[t - 1] + e[t]) / 2 : e[t], d = "Median";
424
+ break;
425
+ }
426
+ case "sum":
427
+ u = i.reduce((e, t) => e + t, 0), d = "Sum";
428
+ break;
429
+ case "last":
430
+ u = i[i.length - 1], d = "Latest";
431
+ break;
432
+ case "range":
433
+ u = Math.max(...i) - Math.min(...i), d = "Range";
434
+ break;
435
+ case "product":
436
+ u = i.reduce((e, t) => e * t, 1), d = "Product";
437
+ break;
438
+ case "std_dev": {
439
+ let e = i.reduce((e, t) => e + t, 0) / i.length, t = i.reduce((t, n) => t + (n - e) ** 2, 0) / i.length;
440
+ u = Math.sqrt(t), d = "Std Dev";
441
+ break;
442
+ }
443
+ default: u = i.reduce((e, t) => e + t, 0) / i.length, d = "Average";
444
+ }
445
+ return {
446
+ isGroup: r,
447
+ state: Number.isInteger(u) ? u.toString() : u.toFixed(1),
448
+ numericValue: u,
449
+ isUnavailable: !1,
450
+ unit: s,
451
+ description: `${d} of ${i.length}`,
452
+ memberValues: a
453
+ };
454
+ }
455
+ function qe(e) {
456
+ if (e.state !== "on") return "rgb(100, 100, 100)";
457
+ let t = (e.attributes?.brightness ?? 255) / 255;
458
+ if (e.attributes?.rgb_color) {
459
+ let [n, r, i] = e.attributes.rgb_color;
460
+ return `rgb(${Math.round(n * t)}, ${Math.round(r * t)}, ${Math.round(i * t)})`;
461
+ }
462
+ if (e.attributes?.color_temp) {
463
+ let n = 1e6 / e.attributes.color_temp / 100, r, i, a;
464
+ return n <= 66 ? (r = 255, i = n <= 19 ? 0 : 99.4708025861 * Math.log(n - 10) - 161.1195681661, a = n <= 19 ? 0 : n <= 66 ? 138.5177312231 * Math.log(n - 10) - 305.0447927307 : 255) : (r = 329.698727446 * (n - 60) ** -.1332047592, i = 288.1221695283 * (n - 60) ** -.0755148492, a = 255), r = Math.max(0, Math.min(255, r)) * t, i = Math.max(0, Math.min(255, i)) * t, a = Math.max(0, Math.min(255, a)) * t, `rgb(${Math.round(r)}, ${Math.round(i)}, ${Math.round(a)})`;
465
+ }
466
+ return `rgb(${Math.round(255 * t)}, ${Math.round(220 * t)}, ${Math.round(180 * t)})`;
467
+ }
468
+ //#endregion
469
+ //#region src/framework/utils/entity-state.ts
470
+ function Je(e) {
471
+ if (!e) return !1;
472
+ if ([
473
+ "on",
474
+ "open",
475
+ "locked",
476
+ "home",
477
+ "playing",
478
+ "active"
479
+ ].includes(e.state)) return !0;
480
+ if (e.domain === "sensor") {
481
+ let t = Number.parseFloat(e.state);
482
+ return !isNaN(t) && t > 0;
483
+ }
484
+ return !1;
485
+ }
486
+ function Ye(e, t, n) {
487
+ return e?.attributes ? e.attributes[t] ?? n : n;
488
+ }
489
+ function Xe(e) {
490
+ return e.filter(Je).length;
491
+ }
492
+ //#endregion
493
+ //#region src/framework/utils/format-value.ts
494
+ function Ze(e, t, n) {
495
+ let { decimals: r, scale: i = !0 } = n || {};
496
+ if (typeof e == "string") return t ? `${e}${t}` : e;
497
+ if (e == null || Number.isNaN(e)) return t ? `--${t}` : "--";
498
+ let a = e, o = t || "";
499
+ i && t && (t === "W" || t === "kW" || t === "MW") && (e >= 1e6 ? (a = e / 1e6, o = "MW") : e >= 1e3 ? (a = e / 1e3, o = "kW") : o = "W"), i && t && (t === "B" || t === "KB" || t === "MB" || t === "GB") && (e >= 1073741824 ? (a = e / 1073741824, o = "GB") : e >= 1048576 ? (a = e / 1048576, o = "MB") : e >= 1024 ? (a = e / 1024, o = "KB") : o = "B");
500
+ let s;
501
+ return s = r === void 0 ? a === e ? Number.isInteger(e) ? e.toString() : Number.parseFloat(e.toFixed(2)).toString() : a.toFixed(1) : a.toFixed(r), o ? `${s}${o}` : s;
502
+ }
503
+ //#endregion
504
+ //#region src/framework/utils/interpret-value.ts
505
+ function Qe(e, t) {
506
+ return e == null || isNaN(e) ? null : t === "°C" ? e < 10 ? "Cold" : e < 18 ? "Cool" : e < 24 ? "Comfortable" : e < 28 ? "Warm" : "Hot" : t === "°F" ? e < 50 ? "Cold" : e < 64 ? "Cool" : e < 75 ? "Comfortable" : e < 82 ? "Warm" : "Hot" : t === "%" ? e < 20 ? "Very Low" : e < 40 ? "Low" : e < 60 ? "Medium" : e < 80 ? "High" : "Very High" : t === "ppm" ? e < 400 ? "Excellent" : e < 600 ? "Good" : e < 1e3 ? "Acceptable" : e < 1500 ? "Mediocre" : "Poor" : t === "lx" ? e < 50 ? "Dark" : e < 200 ? "Dim" : e < 500 ? "Moderate" : e < 1e3 ? "Bright" : "Very Bright" : t === "AQI" ? e <= 50 ? "Good" : e <= 100 ? "Moderate" : e <= 150 ? "Unhealthy for Sensitive" : e <= 200 ? "Unhealthy" : e <= 300 ? "Very Unhealthy" : "Hazardous" : t === "dB" ? e < 30 ? "Very Quiet" : e < 50 ? "Quiet" : e < 70 ? "Moderate" : e < 85 ? "Loud" : "Very Loud" : null;
507
+ }
508
+ //#endregion
509
+ //#region src/framework/components/WidgetValue.tsx
510
+ var $e = /*#__PURE__*/ R("<div class=glasshome-widget-subtitle>"), et = /*#__PURE__*/ R("<div><div class=glasshome-widget-value>");
511
+ function tt(e) {
512
+ return (() => {
513
+ var t = et(), n = t.firstChild;
514
+ return P(n, () => Ze(e.value, e.unit)), P(t, M(w, {
515
+ get when() {
516
+ return F(() => !!e.interpret)() && typeof e.value == "number";
517
+ },
518
+ get children() {
519
+ var t = $e();
520
+ return P(t, () => Qe(e.value, e.unit)), t;
521
+ }
522
+ }), null), N(() => j(t, U("flex flex-col", e.class))), t;
523
+ })();
524
+ }
525
+ //#endregion
526
+ //#region src/framework/core/Widget.tsx
527
+ var nt = /*#__PURE__*/ R("<div><div class=\"relative h-full w-full\">"), rt = /*#__PURE__*/ R("<div class=\"glasshome-widget-loading pointer-events-none absolute inset-0 animate-pulse\">"), it = /*#__PURE__*/ R("<div class=\"flex h-full w-full flex-col items-center justify-center gap-2 text-center\">"), at = /*#__PURE__*/ R("<div class=\"flex items-center justify-center text-white/30\">"), ot = /*#__PURE__*/ R("<h3 class=\"font-semibold text-sm text-white/60\">"), st = /*#__PURE__*/ R("<p class=\"text-white/50 text-xs\">");
528
+ function ct(e) {
529
+ let t = k(z), [n, r] = D(), i = pe(n);
530
+ le(() => {
531
+ let e = n()?.getRootNode();
532
+ ke(typeof ShadowRoot < "u" && e instanceof ShadowRoot || typeof Document < "u" && e instanceof Document ? e : void 0);
533
+ });
534
+ let a = {
535
+ isEditMode: () => e.isEditMode ?? !1,
536
+ updateConfig: t?.updateConfig ?? (() => {}),
537
+ registerDialogOpener: t?.registerDialogOpener,
538
+ callService: t?.callService,
539
+ dimensions: () => ({
540
+ width: i.width ?? 0,
541
+ height: i.height ?? 0
542
+ })
543
+ }, o = E(() => {
544
+ if (e.variant) return typeof e.variant == "string" ? je(e.variant) : e.variant;
545
+ }), s = E(() => ({
546
+ "container-type": "size",
547
+ "container-name": "widget",
548
+ "touch-action": e.gestures && !e.isEditMode ? e.gestures.touchAction() : void 0,
549
+ ...o()?.styles?.container,
550
+ ...o()?.styles?.cssVars || {},
551
+ ...e.tone ? { "--widget-color": `var(--tone-${e.tone})` } : {},
552
+ ...e.color ? { "--widget-color": e.color } : {},
553
+ ...e.colorTo ? { "--widget-color-to": e.colorTo } : {},
554
+ ...e.gradient ? { "--widget-gradient": e.gradient } : {}
555
+ })), c = () => !!e.gestures && !e.isEditMode, l = (t) => {
556
+ c() && e.gestures?.onPointerEnter(t);
557
+ }, u = (t) => {
558
+ c() && e.gestures?.onPointerDown(t);
559
+ }, d = (t) => {
560
+ c() && e.gestures?.onPointerMove(t);
561
+ }, f = (t) => {
562
+ c() && e.gestures?.onPointerUp(t);
563
+ }, p = (t) => {
564
+ c() && e.gestures?.onPointerCancel(t);
565
+ };
566
+ return M(z.Provider, {
567
+ value: a,
568
+ get children() {
569
+ var t = nt(), n = t.firstChild;
570
+ return A(t, "pointercancel", p), A(t, "pointerup", f), A(t, "pointermove", d), A(t, "pointerdown", u), A(t, "pointerenter", l), fe((t) => {
571
+ r(t), e.gestures?.bindElement(t);
572
+ }, t), P(n, (() => {
573
+ var t = F(() => !!e.emptyState);
574
+ return () => t() ? M(lt, {
575
+ get icon() {
576
+ return e.emptyState.icon;
577
+ },
578
+ get title() {
579
+ return e.emptyState.title;
580
+ },
581
+ get message() {
582
+ return e.emptyState.message;
583
+ }
584
+ }) : e.children;
585
+ })()), P(t, (() => {
586
+ var t = F(() => !!e.loading);
587
+ return () => t() && (() => {
588
+ var e = rt();
589
+ return N((t) => I(e, "z-index", V.OVERLAY)), e;
590
+ })();
591
+ })(), null), N((r) => {
592
+ var i = U("glasshome-widget", "relative h-full w-full select-none overflow-hidden rounded-xl border border-border/50", o()?.styles?.class, e.class), a = s(), c = V.CONTENT;
593
+ return i !== r.e && j(t, r.e = i), r.t = L(t, a, r.t), c !== r.a && I(n, "z-index", r.a = c), r;
594
+ }, {
595
+ e: void 0,
596
+ t: void 0,
597
+ a: void 0
598
+ }), t;
599
+ }
600
+ });
601
+ }
602
+ function lt(e) {
603
+ return (() => {
604
+ var t = it();
605
+ return P(t, (() => {
606
+ var t = F(() => !!e.icon);
607
+ return () => t() && (() => {
608
+ var t = at();
609
+ return P(t, () => e.icon), t;
610
+ })();
611
+ })(), null), P(t, (() => {
612
+ var t = F(() => !!e.title);
613
+ return () => t() && (() => {
614
+ var t = ot();
615
+ return P(t, () => e.title), t;
616
+ })();
617
+ })(), null), P(t, (() => {
618
+ var t = F(() => !!e.message);
619
+ return () => t() && (() => {
620
+ var t = st();
621
+ return P(t, () => e.message), t;
622
+ })();
623
+ })(), null), t;
624
+ })();
625
+ }
626
+ var W = ct;
627
+ W.Content = Fe, W.Icon = ze, W.Title = We, W.Status = Ve, W.Value = tt, W.SliderFill = Ne;
628
+ //#endregion
629
+ //#region src/framework/dialogs/WidgetDialog.tsx
630
+ var ut = /*#__PURE__*/ R("<span class=\"inline-flex size-3.5 shrink-0 items-center\">"), dt = /*#__PURE__*/ R("<button type=button>"), ft = /*#__PURE__*/ R("<svg xmlns=http://www.w3.org/2000/svg class=size-3.5 fill=none viewBox=\"0 0 24 24\"stroke=currentColor stroke-width=2><path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\"></path><path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\">"), pt = /*#__PURE__*/ R("<div class=\"rounded-lg bg-muted/30 p-2 text-center md:p-6\"><p class=\"text-muted-foreground text-sm\">No edit options available"), mt = /*#__PURE__*/ R("<svg xmlns=http://www.w3.org/2000/svg class=size-3.5 fill=none viewBox=\"0 0 24 24\"stroke=currentColor stroke-width=2><line x1=4 y1=21 x2=4 y2=14></line><line x1=4 y1=10 x2=4 y2=3></line><line x1=12 y1=21 x2=12 y2=12></line><line x1=12 y1=8 x2=12 y2=3></line><line x1=20 y1=21 x2=20 y2=16></line><line x1=20 y1=12 x2=20 y2=3></line><line x1=1 y1=14 x2=7 y2=14></line><line x1=9 y1=8 x2=15 y2=8></line><line x1=17 y1=16 x2=23 y2=16>"), ht = /*#__PURE__*/ R("<div class=\"rounded-lg bg-muted/30 p-2 text-center md:p-6\"><p class=\"text-muted-foreground text-sm\">No additional controls"), gt = /*#__PURE__*/ R("<svg xmlns=http://www.w3.org/2000/svg class=size-3.5 fill=none viewBox=\"0 0 24 24\"stroke=currentColor stroke-width=2><path d=\"m8 2 1.88 1.88\"></path><path d=\"M14.12 3.88 16 2\"></path><path d=\"M9 7.13v-1a3.003 3.003 0 1 1 6 0v1\"></path><path d=\"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6\"></path><path d=\"M12 20v-9\"></path><path d=\"M6.53 9C4.6 8.8 3 7.1 3 5\"></path><path d=\"M6 13H2\"></path><path d=\"M3 21c0-2.1 1.7-3.9 3.8-4\"></path><path d=\"M20.97 5c0 2.1-1.6 3.8-3.5 4\"></path><path d=\"M22 13h-4\"></path><path d=\"M17.2 17c2.1.1 3.8 1.9 3.8 4\">"), _t = /*#__PURE__*/ R("<div class=\"rounded-lg bg-muted/30 p-2 text-center md:p-6\"><p class=\"text-muted-foreground text-sm\">No debug information available"), vt = /*#__PURE__*/ R("<div class=\"min-w-0 shrink-0\">"), yt = /*#__PURE__*/ R("<div class=\"flex items-center gap-2\"><div class=\"flex h-8 items-center rounded-lg border border-border/50 bg-muted/30 p-0.5\">"), bt = /*#__PURE__*/ R("<div class=\"min-h-0 flex-1 overflow-y-auto [scrollbar-gutter:stable]\">"), xt = /*#__PURE__*/ R("<div class=\"flex shrink-0 items-center justify-end gap-2 border-border/50 border-t pt-3\">");
631
+ function St(e) {
632
+ return (() => {
633
+ var t = dt();
634
+ return t.$$click = () => e.onClick(), P(t, M(w, {
635
+ get when() {
636
+ return e.isActive;
637
+ },
638
+ get children() {
639
+ var t = ut();
640
+ return P(t, () => e.icon), t;
641
+ }
642
+ }), null), P(t, () => e.label, null), N(() => j(t, U("flex cursor-pointer items-center justify-center rounded-md px-3 py-1.5 text-xs transition-all duration-300 ease-in-out", e.isActive ? "gap-1.5 bg-foreground/10 font-semibold text-foreground shadow-sm" : "gap-0 text-muted-foreground hover:bg-foreground/5 hover:text-foreground"))), t;
643
+ })();
644
+ }
645
+ function Ct(e) {
646
+ let [t] = ue(e, /* @__PURE__ */ "open.onOpenChange.title.onSave.hasUnsavedChanges.onDelete.editContent.controlsContent.debugContent.debugData.tabs.class.maxWidth.defaultTab.activeTab.onActiveTabChange.headerActions.configSchema.config.onConfigSave.ResponsiveDialog.ResponsiveDialogContent.ResponsiveDialogHeader.ResponsiveDialogTitle.ResponsiveDialogDescription.Button.SchemaForm".split(".")), n = () => !!t.configSchema && !!t.config && !!t.onConfigSave && !!t.SchemaForm, [r, i] = D({}), [a, o] = D(null);
647
+ T(ce(() => t.config, (e) => {
648
+ e && i({ ...e });
649
+ })), T(ce(() => t.configSchema, (e) => {
650
+ e && o(ge(e));
651
+ }));
652
+ let s = () => n() && JSON.stringify(r()) !== JSON.stringify(t.config), c = (e) => {
653
+ !e && t.config && i({ ...t.config }), t.onOpenChange(e);
654
+ }, l = () => {
655
+ t.onConfigSave?.(r());
656
+ }, [u, d] = D(t.defaultTab ?? "controls"), f = () => t.activeTab ?? u(), p = (e) => {
657
+ t.onActiveTabChange ? t.onActiveTabChange(e) : d(e);
658
+ }, m = () => ({
659
+ sm: "max-w-sm",
660
+ md: "max-w-md",
661
+ lg: "max-w-lg",
662
+ xl: "max-w-xl",
663
+ "2xl": "max-w-2xl",
664
+ "3xl": "max-w-3xl",
665
+ "4xl": "max-w-4xl"
666
+ })[t.maxWidth ?? "3xl"], h = () => {
667
+ if (t.tabs) return t.tabs;
668
+ let e = [];
669
+ return e.push({
670
+ id: "edit",
671
+ label: "Edit",
672
+ icon: ft(),
673
+ content: t.editContent ?? (n() && a() ? M(te, {
674
+ get schema() {
675
+ return a();
676
+ },
677
+ get data() {
678
+ return r();
679
+ },
680
+ onChange: i
681
+ }) : pt())
682
+ }), e.push({
683
+ id: "controls",
684
+ label: "Controls",
685
+ icon: mt(),
686
+ content: t.controlsContent ?? ht()
687
+ }), e.push({
688
+ id: "debug",
689
+ label: "Debug",
690
+ icon: gt(),
691
+ content: t.debugContent ?? _t()
692
+ }), e;
693
+ }, g = async () => {
694
+ if (t.debugData !== void 0) try {
695
+ let e = typeof t.debugData == "string" ? t.debugData : JSON.stringify(t.debugData, null, 2);
696
+ await navigator.clipboard.writeText(e);
697
+ } catch {}
698
+ }, _ = () => {
699
+ let e = h();
700
+ return e.find((e) => e.id === f())?.content ?? e[0]?.content;
701
+ }, v = t.ResponsiveDialog, y = t.ResponsiveDialogContent, b = t.ResponsiveDialogHeader, x = t.ResponsiveDialogTitle, ee = t.ResponsiveDialogDescription, S = t.Button, te = t.SchemaForm, ne = (e) => n() ? c(e) : t.onOpenChange(e), re = () => n() ? s() : t.hasUnsavedChanges, C = () => n() ? l : t.onSave;
702
+ return M(v, {
703
+ get open() {
704
+ return t.open;
705
+ },
706
+ onOpenChange: (e) => ne(e),
707
+ get children() {
708
+ return M(y, {
709
+ get class() {
710
+ return U(m(), t.class);
711
+ },
712
+ get children() {
713
+ return [
714
+ M(b, {
715
+ class: "flex flex-row items-center justify-between gap-3",
716
+ get children() {
717
+ return [(() => {
718
+ var e = vt();
719
+ return P(e, M(x, {
720
+ class: "truncate leading-tight",
721
+ get children() {
722
+ return t.title;
723
+ }
724
+ }), null), P(e, M(ee, {
725
+ class: "sr-only",
726
+ children: "Widget configuration dialog"
727
+ }), null), e;
728
+ })(), (() => {
729
+ var e = yt(), n = e.firstChild;
730
+ return P(n, () => h().map((e) => M(St, {
731
+ get icon() {
732
+ return e.icon;
733
+ },
734
+ get label() {
735
+ return e.label;
736
+ },
737
+ get isActive() {
738
+ return f() === e.id;
739
+ },
740
+ onClick: () => p(e.id)
741
+ }))), P(e, M(w, {
742
+ get when() {
743
+ return t.headerActions;
744
+ },
745
+ get children() {
746
+ return t.headerActions;
747
+ }
748
+ }), null), e;
749
+ })()];
750
+ }
751
+ }),
752
+ (() => {
753
+ var e = bt();
754
+ return P(e, _), e;
755
+ })(),
756
+ M(w, {
757
+ get when() {
758
+ return F(() => f() === "edit")() && (C() || t.onDelete) || f() === "debug" && t.debugData !== void 0;
759
+ },
760
+ get children() {
761
+ var e = xt();
762
+ return P(e, M(w, {
763
+ get when() {
764
+ return F(() => f() === "edit")() && t.onDelete;
765
+ },
766
+ get children() {
767
+ return M(S, {
768
+ size: "sm",
769
+ variant: "destructive",
770
+ onClick: () => t.onDelete?.(),
771
+ children: "Delete"
772
+ });
773
+ }
774
+ }), null), P(e, M(w, {
775
+ get when() {
776
+ return F(() => f() === "edit")() && C();
777
+ },
778
+ get children() {
779
+ return M(S, {
780
+ size: "sm",
781
+ get disabled() {
782
+ return !re();
783
+ },
784
+ onClick: () => C()?.(),
785
+ children: "Save"
786
+ });
787
+ }
788
+ }), null), P(e, M(w, {
789
+ get when() {
790
+ return F(() => f() === "debug")() && t.debugData !== void 0;
791
+ },
792
+ get children() {
793
+ return M(S, {
794
+ size: "sm",
795
+ variant: "outline",
796
+ onClick: g,
797
+ children: "Copy"
798
+ });
799
+ }
800
+ }), null), e;
801
+ }
802
+ })
803
+ ];
804
+ }
805
+ });
806
+ }
807
+ });
808
+ }
809
+ de(["click"]);
810
+ //#endregion
811
+ //#region src/framework/hooks/use-intersection-pause.ts
812
+ function wt(e) {
813
+ if (typeof IntersectionObserver > "u") return () => !1;
814
+ let [t, n] = D(!1), r = new IntersectionObserver((e) => {
815
+ let t = e[0];
816
+ t && n(!t.isIntersecting);
817
+ });
818
+ return T(() => {
819
+ let t = e();
820
+ r.disconnect(), t && r.observe(t);
821
+ }), O(() => r.disconnect()), t;
822
+ }
823
+ //#endregion
824
+ //#region src/framework/hooks/use-reduced-motion.ts
825
+ function Tt() {
826
+ if (typeof window > "u" || typeof window.matchMedia != "function") return () => !1;
827
+ let e = window.matchMedia("(prefers-reduced-motion: reduce)"), [t, n] = D(e.matches), r = (e) => n(e.matches);
828
+ return e.addEventListener("change", r), O(() => e.removeEventListener("change", r)), t;
829
+ }
830
+ //#endregion
831
+ //#region src/framework/hooks/use-widget-dialog.ts
832
+ function Et(e = "controls") {
833
+ let [t, n] = D(!1), [r, i] = D(e), a = (t) => {
834
+ i(t ?? e), n(!0);
835
+ }, o = k(z);
836
+ return o?.registerDialogOpener?.(a), O(() => o?.registerDialogOpener?.(null)), {
837
+ showDialog: t,
838
+ setShowDialog: n,
839
+ openDialog: a,
840
+ closeDialog: () => n(!1),
841
+ activeTab: r,
842
+ setActiveTab: i,
843
+ dialogProps: {
844
+ get open() {
845
+ return t();
846
+ },
847
+ onOpenChange: n,
848
+ get activeTab() {
849
+ return r();
850
+ },
851
+ onActiveTabChange: i
852
+ }
853
+ };
854
+ }
855
+ //#endregion
856
+ //#region src/framework/hooks/use-widget-entity-group.ts
857
+ function Dt(e) {
858
+ let t = e.minEntities ?? 1, n = E(() => e.entities().length), r = E(() => n() >= t), i = E(() => !r() || !e.calculateGroupData ? null : e.calculateGroupData(e.entities())), a = E(() => {
859
+ if (!r()) return;
860
+ let t = e.aggregationMode?.();
861
+ if (!t || t === "none") return;
862
+ let n = e.entities();
863
+ if (t === "light" || t === "binary-sensor" || t === "switch") return Ge(n, e.allEntitiesMode);
864
+ if (t === "sensor") return Ke(n, e.sensorGroupType?.() ?? "mean", !0);
865
+ }), o = E(() => r() ? void 0 : e.emptyStateConfig);
866
+ return {
867
+ entities: e.entities,
868
+ groupData: i,
869
+ aggregatedData: a,
870
+ emptyState: o,
871
+ hasEntities: r,
872
+ count: n
873
+ };
874
+ }
875
+ //#endregion
876
+ //#region src/framework/gestures/cursors.ts
877
+ var G = 32, K = G / 2, q = "white", J = "rgba(0,0,0,0.4)", Y = 2, X = 3;
878
+ function Ot(e) {
879
+ return `url("data:image/svg+xml,${encodeURIComponent(e)}")`;
880
+ }
881
+ function Z(e) {
882
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${G}" height="${G}" viewBox="0 0 ${G} ${G}">${e}</svg>`;
883
+ }
884
+ var kt = Z(`
1063
885
  <g transform="translate(6, 2)">
1064
886
  <!-- shadow -->
1065
- <g stroke="${te}" stroke-width="${ne}" fill="none" stroke-linecap="round" stroke-linejoin="round">
887
+ <g stroke="${J}" stroke-width="${X}" fill="none" stroke-linecap="round" stroke-linejoin="round">
1066
888
  <path d="M10 8V3a2 2 0 0 1 4 0v10l4.5-4.5a2 2 0 0 1 2.83 2.83L14 18.5c-2 2-4 3.5-8 3.5-3 0-5-2-5-5v-6a2 2 0 0 1 4 0v2"/>
1067
889
  </g>
1068
890
  <!-- main -->
1069
- <g stroke="${_}" stroke-width="${de}" fill="none" stroke-linecap="round" stroke-linejoin="round">
891
+ <g stroke="${q}" stroke-width="${Y}" fill="none" stroke-linecap="round" stroke-linejoin="round">
1070
892
  <path d="M10 8V3a2 2 0 0 1 4 0v10l4.5-4.5a2 2 0 0 1 2.83 2.83L14 18.5c-2 2-4 3.5-8 3.5-3 0-5-2-5-5v-6a2 2 0 0 1 4 0v2"/>
1071
893
  </g>
1072
894
  </g>
1073
- `), Vt = ie(`
895
+ `), At = Z(`
1074
896
  <g>
1075
- <circle cx="${l}" cy="${l}" r="8" stroke="${te}" stroke-width="${ne}" fill="none"/>
1076
- <circle cx="${l}" cy="${l}" r="8" stroke="${_}" stroke-width="1.5" fill="none"/>
1077
- <circle cx="${l}" cy="${l}" r="1.5" fill="${_}"/>
897
+ <circle cx="${K}" cy="${K}" r="8" stroke="${J}" stroke-width="${X}" fill="none"/>
898
+ <circle cx="${K}" cy="${K}" r="8" stroke="${q}" stroke-width="1.5" fill="none"/>
899
+ <circle cx="${K}" cy="${K}" r="1.5" fill="${q}"/>
1078
900
  </g>
1079
- `), Wt = ie(`
901
+ `), jt = Z(`
1080
902
  <g>
1081
903
  <!-- shadow -->
1082
- <g stroke="${te}" stroke-width="${ne}" fill="none" stroke-linecap="round" stroke-linejoin="round">
1083
- <line x1="6" y1="${l}" x2="26" y2="${l}"/>
1084
- <polyline points="10,${l - 4} 6,${l} 10,${l + 4}"/>
1085
- <polyline points="22,${l - 4} 26,${l} 22,${l + 4}"/>
904
+ <g stroke="${J}" stroke-width="${X}" fill="none" stroke-linecap="round" stroke-linejoin="round">
905
+ <line x1="6" y1="${K}" x2="26" y2="${K}"/>
906
+ <polyline points="10,${K - 4} 6,${K} 10,20"/>
907
+ <polyline points="22,${K - 4} 26,${K} 22,20"/>
1086
908
  </g>
1087
909
  <!-- main -->
1088
- <g stroke="${_}" stroke-width="${de}" fill="none" stroke-linecap="round" stroke-linejoin="round">
1089
- <line x1="6" y1="${l}" x2="26" y2="${l}"/>
1090
- <polyline points="10,${l - 4} 6,${l} 10,${l + 4}"/>
1091
- <polyline points="22,${l - 4} 26,${l} 22,${l + 4}"/>
910
+ <g stroke="${q}" stroke-width="${Y}" fill="none" stroke-linecap="round" stroke-linejoin="round">
911
+ <line x1="6" y1="${K}" x2="26" y2="${K}"/>
912
+ <polyline points="10,${K - 4} 6,${K} 10,20"/>
913
+ <polyline points="22,${K - 4} 26,${K} 22,20"/>
1092
914
  </g>
1093
915
  <!-- center grip dots -->
1094
- <circle cx="${l}" cy="${l}" r="1.5" fill="${_}"/>
1095
- <circle cx="${l - 5}" cy="${l}" r="1" fill="${_}" opacity="0.6"/>
1096
- <circle cx="${l + 5}" cy="${l}" r="1" fill="${_}" opacity="0.6"/>
916
+ <circle cx="${K}" cy="${K}" r="1.5" fill="${q}"/>
917
+ <circle cx="${K - 5}" cy="${K}" r="1" fill="${q}" opacity="0.6"/>
918
+ <circle cx="21" cy="${K}" r="1" fill="${q}" opacity="0.6"/>
1097
919
  </g>
1098
- `), Rt = ie(`
920
+ `), Mt = Z(`
1099
921
  <g>
1100
922
  <!-- shadow -->
1101
- <g stroke="${te}" stroke-width="${ne}" fill="none" stroke-linecap="round" stroke-linejoin="round">
1102
- <line x1="${l}" y1="6" x2="${l}" y2="26"/>
1103
- <polyline points="${l - 4},10 ${l},6 ${l + 4},10"/>
1104
- <polyline points="${l - 4},22 ${l},26 ${l + 4},22"/>
923
+ <g stroke="${J}" stroke-width="${X}" fill="none" stroke-linecap="round" stroke-linejoin="round">
924
+ <line x1="${K}" y1="6" x2="${K}" y2="26"/>
925
+ <polyline points="${K - 4},10 ${K},6 20,10"/>
926
+ <polyline points="${K - 4},22 ${K},26 20,22"/>
1105
927
  </g>
1106
928
  <!-- main -->
1107
- <g stroke="${_}" stroke-width="${de}" fill="none" stroke-linecap="round" stroke-linejoin="round">
1108
- <line x1="${l}" y1="6" x2="${l}" y2="26"/>
1109
- <polyline points="${l - 4},10 ${l},6 ${l + 4},10"/>
1110
- <polyline points="${l - 4},22 ${l},26 ${l + 4},22"/>
929
+ <g stroke="${q}" stroke-width="${Y}" fill="none" stroke-linecap="round" stroke-linejoin="round">
930
+ <line x1="${K}" y1="6" x2="${K}" y2="26"/>
931
+ <polyline points="${K - 4},10 ${K},6 20,10"/>
932
+ <polyline points="${K - 4},22 ${K},26 20,22"/>
1111
933
  </g>
1112
934
  <!-- center grip dots -->
1113
- <circle cx="${l}" cy="${l}" r="1.5" fill="${_}"/>
1114
- <circle cx="${l}" cy="${l - 5}" r="1" fill="${_}" opacity="0.6"/>
1115
- <circle cx="${l}" cy="${l + 5}" r="1" fill="${_}" opacity="0.6"/>
935
+ <circle cx="${K}" cy="${K}" r="1.5" fill="${q}"/>
936
+ <circle cx="${K}" cy="${K - 5}" r="1" fill="${q}" opacity="0.6"/>
937
+ <circle cx="${K}" cy="21" r="1" fill="${q}" opacity="0.6"/>
938
+ </g>
939
+ `), Nt = Z(`
940
+ <g>
941
+ <!-- shadow -->
942
+ <g stroke="${J}" stroke-width="${X}" fill="none" stroke-linecap="round" stroke-linejoin="round">
943
+ <line x1="7" y1="${K}" x2="25" y2="${K}"/>
944
+ <line x1="${K}" y1="7" x2="${K}" y2="25"/>
945
+ <polyline points="11,${K - 3} 7,${K} 11,19"/>
946
+ <polyline points="21,${K - 3} 25,${K} 21,19"/>
947
+ <polyline points="${K - 3},11 ${K},7 19,11"/>
948
+ <polyline points="${K - 3},21 ${K},25 19,21"/>
949
+ </g>
950
+ <!-- main -->
951
+ <g stroke="${q}" stroke-width="${Y}" fill="none" stroke-linecap="round" stroke-linejoin="round">
952
+ <line x1="7" y1="${K}" x2="25" y2="${K}"/>
953
+ <line x1="${K}" y1="7" x2="${K}" y2="25"/>
954
+ <polyline points="11,${K - 3} 7,${K} 11,19"/>
955
+ <polyline points="21,${K - 3} 25,${K} 21,19"/>
956
+ <polyline points="${K - 3},11 ${K},7 19,11"/>
957
+ <polyline points="${K - 3},21 ${K},25 19,21"/>
958
+ </g>
959
+ <!-- center dot -->
960
+ <circle cx="${K}" cy="${K}" r="2" fill="${q}"/>
1116
961
  </g>
1117
962
  `);
1118
- function Z(e, t, i) {
1119
- return { css: `${Nt(e)} ${t} ${i}, auto`, hotspotX: t, hotspotY: i };
1120
- }
1121
- const U = {
1122
- tap: Z(At, 12, 4),
1123
- hold: Z(Vt, 16, 16),
1124
- slideHorizontal: Z(Wt, l, l),
1125
- slideVertical: Z(Rt, l, l)
963
+ function Q(e, t, n) {
964
+ return {
965
+ css: `${Ot(e)} ${t} ${n}, auto`,
966
+ hotspotX: t,
967
+ hotspotY: n
968
+ };
969
+ }
970
+ var $ = {
971
+ tap: Q(kt, 12, 4),
972
+ hold: Q(At, 16, 16),
973
+ slideHorizontal: Q(jt, K, K),
974
+ slideVertical: Q(Mt, K, K),
975
+ slideAuto: Q(Nt, K, K)
1126
976
  };
1127
- function oe() {
1128
- if (typeof window > "u") return null;
1129
- const e = window;
1130
- return e.Capacitor?.isNativePlatform?.() ? e.Capacitor.Plugins?.Haptics ?? null : null;
1131
- }
1132
- function ae(e) {
1133
- if (!(typeof navigator > "u" || typeof navigator.vibrate != "function"))
1134
- try {
1135
- navigator.vibrate(e);
1136
- } catch {
1137
- }
1138
- }
1139
- const Ht = {
1140
- /** Light confirmation — fires when slide gesture arms after user holds still. */
1141
- tick() {
1142
- const e = oe();
1143
- if (e) {
1144
- e.impact({ style: "Light" }).catch(() => {
1145
- });
1146
- return;
1147
- }
1148
- ae(8);
1149
- },
1150
- /** Medium bump — fires when hold gesture commits (detail opening). */
1151
- bump() {
1152
- const e = oe();
1153
- if (e) {
1154
- e.impact({ style: "Medium" }).catch(() => {
1155
- });
1156
- return;
1157
- }
1158
- ae(20);
1159
- },
1160
- /** Stronger pulse — reserved for edit-mode pickup (future use). */
1161
- pulse() {
1162
- const e = oe();
1163
- if (e) {
1164
- e.impact({ style: "Heavy" }).catch(() => {
1165
- });
1166
- return;
1167
- }
1168
- ae([0, 15, 40, 15]);
1169
- }
977
+ //#endregion
978
+ //#region src/framework/gestures/haptics.ts
979
+ function Pt() {
980
+ if (typeof window > "u") return null;
981
+ let e = window;
982
+ return e.Capacitor?.isNativePlatform?.() ? e.Capacitor.Plugins?.Haptics ?? null : null;
983
+ }
984
+ function Ft(e) {
985
+ if (!(typeof navigator > "u" || typeof navigator.vibrate != "function")) try {
986
+ navigator.vibrate(e);
987
+ } catch {}
988
+ }
989
+ var It = {
990
+ tick() {
991
+ let e = Pt();
992
+ if (e) {
993
+ e.impact({ style: "Light" }).catch(() => {});
994
+ return;
995
+ }
996
+ Ft(8);
997
+ },
998
+ bump() {
999
+ let e = Pt();
1000
+ if (e) {
1001
+ e.impact({ style: "Medium" }).catch(() => {});
1002
+ return;
1003
+ }
1004
+ Ft(20);
1005
+ },
1006
+ pulse() {
1007
+ let e = Pt();
1008
+ if (e) {
1009
+ e.impact({ style: "Heavy" }).catch(() => {});
1010
+ return;
1011
+ }
1012
+ Ft([
1013
+ 0,
1014
+ 15,
1015
+ 40,
1016
+ 15
1017
+ ]);
1018
+ }
1170
1019
  };
1171
- function un(e, t) {
1172
- const n = {
1173
- isDown: !1,
1174
- isTouch: !1,
1175
- startX: 0,
1176
- startY: 0,
1177
- startTime: 0,
1178
- hasMoved: !1,
1179
- sliding: !1,
1180
- holdTimer: null,
1181
- element: null
1182
- };
1183
- let o = null, u = null, d = null;
1184
- const [$, m] = V(null);
1185
- function h(s) {
1186
- s !== u && (d && d.disconnect(), d = new ResizeObserver((f) => {
1187
- const b = f[0];
1188
- if (b) {
1189
- const C = b.borderBoxSize?.[0];
1190
- C ? o = { width: C.inlineSize, height: C.blockSize } : o = { width: b.contentRect.width, height: b.contentRect.height }, m(o.height > o.width);
1191
- }
1192
- }), u = s, d.observe(s), o = { width: s.clientWidth, height: s.clientHeight }, m(o.height > o.width));
1193
- }
1194
- const v = () => {
1195
- n.holdTimer && (clearTimeout(n.holdTimer), n.holdTimer = null);
1196
- }, y = () => {
1197
- n.isDown = !1, n.hasMoved = !1, n.sliding = !1;
1198
- }, g = (s) => {
1199
- const b = e().slide;
1200
- return b?.orientation === "horizontal" ? "horizontal" : b?.orientation === "vertical" ? "vertical" : s && (o || h(s), o) ? o.height > o.width ? "vertical" : "horizontal" : (t?.() ?? "horizontal") === "horizontal" ? "horizontal" : "vertical";
1201
- }, a = (s) => {
1202
- const f = e();
1203
- if (!(!f.tap && !f.hold && !f.slide)) {
1204
- if (n.isDown = !0, n.isTouch = s.pointerType === "touch", n.element = s.currentTarget, h(n.element), n.startX = s.clientX, n.startY = s.clientY, n.startTime = Date.now(), n.hasMoved = !1, n.sliding = !1, f.hold) {
1205
- const b = f.hold.delay ?? 300;
1206
- n.holdTimer = setTimeout(() => {
1207
- n.holdTimer = null, !(!n.isDown || n.hasMoved) && (Ht.bump(), f.hold?.action(), n.isDown = !1);
1208
- }, b);
1209
- }
1210
- if (!n.isTouch && f.slide)
1211
- try {
1212
- s.currentTarget.setPointerCapture(s.pointerId);
1213
- } catch {
1214
- }
1215
- }
1216
- }, S = (s) => {
1217
- if (!n.isDown) return;
1218
- const f = e(), b = s.clientX - n.startX, C = s.clientY - n.startY;
1219
- if (Math.sqrt(b * b + C * C) > 10 && (v(), n.hasMoved = !0), f.slide && n.hasMoved) {
1220
- const D = s.currentTarget, c = g(D);
1221
- if (n.isTouch && !n.sliding) {
1222
- const $e = Math.abs(c === "vertical" ? C : b), ke = Math.abs(c === "vertical" ? b : C);
1223
- if ($e < ke) return;
1224
- }
1225
- n.sliding = !0;
1226
- const Y = f.slide.min ?? 0, N = f.slide.max ?? 100, we = N - Y, pe = c === "vertical" ? -C : b, ue = o ?? { width: D.clientWidth, height: D.clientHeight }, be = c === "vertical" ? ue.height : ue.width, xe = pe / be * we, ye = Math.max(Y, Math.min(N, f.slide.value + xe));
1227
- f.slide.onChange(Math.round(ye)), n.startX = s.clientX, n.startY = s.clientY, s.preventDefault();
1228
- }
1229
- }, w = (s) => {
1230
- const f = e(), b = n.isDown, C = Date.now() - n.startTime, z = f.hold?.delay ?? 300;
1231
- v(), b && f.tap && !n.hasMoved && C < z && f.tap();
1232
- try {
1233
- s.currentTarget.releasePointerCapture(s.pointerId);
1234
- } catch {
1235
- }
1236
- y();
1237
- }, M = (s) => {
1238
- v();
1239
- try {
1240
- s.currentTarget.releasePointerCapture(s.pointerId);
1241
- } catch {
1242
- }
1243
- y();
1244
- }, O = (s) => {
1245
- const f = e();
1246
- if (f.slide) {
1247
- const b = f.slide.orientation;
1248
- return b === "horizontal" ? U.slideHorizontal.css : b === "vertical" ? U.slideVertical.css : (o || h(s), o && o.height > o.width ? U.slideVertical.css : U.slideHorizontal.css);
1249
- }
1250
- return f.tap ? U.tap.css : f.hold ? U.hold.css : "";
1251
- };
1252
- return {
1253
- onPointerDown: a,
1254
- onPointerMove: S,
1255
- onPointerUp: w,
1256
- onPointerCancel: M,
1257
- onPointerEnter: (s) => {
1258
- const f = s.currentTarget;
1259
- n.element = f, f.style.cursor = O(f);
1260
- },
1261
- bindElement: (s) => {
1262
- s && (n.element = s, h(s));
1263
- },
1264
- touchAction: () => {
1265
- const s = e();
1266
- if (s.slide) {
1267
- const f = s.slide.orientation;
1268
- return f === "vertical" || f !== "horizontal" && ($() ?? (t?.() ?? "horizontal") !== "horizontal") ? "pan-x" : "pan-y";
1269
- }
1270
- return s.tap || s.hold ? "manipulation" : "auto";
1271
- },
1272
- dispose: () => {
1273
- v(), d && (d.disconnect(), d = null), u = null, o = null;
1274
- }
1275
- };
1276
- }
1277
- const Pt = {
1278
- solar: "oklch(0.74 0.18 60)",
1279
- grid: "oklch(0.62 0.12 245)",
1280
- battery: "oklch(0.70 0.18 145)",
1281
- ev: "oklch(0.70 0.14 190)",
1282
- home: "oklch(0.68 0.06 250)",
1283
- positive: "oklch(0.70 0.14 160)",
1284
- // Fault red-orange; used only for faults, never normal consumption.
1285
- negative: "oklch(0.64 0.22 27)"
1020
+ //#endregion
1021
+ //#region src/framework/gestures/use-widget-gestures.ts
1022
+ function Lt(e, t) {
1023
+ let n = {
1024
+ isDown: !1,
1025
+ isTouch: !1,
1026
+ startX: 0,
1027
+ startY: 0,
1028
+ startTime: 0,
1029
+ hasMoved: !1,
1030
+ sliding: !1,
1031
+ holdTimer: null,
1032
+ element: null
1033
+ }, r = null, i = null, a = null, [o, s] = D(null);
1034
+ function c(e) {
1035
+ e !== i && (a && a.disconnect(), a = new ResizeObserver((e) => {
1036
+ let t = e[0];
1037
+ if (t) {
1038
+ let e = t.borderBoxSize?.[0];
1039
+ r = e ? {
1040
+ width: e.inlineSize,
1041
+ height: e.blockSize
1042
+ } : {
1043
+ width: t.contentRect.width,
1044
+ height: t.contentRect.height
1045
+ }, s(r.height > r.width);
1046
+ }
1047
+ }), i = e, a.observe(e), r = {
1048
+ width: e.clientWidth,
1049
+ height: e.clientHeight
1050
+ }, s(r.height > r.width));
1051
+ }
1052
+ let l = () => {
1053
+ n.holdTimer &&= (clearTimeout(n.holdTimer), null);
1054
+ }, u = () => {
1055
+ n.isDown = !1, n.hasMoved = !1, n.sliding = !1;
1056
+ }, d = (n) => {
1057
+ let i = e().slide;
1058
+ return i?.orientation === "horizontal" ? "horizontal" : i?.orientation === "vertical" ? "vertical" : n && (r || c(n), r) ? r.height > r.width ? "vertical" : "horizontal" : (t?.() ?? "horizontal") === "horizontal" ? "horizontal" : "vertical";
1059
+ }, f = (t) => {
1060
+ let r = e();
1061
+ if (!(!r.tap && !r.hold && !r.slide)) {
1062
+ if (n.isDown = !0, n.isTouch = t.pointerType === "touch", n.element = t.currentTarget, c(n.element), n.startX = t.clientX, n.startY = t.clientY, n.startTime = Date.now(), n.hasMoved = !1, n.sliding = !1, r.hold) {
1063
+ let e = r.hold.delay ?? 300;
1064
+ n.holdTimer = setTimeout(() => {
1065
+ n.holdTimer = null, !(!n.isDown || n.hasMoved) && (It.bump(), r.hold?.action(), n.isDown = !1);
1066
+ }, e);
1067
+ }
1068
+ if (!n.isTouch && r.slide) try {
1069
+ t.currentTarget.setPointerCapture(t.pointerId);
1070
+ } catch {}
1071
+ }
1072
+ }, p = (t) => {
1073
+ if (!n.isDown) return;
1074
+ let i = e(), a = t.clientX - n.startX, o = t.clientY - n.startY;
1075
+ if (Math.sqrt(a * a + o * o) > 10 && (l(), n.hasMoved = !0), i.slide && n.hasMoved) {
1076
+ let e = t.currentTarget, s = d(e);
1077
+ if (n.isTouch && !n.sliding && Math.abs(s === "vertical" ? o : a) < Math.abs(s === "vertical" ? a : o)) return;
1078
+ n.sliding = !0;
1079
+ let c = i.slide.min ?? 0, l = i.slide.max ?? 100, u = l - c, f = s === "vertical" ? -o : a, p = r ?? {
1080
+ width: e.clientWidth,
1081
+ height: e.clientHeight
1082
+ }, m = f / (s === "vertical" ? p.height : p.width) * u, h = Math.max(c, Math.min(l, i.slide.value + m));
1083
+ i.slide.onChange(Math.round(h)), n.startX = t.clientX, n.startY = t.clientY, t.preventDefault();
1084
+ }
1085
+ }, m = (t) => {
1086
+ let r = e(), i = n.isDown, a = Date.now() - n.startTime, o = r.hold?.delay ?? 300;
1087
+ l(), i && r.tap && !n.hasMoved && a < o && r.tap();
1088
+ try {
1089
+ t.currentTarget.releasePointerCapture(t.pointerId);
1090
+ } catch {}
1091
+ u();
1092
+ }, h = (e) => {
1093
+ l();
1094
+ try {
1095
+ e.currentTarget.releasePointerCapture(e.pointerId);
1096
+ } catch {}
1097
+ u();
1098
+ }, g = (t) => {
1099
+ let n = e();
1100
+ if (n.slide) {
1101
+ let e = n.slide.orientation;
1102
+ return e === "horizontal" ? $.slideHorizontal.css : e === "vertical" ? $.slideVertical.css : (r || c(t), r && r.height > r.width ? $.slideVertical.css : $.slideHorizontal.css);
1103
+ }
1104
+ return n.tap ? $.tap.css : n.hold ? $.hold.css : "";
1105
+ };
1106
+ return {
1107
+ onPointerDown: f,
1108
+ onPointerMove: p,
1109
+ onPointerUp: m,
1110
+ onPointerCancel: h,
1111
+ onPointerEnter: (e) => {
1112
+ let t = e.currentTarget;
1113
+ n.element = t, t.style.cursor = g(t);
1114
+ },
1115
+ bindElement: (e) => {
1116
+ e && (n.element = e, c(e));
1117
+ },
1118
+ touchAction: () => {
1119
+ let n = e();
1120
+ if (n.slide) {
1121
+ let e = n.slide.orientation;
1122
+ return e === "vertical" || e !== "horizontal" && (o() ?? (t?.() ?? "horizontal") !== "horizontal") ? "pan-x" : "pan-y";
1123
+ }
1124
+ return n.tap || n.hold ? "manipulation" : "auto";
1125
+ },
1126
+ dispose: () => {
1127
+ l(), a &&= (a.disconnect(), null), i = null, r = null;
1128
+ }
1129
+ };
1130
+ }
1131
+ //#endregion
1132
+ //#region src/framework/theming/svg-colors.ts
1133
+ var Rt = {
1134
+ solar: "oklch(0.74 0.18 60)",
1135
+ grid: "oklch(0.62 0.12 245)",
1136
+ battery: "oklch(0.70 0.18 145)",
1137
+ ev: "oklch(0.70 0.14 190)",
1138
+ home: "oklch(0.68 0.06 250)",
1139
+ positive: "oklch(0.70 0.14 160)",
1140
+ negative: "oklch(0.64 0.22 27)"
1286
1141
  };
1287
- function It(e) {
1288
- return {
1289
- fill: `color-mix(in oklch, ${e} 20%, transparent)`,
1290
- stroke: e,
1291
- solid: e
1292
- };
1293
- }
1294
- const gn = Object.fromEntries(
1295
- Object.entries(Pt).map(([e, t]) => [e, It(t)])
1296
- ), hn = A.enum([
1297
- "success",
1298
- "warning",
1299
- "danger",
1300
- "info",
1301
- "neutral",
1302
- "accent"
1303
- ]), fn = {
1304
- /** Optional display name override (renders as text input) */
1305
- title: () => A.string().optional().meta({ title: "Title", description: "Optional display name override" }),
1306
- /** Multi-select entity picker for a HA domain */
1307
- entityIds: (e, t) => A.array(A.string()).default([]).meta({
1308
- domain: e,
1309
- title: "Entities",
1310
- ...t?.deviceClass ? { deviceClass: t.deviceClass } : {}
1311
- }),
1312
- /** Single-select entity picker for a HA domain */
1313
- singleEntity: (e, t) => A.array(A.string()).default([]).meta({
1314
- domain: e,
1315
- title: "Entity",
1316
- singleSelect: !0,
1317
- ...t?.deviceClass ? { deviceClass: t.deviceClass } : {}
1318
- }),
1319
- /** Area picker dropdown */
1320
- areaId: () => A.string().optional().meta({ formType: "area-picker", title: "Area" })
1321
- };
1322
- function mn(e) {
1323
- if (e.length < 2) return "";
1324
- const t = e[0], i = e[1];
1325
- if (!t || !i) return "";
1326
- if (e.length === 2) return `M ${t.x} ${t.y} L ${i.x} ${i.y}`;
1327
- const r = e.length, n = [], o = [], u = [];
1328
- for (let m = 0; m < r - 1; m++) {
1329
- const h = e[m], v = e[m + 1];
1330
- !h || !v || (n.push(v.x - h.x), o.push(v.y - h.y), u.push((v.y - h.y) / (v.x - h.x)));
1331
- }
1332
- const d = [u[0] ?? 0];
1333
- for (let m = 1; m < r - 1; m++) {
1334
- const h = u[m - 1] ?? 0, v = u[m] ?? 0, y = n[m - 1] ?? 0, g = n[m] ?? 0;
1335
- h * v <= 0 ? d.push(0) : d.push(
1336
- 3 * (y + g) / ((2 * g + y) / h + (g + 2 * y) / v)
1337
- );
1338
- }
1339
- d.push(u[r - 2] ?? 0);
1340
- let $ = `M ${t.x} ${t.y}`;
1341
- for (let m = 0; m < r - 1; m++) {
1342
- const h = e[m], v = e[m + 1];
1343
- if (!h || !v) continue;
1344
- const y = (n[m] ?? 0) / 3, g = d[m] ?? 0, a = d[m + 1] ?? 0;
1345
- $ += ` C ${h.x + y} ${h.y + g * y}, ${v.x - y} ${v.y - a * y}, ${v.x} ${v.y}`;
1346
- }
1347
- return $;
1348
- }
1349
- function vn() {
1350
- return document.documentElement.classList.contains("dark");
1351
- }
1352
- const Lt = "1.2.0", Ut = {
1353
- version: Lt
1354
- }, wn = Ut.version;
1355
- export {
1356
- wn as SDK_VERSION,
1357
- hn as ToneSchema,
1358
- q as Widget,
1359
- Ye as WidgetContent,
1360
- P as WidgetCtx,
1361
- an as WidgetDialog,
1362
- Qe as WidgetIcon,
1363
- xn as WidgetManifestSchema,
1364
- Ge as WidgetSliderFill,
1365
- et as WidgetStatus,
1366
- it as WidgetTitle,
1367
- ut as WidgetValue,
1368
- kn as byDomain,
1369
- rt as calculateLightGroup,
1370
- ot as calculateSensorGroup,
1371
- on as countActiveEntities,
1372
- Jt as defineWidget,
1373
- yn as formatSchemaError,
1374
- rn as getEntityAttribute,
1375
- Pn as getForecasts,
1376
- In as getStream,
1377
- Ln as getWebRtcClientConfig,
1378
- Pe as injectTokens,
1379
- vn as isDark,
1380
- at as isEntityActive,
1381
- mn as monotoneCubicPath,
1382
- Un as sendWebRtcCandidate,
1383
- jn as startWebRtcSession,
1384
- Bn as state,
1385
- gn as svgColors,
1386
- Fn as trackEntityHistory,
1387
- Gn as untrackEntityHistory,
1388
- Cn as useArea,
1389
- Sn as useCamera,
1390
- Mn as useConnection,
1391
- Dn as useCurrency,
1392
- Tn as useEntities,
1393
- _n as useEntity,
1394
- On as useEntityHistory,
1395
- zn as useEntityStatistics,
1396
- En as useForecast,
1397
- Nn as useHassConfig,
1398
- sn as useIntersectionPause,
1399
- An as useLocale,
1400
- ln as useReducedMotion,
1401
- Zt as useService,
1402
- Vn as useStore,
1403
- Wn as useTemperatureUnit,
1404
- nn as useToggle,
1405
- tn as useTurnOff,
1406
- en as useTurnOn,
1407
- Rn as useUnitSystem,
1408
- Qt as useWidgetContext,
1409
- cn as useWidgetDialog,
1410
- dn as useWidgetEntityGroup,
1411
- un as useWidgetGestures,
1412
- fn as widgetFields
1142
+ function zt(e) {
1143
+ return {
1144
+ fill: `color-mix(in oklch, ${e} 20%, transparent)`,
1145
+ stroke: e,
1146
+ solid: e
1147
+ };
1148
+ }
1149
+ var Bt = Object.fromEntries(Object.entries(Rt).map(([e, t]) => [e, zt(t)])), Vt = n.enum([
1150
+ "success",
1151
+ "warning",
1152
+ "danger",
1153
+ "info",
1154
+ "neutral",
1155
+ "accent"
1156
+ ]), Ht = {
1157
+ title: () => n.string().optional().meta({
1158
+ title: "Title",
1159
+ description: "Optional display name override"
1160
+ }),
1161
+ entityIds: (e, t) => n.array(n.string()).default([]).meta({
1162
+ domain: e,
1163
+ title: "Entities",
1164
+ ...t?.deviceClass ? { deviceClass: t.deviceClass } : {}
1165
+ }),
1166
+ singleEntity: (e, t) => n.array(n.string()).default([]).meta({
1167
+ domain: e,
1168
+ title: "Entity",
1169
+ singleSelect: !0,
1170
+ ...t?.deviceClass ? { deviceClass: t.deviceClass } : {}
1171
+ }),
1172
+ areaId: () => n.string().optional().meta({
1173
+ formType: "area-picker",
1174
+ title: "Area"
1175
+ })
1413
1176
  };
1177
+ //#endregion
1178
+ //#region src/shared/spline.ts
1179
+ function Ut(e) {
1180
+ if (e.length < 2) return "";
1181
+ let t = e[0], n = e[1];
1182
+ if (!t || !n) return "";
1183
+ if (e.length === 2) return `M ${t.x} ${t.y} L ${n.x} ${n.y}`;
1184
+ let r = e.length, i = [], a = [], o = [];
1185
+ for (let t = 0; t < r - 1; t++) {
1186
+ let n = e[t], r = e[t + 1];
1187
+ !n || !r || (i.push(r.x - n.x), a.push(r.y - n.y), o.push((r.y - n.y) / (r.x - n.x)));
1188
+ }
1189
+ let s = [o[0] ?? 0];
1190
+ for (let e = 1; e < r - 1; e++) {
1191
+ let t = o[e - 1] ?? 0, n = o[e] ?? 0, r = i[e - 1] ?? 0, a = i[e] ?? 0;
1192
+ t * n <= 0 ? s.push(0) : s.push(3 * (r + a) / ((2 * a + r) / t + (a + 2 * r) / n));
1193
+ }
1194
+ s.push(o[r - 2] ?? 0);
1195
+ let c = `M ${t.x} ${t.y}`;
1196
+ for (let t = 0; t < r - 1; t++) {
1197
+ let n = e[t], r = e[t + 1];
1198
+ if (!n || !r) continue;
1199
+ let a = (i[t] ?? 0) / 3, o = s[t] ?? 0, l = s[t + 1] ?? 0;
1200
+ c += ` C ${n.x + a} ${n.y + o * a}, ${r.x - a} ${r.y - l * a}, ${r.x} ${r.y}`;
1201
+ }
1202
+ return c;
1203
+ }
1204
+ //#endregion
1205
+ //#region src/theme.ts
1206
+ function Wt() {
1207
+ return document.documentElement.classList.contains("dark");
1208
+ }
1209
+ //#endregion
1210
+ //#region src/version.ts
1211
+ var Gt = {
1212
+ name: "@glasshome/widget-sdk",
1213
+ version: "1.3.0",
1214
+ description: "SDK for building GlassHome dashboard widgets with SolidJS",
1215
+ keywords: [
1216
+ "glasshome",
1217
+ "widget",
1218
+ "sdk",
1219
+ "solidjs",
1220
+ "vite",
1221
+ "home-assistant",
1222
+ "dashboard",
1223
+ "smart-home"
1224
+ ],
1225
+ type: "module",
1226
+ sideEffects: !1,
1227
+ main: "./dist/index.js",
1228
+ types: "./dist/index.d.ts",
1229
+ exports: {
1230
+ ".": {
1231
+ "@glasshome/source": "./src/index.ts",
1232
+ types: "./dist/index.d.ts",
1233
+ import: "./dist/index.js"
1234
+ },
1235
+ "./schemas": {
1236
+ "@glasshome/source": "./src/schemas.ts",
1237
+ types: "./dist/schemas.d.ts",
1238
+ import: "./dist/schemas.js"
1239
+ },
1240
+ "./vite": {
1241
+ "@glasshome/source": "./src/vite/index.ts",
1242
+ types: "./dist/vite/index.d.ts",
1243
+ import: "./dist/vite/index.js"
1244
+ },
1245
+ "./tailwind-sources": "./tailwind-sources.css",
1246
+ "./package.json": "./package.json"
1247
+ },
1248
+ files: [
1249
+ "dist",
1250
+ "preview",
1251
+ "tailwind-sources.css"
1252
+ ],
1253
+ scripts: {
1254
+ build: "vite build && tsc",
1255
+ dev: "vite build --watch"
1256
+ },
1257
+ peerDependencies: {
1258
+ "@glasshome/sync-layer": "0.3.0",
1259
+ "solid-js": "^1.9.11"
1260
+ },
1261
+ dependencies: {
1262
+ "@glasshome/widget-contract": "0.1.0",
1263
+ "@modular-forms/solid": "^0.25.1",
1264
+ "@solid-primitives/resize-observer": "^2.1.5",
1265
+ clsx: "^2.1.1",
1266
+ "tailwind-merge": "^3.5.0",
1267
+ zod: "^4.1.13",
1268
+ "@tailwindcss/vite": "^4.1.13",
1269
+ tailwindcss: "^4.1.13"
1270
+ },
1271
+ devDependencies: {
1272
+ "@types/bun": "latest",
1273
+ "@types/node": "^25.2.2",
1274
+ typescript: "^5",
1275
+ vite: "^8.1.0",
1276
+ "vite-plugin-solid": "^2.11.12"
1277
+ },
1278
+ repository: {
1279
+ type: "git",
1280
+ url: "https://github.com/glasshome/widget-sdk.git"
1281
+ },
1282
+ homepage: "https://github.com/glasshome/widget-sdk#readme",
1283
+ bugs: { url: "https://github.com/glasshome/widget-sdk/issues" },
1284
+ author: "GlassHome Labs",
1285
+ license: "MIT",
1286
+ publishConfig: { access: "public" },
1287
+ engines: { node: ">=18" }
1288
+ }.version;
1289
+ //#endregion
1290
+ export { Gt as SDK_VERSION, Vt as ToneSchema, W as Widget, Fe as WidgetContent, z as WidgetCtx, Ct as WidgetDialog, ze as WidgetIcon, e as WidgetManifestSchema, Ne as WidgetSliderFill, Ve as WidgetStatus, We as WidgetTitle, tt as WidgetValue, f as byDomain, Ge as calculateLightGroup, Ke as calculateSensorGroup, Xe as countActiveEntities, ve as defineWidget, t as formatSchemaError, Ye as getEntityAttribute, r as getForecasts, i as getStream, a as getWebRtcClientConfig, o as hassMediaUrl, ke as injectTokens, Wt as isDark, Je as isEntityActive, Ut as monotoneCubicPath, s as sendWebRtcCandidate, c as startWebRtcSession, l as state, Bt as svgColors, u as trackEntityHistory, d as untrackEntityHistory, p as useArea, m as useCamera, h as useConnection, g as useCurrency, _ as useEntities, v as useEntity, y as useEntityHistory, b as useEntityStatistics, x as useForecast, ee as useHassConfig, wt as useIntersectionPause, S as useLocale, Tt as useReducedMotion, xe as useService, ne as useStore, re as useTemperatureUnit, we as useToggle, Ce as useTurnOff, Se as useTurnOn, oe as useUnitSystem, ye as useWidgetContext, Et as useWidgetDialog, Dt as useWidgetEntityGroup, Lt as useWidgetGestures, Ht as widgetFields };