@glasshome/widget-sdk 1.1.0 → 1.2.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.
@@ -8,9 +8,13 @@ export declare const widgetFields: {
8
8
  /** Optional display name override (renders as text input) */
9
9
  title: () => z.ZodOptional<z.ZodString>;
10
10
  /** Multi-select entity picker for a HA domain */
11
- entityIds: (domain: string) => z.ZodDefault<z.ZodArray<z.ZodString>>;
11
+ entityIds: (domain: string, options?: {
12
+ deviceClass?: string;
13
+ }) => z.ZodDefault<z.ZodArray<z.ZodString>>;
12
14
  /** Single-select entity picker for a HA domain */
13
- singleEntity: (domain: string) => z.ZodDefault<z.ZodArray<z.ZodString>>;
15
+ singleEntity: (domain: string, options?: {
16
+ deviceClass?: string;
17
+ }) => z.ZodDefault<z.ZodArray<z.ZodString>>;
14
18
  /** Area picker dropdown */
15
19
  areaId: () => z.ZodOptional<z.ZodString>;
16
20
  };
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { z as A } from "zod";
2
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 Se, delegateEvents as Ce } from "solid-js/web";
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
4
  import { createElementSize as Me } from "@solid-primitives/resize-observer";
5
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
6
  import { clsx as Oe } from "clsx";
7
7
  import { twMerge as ze } from "tailwind-merge";
8
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 Sn, useCamera as Cn, 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";
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
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
11
  function me(e) {
12
12
  return A.toJSONSchema(e, {
@@ -472,14 +472,14 @@ function rt(e, t = !1) {
472
472
  };
473
473
  const i = e.length > 1;
474
474
  if (!i) {
475
- const s = e[0], f = s.state === "on", b = s.attributes?.brightness || 0, S = Math.round(b / 255 * 100);
475
+ const s = e[0], f = s.state === "on", b = s.attributes?.brightness || 0, C = Math.round(b / 255 * 100);
476
476
  return {
477
477
  isGroup: !1,
478
478
  state: s.state,
479
479
  isOn: f,
480
480
  isUnavailable: s.state === "unavailable",
481
481
  brightness: b,
482
- brightnessPercent: S,
482
+ brightnessPercent: C,
483
483
  color: fe(s),
484
484
  onCount: f ? 1 : 0,
485
485
  totalCount: 1,
@@ -503,18 +503,18 @@ function rt(e, t = !1) {
503
503
  u++;
504
504
  break;
505
505
  }
506
- const h = e.length, v = u === h, y = o + u === h, g = r > 0, a = r === h, C = n === h;
506
+ const h = e.length, v = u === h, y = o + u === h, g = r > 0, a = r === h, S = n === h;
507
507
  let w, M;
508
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
509
  const O = $ > 0 ? Math.round(d / $) : 0, L = Math.round(O / 255 * 100);
510
510
  let F;
511
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), S = O / 255;
513
- F = `rgb(${Math.round(s * S)}, ${Math.round(f * S)}, ${Math.round(b * S)})`;
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
514
  } else
515
515
  F = fe(e[0]);
516
516
  let H;
517
- return a ? H = "All on" : C ? H = "All off" : r > 0 ? H = `${r} of ${h} on` : H = "Off", {
517
+ return a ? H = "All on" : S ? H = "All off" : r > 0 ? H = `${r} of ${h} on` : H = "Off", {
518
518
  isGroup: i,
519
519
  state: w,
520
520
  isOn: M,
@@ -539,14 +539,14 @@ function ot(e, t = "mean", i = !0) {
539
539
  const r = e.length > 1;
540
540
  if (!r) {
541
541
  const g = e[0], a = Number.parseFloat(g.state);
542
- let C = g.state;
543
- return Number.isNaN(a) || (C = Number.isInteger(a) ? a.toString() : a.toFixed(1)), {
542
+ let S = g.state;
543
+ return Number.isNaN(a) || (S = Number.isInteger(a) ? a.toString() : a.toFixed(1)), {
544
544
  isGroup: !1,
545
- state: C,
545
+ state: S,
546
546
  numericValue: Number.isNaN(a) ? null : a,
547
547
  isUnavailable: g.state === "unavailable",
548
548
  unit: g.unitOfMeasurement ?? void 0,
549
- description: C
549
+ description: S
550
550
  };
551
551
  }
552
552
  const n = [], o = [];
@@ -594,7 +594,7 @@ function ot(e, t = "mean", i = !0) {
594
594
  h = n.reduce((g, a) => g + a, 0) / n.length, v = "Average";
595
595
  break;
596
596
  case "median": {
597
- const g = [...n].sort((C, w) => C - w), a = Math.floor(g.length / 2);
597
+ const g = [...n].sort((S, w) => S - w), a = Math.floor(g.length / 2);
598
598
  h = g.length % 2 === 0 ? (g[a - 1] + g[a]) / 2 : g[a], v = "Median";
599
599
  break;
600
600
  }
@@ -611,7 +611,7 @@ function ot(e, t = "mean", i = !0) {
611
611
  h = n.reduce((g, a) => g * a, 1), v = "Product";
612
612
  break;
613
613
  case "std_dev": {
614
- const g = n.reduce((C, w) => C + w, 0) / n.length, a = n.reduce((C, w) => C + (w - g) ** 2, 0) / n.length;
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
615
  h = Math.sqrt(a), v = "Std Dev";
616
616
  break;
617
617
  }
@@ -740,10 +740,10 @@ function pt(e) {
740
740
  return k(P.Provider, {
741
741
  value: o,
742
742
  get children() {
743
- var a = gt(), C = a.firstChild;
744
- return K(a, "pointercancel", g), K(a, "pointerup", y), K(a, "pointermove", v), K(a, "pointerdown", h), K(a, "pointerenter", m), Se((w) => {
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
745
  r(w), e.gestures?.bindElement(w);
746
- }, a), p(C, (() => {
746
+ }, a), p(S, (() => {
747
747
  var w = T(() => !!e.emptyState);
748
748
  return () => w() ? k(bt, {
749
749
  get icon() {
@@ -764,7 +764,7 @@ function pt(e) {
764
764
  })();
765
765
  })(), null), W((w) => {
766
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(C, "z-index", w.a = L), w;
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
768
  }, {
769
769
  e: void 0,
770
770
  t: void 0,
@@ -804,7 +804,7 @@ q.Title = it;
804
804
  q.Status = et;
805
805
  q.Value = ut;
806
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'), St = /* @__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>'), Ct = /* @__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">');
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
808
  function Et(e) {
809
809
  return (() => {
810
810
  var t = yt();
@@ -847,7 +847,7 @@ function an(e) {
847
847
  "3xl": "max-w-3xl",
848
848
  "4xl": "max-w-4xl"
849
849
  }[c];
850
- }, C = () => {
850
+ }, S = () => {
851
851
  if (t.tabs) return t.tabs;
852
852
  const c = [];
853
853
  return c.push({
@@ -866,8 +866,8 @@ function an(e) {
866
866
  }), c.push({
867
867
  id: "controls",
868
868
  label: "Controls",
869
- icon: St(),
870
- content: t.controlsContent ?? Ct()
869
+ icon: Ct(),
870
+ content: t.controlsContent ?? St()
871
871
  }), c.push({
872
872
  id: "debug",
873
873
  label: "Debug",
@@ -882,14 +882,14 @@ function an(e) {
882
882
  } catch {
883
883
  }
884
884
  }, M = () => {
885
- const c = C();
885
+ const c = S();
886
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, S = (c) => i() ? $(c) : t.onOpenChange(c), z = () => i() ? d() : t.hasUnsavedChanges, D = () => i() ? m : t.onSave;
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
888
  return k(O, {
889
889
  get open() {
890
890
  return t.open;
891
891
  },
892
- onOpenChange: (c) => S(c),
892
+ onOpenChange: (c) => C(c),
893
893
  get children() {
894
894
  return k(L, {
895
895
  get class() {
@@ -912,7 +912,7 @@ function an(e) {
912
912
  }), null), c;
913
913
  })(), (() => {
914
914
  var c = _t(), Y = c.firstChild;
915
- return p(Y, () => C().map((N) => k(Et, {
915
+ return p(Y, () => S().map((N) => k(Et, {
916
916
  get icon() {
917
917
  return N.icon;
918
918
  },
@@ -988,7 +988,7 @@ function an(e) {
988
988
  }
989
989
  });
990
990
  }
991
- Ce(["click"]);
991
+ Se(["click"]);
992
992
  function sn(e) {
993
993
  if (typeof IntersectionObserver > "u")
994
994
  return () => !1;
@@ -1186,8 +1186,8 @@ function un(e, t) {
1186
1186
  s !== u && (d && d.disconnect(), d = new ResizeObserver((f) => {
1187
1187
  const b = f[0];
1188
1188
  if (b) {
1189
- const S = b.borderBoxSize?.[0];
1190
- S ? o = { width: S.inlineSize, height: S.blockSize } : o = { width: b.contentRect.width, height: b.contentRect.height }, m(o.height > o.width);
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
1191
  }
1192
1192
  }), u = s, d.observe(s), o = { width: s.clientWidth, height: s.clientHeight }, m(o.height > o.width));
1193
1193
  }
@@ -1213,22 +1213,22 @@ function un(e, t) {
1213
1213
  } catch {
1214
1214
  }
1215
1215
  }
1216
- }, C = (s) => {
1216
+ }, S = (s) => {
1217
1217
  if (!n.isDown) return;
1218
- const f = e(), b = s.clientX - n.startX, S = s.clientY - n.startY;
1219
- if (Math.sqrt(b * b + S * S) > 10 && (v(), n.hasMoved = !0), f.slide && n.hasMoved) {
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
1220
  const D = s.currentTarget, c = g(D);
1221
1221
  if (n.isTouch && !n.sliding) {
1222
- const $e = Math.abs(c === "vertical" ? S : b), ke = Math.abs(c === "vertical" ? b : S);
1222
+ const $e = Math.abs(c === "vertical" ? C : b), ke = Math.abs(c === "vertical" ? b : C);
1223
1223
  if ($e < ke) return;
1224
1224
  }
1225
1225
  n.sliding = !0;
1226
- const Y = f.slide.min ?? 0, N = f.slide.max ?? 100, we = N - Y, pe = c === "vertical" ? -S : 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));
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
1227
  f.slide.onChange(Math.round(ye)), n.startX = s.clientX, n.startY = s.clientY, s.preventDefault();
1228
1228
  }
1229
1229
  }, w = (s) => {
1230
- const f = e(), b = n.isDown, S = Date.now() - n.startTime, z = f.hold?.delay ?? 300;
1231
- v(), b && f.tap && !n.hasMoved && S < z && f.tap();
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
1232
  try {
1233
1233
  s.currentTarget.releasePointerCapture(s.pointerId);
1234
1234
  } catch {
@@ -1251,7 +1251,7 @@ function un(e, t) {
1251
1251
  };
1252
1252
  return {
1253
1253
  onPointerDown: a,
1254
- onPointerMove: C,
1254
+ onPointerMove: S,
1255
1255
  onPointerUp: w,
1256
1256
  onPointerCancel: M,
1257
1257
  onPointerEnter: (s) => {
@@ -1304,9 +1304,18 @@ const gn = Object.fromEntries(
1304
1304
  /** Optional display name override (renders as text input) */
1305
1305
  title: () => A.string().optional().meta({ title: "Title", description: "Optional display name override" }),
1306
1306
  /** Multi-select entity picker for a HA domain */
1307
- entityIds: (e) => A.array(A.string()).default([]).meta({ domain: e, title: "Entities" }),
1307
+ entityIds: (e, t) => A.array(A.string()).default([]).meta({
1308
+ domain: e,
1309
+ title: "Entities",
1310
+ ...t?.deviceClass ? { deviceClass: t.deviceClass } : {}
1311
+ }),
1308
1312
  /** Single-select entity picker for a HA domain */
1309
- singleEntity: (e) => A.array(A.string()).default([]).meta({ domain: e, title: "Entity", singleSelect: !0 }),
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
+ }),
1310
1319
  /** Area picker dropdown */
1311
1320
  areaId: () => A.string().optional().meta({ formType: "area-picker", title: "Area" })
1312
1321
  };
@@ -1340,7 +1349,7 @@ function mn(e) {
1340
1349
  function vn() {
1341
1350
  return document.documentElement.classList.contains("dark");
1342
1351
  }
1343
- const Lt = "1.1.0", Ut = {
1352
+ const Lt = "1.2.0", Ut = {
1344
1353
  version: Lt
1345
1354
  }, wn = Ut.version;
1346
1355
  export {
@@ -1376,8 +1385,8 @@ export {
1376
1385
  gn as svgColors,
1377
1386
  Fn as trackEntityHistory,
1378
1387
  Gn as untrackEntityHistory,
1379
- Sn as useArea,
1380
- Cn as useCamera,
1388
+ Cn as useArea,
1389
+ Sn as useCamera,
1381
1390
  Mn as useConnection,
1382
1391
  Dn as useCurrency,
1383
1392
  Tn as useEntities,
@@ -1,26 +1,26 @@
1
- import { createHash as _ } from "node:crypto";
2
- import { existsSync as l, rmSync as R, mkdirSync as D, readdirSync as I, statSync as k, readFileSync as w, writeFileSync as p } from "node:fs";
1
+ import { createHash as R } from "node:crypto";
2
+ import { existsSync as l, rmSync as T, mkdirSync as D, readdirSync as I, statSync as P, readFileSync as g, writeFileSync as w } from "node:fs";
3
3
  import { createRequire as F } from "node:module";
4
- import { resolve as a, join as d, dirname as y, sep as x } from "node:path";
5
- import { fileURLToPath as T } from "node:url";
6
- import { widgetManifestSchema as U, formatSchemaError as C } from "@glasshome/widget-contract";
7
- import H from "@tailwindcss/vite";
4
+ import { resolve as c, join as u, dirname as y, sep as x } from "node:path";
5
+ import { fileURLToPath as H } from "node:url";
6
+ import { widgetManifestSchema as U, formatSchemaError as A } from "@glasshome/widget-contract";
7
+ import C from "@tailwindcss/vite";
8
8
  function L(e) {
9
9
  const t = JSON.stringify(e, Object.keys(e).sort());
10
- return _("sha256").update(t).digest("hex").slice(0, 16);
10
+ return R("sha256").update(t).digest("hex").slice(0, 16);
11
11
  }
12
- const J = "virtual:glasshome-widget", P = "\0virtual:glasshome-widget", A = "/@glasshome/preview";
13
- function h(e) {
12
+ const V = "virtual:glasshome-widget", E = "\0virtual:glasshome-widget", B = "/@glasshome/preview";
13
+ function p(e) {
14
14
  return x === "\\" ? e.split(x).join("/") : e;
15
15
  }
16
16
  function S() {
17
- const e = T(import.meta.url);
18
- return a(y(e), "../../preview");
17
+ const e = H(import.meta.url);
18
+ return c(y(e), "../../preview");
19
19
  }
20
- function $(e) {
20
+ function k(e) {
21
21
  return e === "solid-js" || e.startsWith("solid-js/") || e === "@glasshome/widget-sdk" || e.startsWith("@glasshome/widget-sdk/") || e === "@glasshome/ui" || e.startsWith("@glasshome/ui/");
22
22
  }
23
- function j() {
23
+ function O() {
24
24
  return {
25
25
  name: "glasshome-widget:sync-layer-guard",
26
26
  apply: "build",
@@ -33,35 +33,57 @@ function j() {
33
33
  }
34
34
  };
35
35
  }
36
- const B = "node_modules/.cache/glasshome-widgets";
37
- function E(e) {
36
+ const J = "node_modules/.cache/glasshome-widgets";
37
+ function $(e) {
38
38
  try {
39
- return F(d(process.cwd(), "package.json")).resolve(e);
39
+ return F(u(process.cwd(), "package.json")).resolve(e);
40
40
  } catch {
41
41
  return null;
42
42
  }
43
43
  }
44
- function O(e, t, n) {
45
- const o = a(e, B);
46
- D(o, { recursive: !0 });
47
- const i = E("@glasshome/ui/styles");
48
- if (!i)
44
+ const G = [
45
+ "--radius",
46
+ "--background",
47
+ "--foreground",
48
+ "--card",
49
+ "--primary",
50
+ "--border",
51
+ "--muted",
52
+ "--accent"
53
+ ];
54
+ function j(e, t) {
55
+ const i = u(e, `${t}.css`);
56
+ if (!l(i)) return;
57
+ const n = g(i, "utf-8");
58
+ for (const o of n.matchAll(/:host[^{]*\{([^}]*)\}/g)) {
59
+ const s = o[1] ?? "", r = G.find((a) => s.includes(`${a}:`));
60
+ if (r)
61
+ throw new Error(
62
+ `[glasshome-widget] "${t}.css" defines theme variable "${r}" on :host. Theme variables must inherit from the document so widgets follow the household theme — never re-scope them into the widget's shadow root.`
63
+ );
64
+ }
65
+ }
66
+ function N(e, t, i) {
67
+ const n = c(e, J);
68
+ D(n, { recursive: !0 });
69
+ const o = $("@glasshome/ui/styles");
70
+ if (!o)
49
71
  throw new Error(
50
72
  "[widget-sdk] @glasshome/ui is required to build widgets (it provides the theme every GlassHome widget ships with). Add it to your widget's dependencies."
51
73
  );
52
- const s = a(y(i), "../.."), r = E("@glasshome/widget-sdk/tailwind-sources"), c = r ? y(r) : null, g = [
53
- d(s, "src"),
54
- d(s, "dist"),
55
- ...c ? [d(c, "src"), d(c, "dist")] : [],
56
- y(n)
57
- ].filter((u) => l(u)), m = a(o, `${t}.tailwind.css`);
58
- p(
74
+ const s = c(y(o), "../.."), r = $("@glasshome/widget-sdk/tailwind-sources"), a = r ? y(r) : null, h = [
75
+ u(s, "src"),
76
+ u(s, "dist"),
77
+ ...a ? [u(a, "src"), u(a, "dist")] : [],
78
+ y(i)
79
+ ].filter((d) => l(d)), m = c(n, `${t}.tailwind.css`);
80
+ w(
59
81
  m,
60
82
  [
61
83
  '@import "tailwindcss" source(none);',
62
84
  '@import "tw-animate-css";',
63
85
  '@import "@glasshome/ui/styles/theme";',
64
- ...g.map((u) => `@source "${h(u)}";`),
86
+ ...h.map((d) => `@source "${p(d)}";`),
65
87
  "@custom-variant dark {",
66
88
  " &:is(.dark *) { @slot }",
67
89
  " :host(.dark) & { @slot }",
@@ -70,84 +92,84 @@ function O(e, t, n) {
70
92
  ].join(`
71
93
  `)
72
94
  );
73
- const f = a(o, `${t}.entry.ts`);
74
- return p(
95
+ const f = c(n, `${t}.entry.ts`);
96
+ return w(
75
97
  f,
76
98
  [
77
- `import "${h(m)}";`,
78
- `export { default } from "${h(n)}";`,
99
+ `import "${p(m)}";`,
100
+ `export { default } from "${p(i)}";`,
79
101
  ""
80
102
  ].join(`
81
103
  `)
82
104
  ), f;
83
105
  }
84
- function W() {
85
- const e = H();
106
+ function _() {
107
+ const e = C();
86
108
  for (const t of e)
87
109
  t.apply ??= "build";
88
110
  return e;
89
111
  }
90
- function G(e) {
112
+ function q(e) {
91
113
  const t = [];
92
114
  if (!l(e)) return t;
93
- for (const n of I(e)) {
94
- const o = a(e, n);
95
- if (!k(o).isDirectory()) continue;
96
- const i = a(o, "index.tsx"), s = a(o, "manifest.json");
97
- l(i) && l(s) && t.push({ name: n, entry: i });
115
+ for (const i of I(e)) {
116
+ const n = c(e, i);
117
+ if (!P(n).isDirectory()) continue;
118
+ const o = c(n, "index.tsx"), s = c(n, "manifest.json");
119
+ l(o) && l(s) && t.push({ name: i, entry: o });
98
120
  }
99
121
  return t;
100
122
  }
101
- function V(e, t) {
102
- const n = [];
123
+ function z(e, t) {
124
+ const i = [];
103
125
  if (l(e))
104
- for (const i of I(e)) {
105
- if (!k(d(e, i)).isDirectory()) continue;
106
- const s = d(e, i, "manifest.json");
126
+ for (const o of I(e)) {
127
+ if (!P(u(e, o)).isDirectory()) continue;
128
+ const s = u(e, o, "manifest.json");
107
129
  if (!l(s)) continue;
108
130
  const r = U.safeParse(
109
- JSON.parse(w(s, "utf-8"))
131
+ JSON.parse(g(s, "utf-8"))
110
132
  );
111
133
  if (!r.success)
112
134
  throw new Error(
113
- `[registry] Invalid manifest for "${i}": ${C(r.error)}`
135
+ `[registry] Invalid manifest for "${o}": ${A(r.error)}`
114
136
  );
115
- const c = l(d(t, `${i}.css`));
116
- n.push({
137
+ const a = l(u(t, `${o}.css`));
138
+ i.push({
117
139
  ...r.data,
118
- bundleUrl: `./${i}.js`,
119
- ...c ? { cssUrl: `./${i}.css` } : {}
140
+ bundleUrl: `./${o}.js`,
141
+ ...a ? { cssUrl: `./${o}.css` } : {}
120
142
  });
121
143
  }
122
- const o = {
144
+ const n = {
123
145
  version: 1,
124
146
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
125
147
  baseUrl: "./",
126
- widgets: n
148
+ widgets: i
127
149
  };
128
- l(t) || D(t, { recursive: !0 }), p(d(t, "registry.json"), JSON.stringify(o, null, 2)), console.log(`[registry] Generated registry.json with ${n.length} widget(s)`);
150
+ l(t) || D(t, { recursive: !0 }), w(u(t, "registry.json"), JSON.stringify(n, null, 2)), console.log(`[registry] Generated registry.json with ${i.length} widget(s)`);
129
151
  }
130
- async function q(e) {
131
- const { build: t } = await import("vite"), n = process.cwd(), o = a(n, e?.srcDir ?? "src"), i = a(n, e?.outDir ?? "dist");
132
- let s = G(o);
152
+ async function M(e) {
153
+ const { build: t } = await import("vite"), i = process.cwd(), n = c(i, e?.srcDir ?? "src"), o = c(i, e?.outDir ?? "dist");
154
+ let s = q(n);
133
155
  if (s.length === 0) {
134
- console.warn("[glasshome-widgets] No widgets found in", o);
156
+ console.warn("[glasshome-widgets] No widgets found in", n);
135
157
  return;
136
158
  }
137
159
  if (e?.only) {
138
160
  const r = new Set(e.only);
139
- s = s.filter((c) => r.has(c.name));
161
+ s = s.filter((a) => r.has(a.name));
140
162
  }
141
- e?.only || l(i) && R(i, { recursive: !0 }), l(i) || D(i, { recursive: !0 });
163
+ e?.only || l(o) && T(o, { recursive: !0 }), l(o) || D(o, { recursive: !0 });
142
164
  for (const r of s)
143
165
  await t({
144
166
  configFile: !1,
145
- root: n,
146
- plugins: [...W(), ...e?.plugins ?? [], j()],
167
+ root: i,
168
+ plugins: [..._(), ...e?.plugins ?? [], O()],
147
169
  ...e?.viteConfig,
148
170
  build: {
149
171
  lib: {
150
- entry: O(n, r.name, r.entry),
172
+ entry: N(i, r.name, r.entry),
151
173
  formats: ["es"],
152
174
  fileName: r.name,
153
175
  // Widget CSS ships as a separate asset (adopted by the host's
@@ -155,19 +177,19 @@ async function q(e) {
155
177
  cssFileName: r.name
156
178
  },
157
179
  rollupOptions: {
158
- external: $
180
+ external: k
159
181
  },
160
- outDir: i,
182
+ outDir: o,
161
183
  emptyOutDir: !1,
162
184
  copyPublicDir: !1,
163
185
  ...e?.viteConfig?.build
164
186
  },
165
187
  logLevel: "warn"
166
- });
167
- V(o, i);
188
+ }), j(o, r.name);
189
+ z(n, o);
168
190
  }
169
- function ee(e) {
170
- const t = e?.entry ?? "src/index.tsx", n = {
191
+ function te(e) {
192
+ const t = e?.entry ?? "src/index.tsx", i = {
171
193
  name: "glasshome-widget:build",
172
194
  apply: "build",
173
195
  config() {
@@ -175,100 +197,101 @@ function ee(e) {
175
197
  return {
176
198
  build: {
177
199
  lib: {
178
- entry: O(s, "index", a(s, t)),
200
+ entry: N(s, "index", c(s, t)),
179
201
  formats: ["es"],
180
202
  fileName: "index",
181
203
  cssFileName: "index"
182
204
  },
183
205
  rollupOptions: {
184
- external: $
206
+ external: k
185
207
  }
186
208
  }
187
209
  };
188
210
  }
189
- }, o = {
211
+ }, n = {
190
212
  name: "glasshome-widget:dev",
191
213
  apply: "serve",
192
214
  enforce: "pre",
193
215
  config() {
194
- const s = S(), r = process.cwd(), c = a(r, "..", "..");
216
+ const s = S(), r = process.cwd(), a = c(r, "..", "..");
195
217
  return {
196
218
  server: {
197
219
  fs: {
198
- allow: [s, r, c]
220
+ allow: [s, r, a]
199
221
  }
200
222
  }
201
223
  };
202
224
  },
203
225
  configureServer(s) {
204
- const r = S(), c = d(r, "preview.html");
205
- s.middlewares.use(async (g, m, f) => {
206
- if (g.url === "/" || g.url === "/index.html")
226
+ const r = S(), a = u(r, "preview.html");
227
+ s.middlewares.use(async (h, m, f) => {
228
+ if (h.url === "/" || h.url === "/index.html")
207
229
  try {
208
- let u = w(c, "utf-8");
209
- u = await s.transformIndexHtml(g.url, u), m.setHeader("Content-Type", "text/html"), m.statusCode = 200, m.end(u);
210
- } catch (u) {
211
- f(u);
230
+ let d = g(a, "utf-8");
231
+ d = await s.transformIndexHtml(h.url, d), m.setHeader("Content-Type", "text/html"), m.statusCode = 200, m.end(d);
232
+ } catch (d) {
233
+ f(d);
212
234
  }
213
235
  else
214
236
  f();
215
237
  });
216
238
  },
217
239
  resolveId(s) {
218
- if (s === A) {
240
+ if (s === B) {
219
241
  const r = S();
220
- return h(d(r, "host.tsx"));
242
+ return p(u(r, "host.tsx"));
221
243
  }
222
- if (s === J)
223
- return P;
244
+ if (s === V)
245
+ return E;
224
246
  },
225
247
  load(s) {
226
- if (s === P)
227
- return `export { default } from "${h(a(process.cwd(), t))}";`;
248
+ if (s === E)
249
+ return `export { default } from "${p(c(process.cwd(), t))}";`;
228
250
  }
229
- }, i = {
251
+ }, o = {
230
252
  name: "glasshome-widget:schema",
231
253
  apply: "build",
232
254
  async closeBundle() {
233
- const s = a(process.cwd(), "dist", "index.js");
255
+ j(c(process.cwd(), "dist"), "index");
256
+ const s = c(process.cwd(), "dist", "index.js");
234
257
  if (l(s))
235
258
  try {
236
- const c = (await import(`${s}?t=${Date.now()}`)).default;
237
- if (!c?.configSchema) return;
238
- const { z: g } = await import("zod"), m = g.toJSONSchema(c.configSchema, { unrepresentable: "any" }), f = a(process.cwd(), "manifest.json");
259
+ const a = (await import(`${s}?t=${Date.now()}`)).default;
260
+ if (!a?.configSchema) return;
261
+ const { z: h } = await import("zod"), m = h.toJSONSchema(a.configSchema, { unrepresentable: "any" }), f = c(process.cwd(), "manifest.json");
239
262
  if (l(f)) {
240
- const b = JSON.parse(w(f, "utf-8"));
241
- b.schema = m, p(f, JSON.stringify(b, null, 2));
263
+ const b = JSON.parse(g(f, "utf-8"));
264
+ b.schema = m, w(f, JSON.stringify(b, null, 2));
242
265
  }
243
- const u = L(m), v = a(process.cwd(), ".schema-hash");
244
- if (l(v) && w(v, "utf-8").trim() !== u) {
245
- const N = c.manifest?.name ?? "unknown";
266
+ const d = L(m), v = c(process.cwd(), ".schema-hash");
267
+ if (l(v) && g(v, "utf-8").trim() !== d) {
268
+ const W = a.manifest?.name ?? "unknown";
246
269
  console.warn(
247
- `[widget-sdk] Schema shape changed for "${N}" — verify configVersion was bumped`
270
+ `[widget-sdk] Schema shape changed for "${W}" — verify configVersion was bumped`
248
271
  );
249
272
  }
250
- p(v, u);
273
+ w(v, d);
251
274
  } catch {
252
275
  }
253
276
  }
254
277
  };
255
- return [...W(), n, j(), i, o];
278
+ return [..._(), i, O(), o, n];
256
279
  }
257
- function se(e) {
258
- const t = e?.srcDir ?? "src", n = e?.outDir ?? "dist";
259
- let o = [];
280
+ function re(e) {
281
+ const t = e?.srcDir ?? "src", i = e?.outDir ?? "dist";
282
+ let n = [];
260
283
  return [{
261
284
  name: "glasshome-widgets:build",
262
285
  apply: "build",
263
286
  config(s) {
264
- return o = (s.plugins ?? []).flat().filter(Boolean).filter(
287
+ return n = (s.plugins ?? []).flat().filter(Boolean).filter(
265
288
  (r) => !r.name?.startsWith("glasshome-widgets:")
266
289
  ), {
267
290
  build: {
268
291
  rollupOptions: {
269
292
  input: { __glasshome_noop: "\0glasshome-noop" }
270
293
  },
271
- outDir: n,
294
+ outDir: i,
272
295
  copyPublicDir: !1
273
296
  }
274
297
  };
@@ -280,19 +303,19 @@ function se(e) {
280
303
  if (s === "\0glasshome-noop") return "export {}";
281
304
  },
282
305
  async closeBundle() {
283
- await q({
306
+ await M({
284
307
  srcDir: t,
285
- outDir: n,
286
- plugins: o
308
+ outDir: i,
309
+ plugins: n
287
310
  });
288
311
  }
289
312
  }];
290
313
  }
291
314
  export {
292
- q as buildWidgets,
293
- G as discoverWidgets,
294
- V as generateRegistry,
295
- ee as glasshomeWidget,
296
- se as glasshomeWidgets,
297
- $ as isWidgetExternal
315
+ M as buildWidgets,
316
+ q as discoverWidgets,
317
+ z as generateRegistry,
318
+ te as glasshomeWidget,
319
+ re as glasshomeWidgets,
320
+ k as isWidgetExternal
298
321
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glasshome/widget-sdk",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "SDK for building GlassHome dashboard widgets with SolidJS",
5
5
  "keywords": [
6
6
  "glasshome",