@glasshome/widget-sdk 1.8.1 → 1.9.1

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.
@@ -40,6 +40,22 @@ var e = "https://glasshome.app/docs/widget-sdk/config", t = [
40
40
  docsUrl: e,
41
41
  sourcePattern: "\\bareaId\\s*:\\s*z\\.string\\("
42
42
  },
43
+ {
44
+ id: "ctx.dimensions",
45
+ since: "1.9.0",
46
+ removeIn: "2.0.0",
47
+ replacement: "useWidgetDimensions()",
48
+ docsUrl: "https://glasshome.app/docs/widget-api-reference",
49
+ sourcePattern: "\\.dimensions\\(\\)"
50
+ },
51
+ {
52
+ id: "direct-ui-import",
53
+ since: "1.9.0",
54
+ removeIn: "2.0.0",
55
+ replacement: "the same export from \"@glasshome/widget-sdk\" (keep @glasshome/ui installed: its styles stay in the build)",
56
+ docsUrl: "https://glasshome.app/docs/widget-styling#importing-ui-components",
57
+ sourcePattern: "from\\s+[\"']@glasshome/ui(/[^\"']*)?[\"']"
58
+ },
43
59
  {
44
60
  id: "raw-zod-config",
45
61
  since: "1.4.0",
@@ -13,7 +13,9 @@ import { z, type ZodType } from "zod";
13
13
  * key is optional. Erasing it silently diverges `Infer` from raw `z.infer` (a key
14
14
  * becomes `x: T | undefined` instead of `x?: T`), so the concrete types are load-bearing.
15
15
  *
16
- * SchemaForm renders a FLAT object only; `field.group` is the sole nested exception.
16
+ * SchemaForm renders a flat object plus the nested shapes declared here:
17
+ * `field.group` (one level), `field.list` (array of items, depth 1), and
18
+ * `field.variants` (discriminated union, legal top-level or inside a list).
17
19
  */
18
20
  /** A single config field. Structurally a zod schema producing `T`. */
19
21
  export type Field<T> = ZodType<T>;
@@ -91,6 +93,35 @@ declare function group<S extends ConfigShape>(shape: S, o: {
91
93
  }): Field<{
92
94
  [K in keyof S]: Infer<S[K]>;
93
95
  }>;
96
+ type ListOpts = {
97
+ title: string;
98
+ description?: string;
99
+ min?: number;
100
+ max: number;
101
+ addLabel?: string;
102
+ /** Field name whose value captions the collapsed item row. Must exist in
103
+ * every item (for variants: in `shared` or common to all variants). A name,
104
+ * not a function: it has to survive JSON serialization. */
105
+ labelField?: string;
106
+ };
107
+ type VariantShapes = Record<string, ConfigShape>;
108
+ type VariantsOpts<V extends VariantShapes, S extends ConfigShape> = {
109
+ title: string;
110
+ description?: string;
111
+ /** Display names for the discriminator Select, keyed by variant kind. */
112
+ labels?: {
113
+ [K in keyof V]?: string;
114
+ };
115
+ /** Fields merged into every variant (variant-specific fields win on collision). */
116
+ shared?: S;
117
+ };
118
+ type VariantsOutput<D extends string, V extends VariantShapes, S extends ConfigShape> = {
119
+ [K in keyof V & string]: z.output<z.ZodObject<{
120
+ [P in D]: z.ZodLiteral<K>;
121
+ } & S & V[K]>>;
122
+ }[keyof V & string];
123
+ declare function list<Item extends ZodType>(item: Item, o: ListOpts): Field<Array<z.output<Item>>>;
124
+ declare function variants<D extends string, V extends VariantShapes, S extends ConfigShape = Record<never, never>>(discriminator: D, variantShapes: V, o: VariantsOpts<V, S>): Field<VariantsOutput<D, V, S>>;
94
125
  export declare const field: {
95
126
  title: typeof title;
96
127
  text: typeof text;
@@ -103,6 +134,8 @@ export declare const field: {
103
134
  icon: typeof icon;
104
135
  stringList: typeof stringList;
105
136
  group: typeof group;
137
+ list: typeof list;
138
+ variants: typeof variants;
106
139
  };
107
140
  export declare function defineConfig<S extends ConfigShape>(shape: S): z.ZodObject<{ -readonly [P in keyof S]: S[P]; }, z.core.$strip>;
108
141
  export {};
@@ -2,8 +2,8 @@
2
2
  * Widget — main container component.
3
3
  *
4
4
  * Renders the shell (gradient, border highlight, channel vars) and provides
5
- * a minimal context (isEditMode, updateConfig) for slot components and host
6
- * RPC. All visual scale (icon size, text size, padding, gap, content layout
5
+ * a minimal context (updateConfig, host RPC) plus the measured-size context
6
+ * for `useWidgetDimensions()`. All visual scale (icon size, text size, padding, gap, content layout
7
7
  * direction, slider fill orientation) lives in pure CSS via container queries
8
8
  * on `.glasshome-widget`. The widget reacts to its own rendered box without
9
9
  * any JS measurement.
@@ -0,0 +1,8 @@
1
+ import type { ZodType } from "zod";
2
+ /**
3
+ * Save-gate for the widget dialog's schema editor: runs the widget's real zod
4
+ * config schema over the draft. Returns readable message strings for the
5
+ * SchemaForm `errors` prop, or null when the draft is valid. Cross-item rules
6
+ * (zod `.check()` on an array) land at the list path, e.g. "nodes: <message>".
7
+ */
8
+ export declare function validateConfigDraft(schema: ZodType, draft: Record<string, unknown>): string[] | null;
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Hooks for widget development: context, dialog, entity group.
5
5
  */
6
- export { type ReactiveWidgetContext, type ServiceCallFn, useWidgetContext, WidgetCtx, } from "./use-widget-context";
6
+ export { type ReactiveWidgetContext, type ServiceCallFn, useWidgetContext, WidgetCtx, type WidgetDimensions, } from "./use-widget-context";
7
+ export { useWidgetDimensions, type WidgetDimensionsAccessor, WidgetSizeCtx, } from "./use-widget-dimensions";
7
8
  export { useIntersectionPause } from "./use-intersection-pause";
8
9
  export { useReducedMotion } from "./use-reduced-motion";
9
10
  export { useWidgetDialog, type WidgetDialogReturn } from "./use-widget-dialog";
@@ -3,13 +3,9 @@
3
3
  *
4
4
  * Visual scale (icon size, text size, padding, layout direction) lives in
5
5
  * CSS via container queries on `.glasshome-widget`. This context only
6
- * carries:
7
- * - host RPC (updateConfig)
8
- * - edit-mode flag
9
- * - raw measured dimensions (for widgets that branch rendered content
10
- * based on size — e.g. hide a forecast strip on small chips).
11
- *
12
- * Widgets decide their own thresholds; there is no shared size tier.
6
+ * carries host RPC (updateConfig, dialog opener, service calls) plus the
7
+ * deprecated `dimensions` accessor; size reads go through
8
+ * `useWidgetDimensions()`, which only exists inside `<Widget>`.
13
9
  */
14
10
  export interface WidgetDimensions {
15
11
  width: number;
@@ -19,9 +15,12 @@ export interface WidgetDimensions {
19
15
  validated there against the widget's granted capabilities. */
20
16
  export type ServiceCallFn = (domain: string, service: string, serviceData?: Record<string, unknown>, target?: Record<string, unknown>) => Promise<void>;
21
17
  export interface ReactiveWidgetContext {
22
- isEditMode: () => boolean;
23
18
  updateConfig: (config: Record<string, unknown>) => void;
24
- /** Measured shell dimensions in CSS px. (0,0) before first layout. */
19
+ /**
20
+ * Measured shell dimensions in CSS px. (0,0) before first layout.
21
+ * @deprecated since 1.9.0, removed in 2.0.0. Use `useWidgetDimensions()`
22
+ * (throws outside `<Widget>` instead of silently reading the host stub).
23
+ */
25
24
  dimensions: () => WidgetDimensions;
26
25
  /** Host RPC: `useWidgetDialog` registers its opener here so the host can
27
26
  open the widget's dialog on a chosen tab. Called with `null` on cleanup. */
@@ -0,0 +1,14 @@
1
+ import type { WidgetDimensions } from "./use-widget-context";
2
+ export type WidgetDimensionsAccessor = () => WidgetDimensions;
3
+ /**
4
+ * Provided only by `<Widget>` (ResizeObserver-measured shell box). Unlike
5
+ * `WidgetCtx`, the host's pre-`<Widget>` stub never provides it, so a read
6
+ * from the wrong scope throws instead of silently returning (0,0).
7
+ */
8
+ export declare const WidgetSizeCtx: import("solid-js").Context<WidgetDimensionsAccessor | undefined>;
9
+ /**
10
+ * Reactive accessor for the widget shell's measured dimensions (CSS px,
11
+ * (0,0) before first layout). Must be called inside `<Widget>`; called from
12
+ * the top-level widget scope it throws instead of freezing on the host stub.
13
+ */
14
+ export declare function useWidgetDimensions(): WidgetDimensionsAccessor;
@@ -37,7 +37,7 @@ export { WidgetTitle } from "./components/WidgetTitle";
37
37
  export { WidgetValue } from "./components/WidgetValue";
38
38
  export { WidgetSliderFill } from "./backgrounds/WidgetSliderFill";
39
39
  export { WidgetDialog, type WidgetDialogProps, type WidgetDialogTab } from "./dialogs";
40
- export { type AggregationPreset, type ReactiveWidgetContext, type ServiceCallFn, type UseWidgetEntityGroupOptions, type UseWidgetEntityGroupResult, useIntersectionPause, useReducedMotion, useWidgetContext, useWidgetDialog, useWidgetEntityGroup, WidgetCtx, type WidgetDialogReturn, } from "./hooks";
40
+ export { type AggregationPreset, type ReactiveWidgetContext, type ServiceCallFn, type UseWidgetEntityGroupOptions, type UseWidgetEntityGroupResult, useIntersectionPause, useReducedMotion, useWidgetContext, useWidgetDialog, useWidgetDimensions, useWidgetEntityGroup, WidgetCtx, type WidgetDialogReturn, type WidgetDimensions, type WidgetDimensionsAccessor, WidgetSizeCtx, } from "./hooks";
41
41
  export { type GestureHandlers, useWidgetGestures } from "./gestures/use-widget-gestures";
42
42
  export { injectTokens, type SvgColorKey, svgColors, type Tone, ToneSchema, } from "./theming";
43
43
  export { widgetFields } from "./fields";
@@ -1,6 +1,6 @@
1
- import { n as e, t } from "../tokens-Bdfb1xYe.js";
2
- import { ErrorBoundary as n, createComponent as r } from "solid-js";
3
- import { render as i } from "solid-js/web";
1
+ import { ErrorBoundary as e, createComponent as t } from "solid-js";
2
+ import { render as n } from "solid-js/web";
3
+ import { WidgetCtx as r, injectTokens as i } from "@glasshome/widget-sdk";
4
4
  //#region src/host/instantiate-widget.ts
5
5
  var a = /* @__PURE__ */ new Map();
6
6
  function o(e) {
@@ -26,17 +26,17 @@ function d(e, t) {
26
26
  }
27
27
  function f(a, s) {
28
28
  let c = a.attachShadow({ mode: "closed" }), l = d(a, s.mirrorClasses ?? ["dark"]);
29
- t(c), s.cssText !== null && (c.adoptedStyleSheets = [...c.adoptedStyleSheets, o(s.cssText)]), s.extraSheets?.length && (c.adoptedStyleSheets = [...c.adoptedStyleSheets, ...s.extraSheets]);
30
- let u = i(() => r(e.Provider, {
29
+ i(c), s.cssText !== null && (c.adoptedStyleSheets = [...c.adoptedStyleSheets, o(s.cssText)]), s.extraSheets?.length && (c.adoptedStyleSheets = [...c.adoptedStyleSheets, ...s.extraSheets]);
30
+ let u = n(() => t(r.Provider, {
31
31
  value: s.ctx,
32
32
  get children() {
33
- return r(n, {
33
+ return t(e, {
34
34
  fallback: (e) => {
35
35
  let t = e instanceof Error ? e : Error(String(e));
36
36
  return queueMicrotask(() => s.onCrash(t)), null;
37
37
  },
38
38
  get children() {
39
- return r(s.definition.component, { get config() {
39
+ return t(s.definition.component, { get config() {
40
40
  return s.config();
41
41
  } });
42
42
  }
@@ -1,6 +1,5 @@
1
+ import type { ReactiveWidgetContext, WidgetDefinition } from "@glasshome/widget-sdk";
1
2
  import { type Accessor } from "solid-js";
2
- import type { ReactiveWidgetContext } from "../framework/hooks/use-widget-context";
3
- import type { WidgetDefinition } from "../types";
4
3
  export interface WidgetInstanceHandle {
5
4
  dispose: () => void;
6
5
  }
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { defineWidget } from "./define-widget";
2
2
  export * from "./data";
3
3
  export * from "./framework";
4
4
  export { monotoneCubicPath } from "./shared/spline";
5
+ export * from "./ui";
5
6
  export { formatSchemaError, WidgetManifestSchema } from "./schemas";
6
7
  export { isDark } from "./theme";
7
8
  export type { GridSize, WidgetContext, WidgetDefinition, WidgetExample, WidgetManifest, } from "./types";