@glasshome/widget-sdk 0.4.0 → 0.4.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.
package/dist/theme.d.ts CHANGED
@@ -1,19 +1,7 @@
1
1
  /**
2
2
  * Theme utilities — plain DOM reads.
3
3
  * Framework-agnostic: no SolidJS imports.
4
- *
5
- * These functions read CSS custom properties and class state from the
6
- * document root. They are synchronous and work in any browser environment.
7
4
  */
8
- /**
9
- * Read a CSS custom property (theme token) from the document root.
10
- * Automatically prepends "--" if not already present.
11
- *
12
- * @example
13
- * getThemeToken("color-primary") // reads --color-primary
14
- * getThemeToken("--color-primary") // also works
15
- */
16
- export declare function getThemeToken(name: string): string;
17
5
  /**
18
6
  * Check whether the current theme is dark mode.
19
7
  * Reads the presence of the "dark" class on <html>.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glasshome/widget-sdk",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "SDK for building GlassHome dashboard widgets with SolidJS",
5
5
  "keywords": [
6
6
  "glasshome",
@@ -1,22 +0,0 @@
1
- /**
2
- * SolidJS-specific utility — NOT part of the framework-agnostic SDK contract.
3
- * This module uses SolidJS signals for reactive entity state management.
4
- * It is exported from the SDK as a convenience for SolidJS widget authors.
5
- */
6
- import { type Accessor } from "solid-js";
7
- export interface Entity {
8
- id: string;
9
- state: string;
10
- attributes: Record<string, unknown>;
11
- last_updated?: string;
12
- }
13
- /**
14
- * Create a reactive entity signal. Returns a signal accessor that tracks
15
- * entity state changes.
16
- *
17
- * NOTE: The setter from `createSignal` is intentionally destructured away.
18
- * The signal infrastructure is kept in place so that when the sync-layer is
19
- * ported, the runtime can update entity state reactively without changing
20
- * the public API surface. Until then the accessor behaves as a constant.
21
- */
22
- export declare function createEntity(initialState: Entity): Accessor<Entity>;
@@ -1,36 +0,0 @@
1
- /**
2
- * Glow Component
3
- *
4
- * Channel-driven background glow. Renders a blurred radial gradient at the
5
- * BACKGROUND z-index layer using the Widget's channel color. Defaults to the
6
- * parent Widget's `--widget-color`; pass `color` to override locally.
7
- *
8
- * @example
9
- * ```tsx
10
- * <Widget tone="info">
11
- * <Glow />
12
- * </Widget>
13
- * ```
14
- *
15
- * @example With local override
16
- * ```tsx
17
- * <Glow color="oklch(0.7 0.2 30)" />
18
- * ```
19
- */
20
- import type { JSX } from "solid-js";
21
- interface GlowProps {
22
- /**
23
- * Optional CSS color string override (oklch, hsl, rgb, hex, var()).
24
- * Sets `--widget-color` locally on the Glow element. When omitted the
25
- * parent Widget's channel color cascades in.
26
- * BREAKING (Phase 26): previously a Tailwind color variant key.
27
- */
28
- color?: string;
29
- /** Additional CSS classes */
30
- class?: string;
31
- }
32
- /**
33
- * Glow effect component, channel-driven radial gradient.
34
- */
35
- export declare function Glow(props: GlowProps): JSX.Element;
36
- export {};
@@ -1,35 +0,0 @@
1
- /**
2
- * WidgetEmptyState Component
3
- *
4
- * Placeholder component for widgets with no data or content.
5
- * Shows a centered message with optional icon and action.
6
- *
7
- * @example
8
- * ```tsx
9
- * <Widget.EmptyState
10
- * icon={<AlertCircle />}
11
- * title="No devices found"
12
- * message="Add devices to see them here"
13
- * action={<Button>Add Device</Button>}
14
- * />
15
- * ```
16
- */
17
- import type { JSX } from "solid-js";
18
- interface WidgetEmptyStateProps {
19
- /** Icon to display (optional) */
20
- icon?: JSX.Element;
21
- /** Main title/heading */
22
- title?: string;
23
- /** Descriptive message */
24
- message?: string;
25
- /** Optional action button */
26
- action?: JSX.Element;
27
- /** Additional CSS classes */
28
- class?: string;
29
- }
30
- /**
31
- * Widget empty state component
32
- * Shows centered placeholder when widget has no content
33
- */
34
- export declare function WidgetEmptyState(props: WidgetEmptyStateProps): JSX.Element;
35
- export {};
@@ -1,48 +0,0 @@
1
- /**
2
- * WidgetMetrics Component
3
- *
4
- * Small data displays for showing multiple stats/values.
5
- * Automatically arranges metrics based on widget size.
6
- *
7
- * @example
8
- * ```tsx
9
- * <Widget.Metrics>
10
- * <Widget.Metrics.Item label="Temp" value="72F" />
11
- * <Widget.Metrics.Item label="Humidity" value="45%" />
12
- * <Widget.Metrics.Item label="Battery" value="87%" />
13
- * </Widget.Metrics>
14
- * ```
15
- */
16
- import type { JSX } from "solid-js";
17
- interface WidgetMetricsProps {
18
- /** Layout direction (default: "auto" - horizontal for horizontal widgets, vertical for others) */
19
- direction?: "horizontal" | "vertical" | "auto";
20
- /** Additional CSS classes */
21
- class?: string;
22
- /** Metric items */
23
- children: JSX.Element;
24
- }
25
- interface WidgetMetricsComponent {
26
- (props: WidgetMetricsProps): JSX.Element;
27
- Item: typeof WidgetMetricsItem;
28
- }
29
- interface WidgetMetricsItemProps {
30
- /** Metric label */
31
- label: string;
32
- /** Metric value */
33
- value: string | number;
34
- /** Optional unit */
35
- unit?: string;
36
- /** Optional icon */
37
- icon?: JSX.Element;
38
- /** Whether to dim the metric */
39
- dimmed?: boolean;
40
- /** Additional CSS classes */
41
- class?: string;
42
- }
43
- /**
44
- * Individual metric item
45
- */
46
- declare function WidgetMetricsItem(props: WidgetMetricsItemProps): JSX.Element;
47
- export declare const WidgetMetrics: WidgetMetricsComponent;
48
- export {};
@@ -1,29 +0,0 @@
1
- /**
2
- * WidgetSubtitle Component
3
- *
4
- * Secondary text component below the title with automatic typography scaling.
5
- *
6
- * @example
7
- * ```tsx
8
- * <Widget.Subtitle>Living Room</Widget.Subtitle>
9
- * ```
10
- *
11
- * @example With dimmed style
12
- * ```tsx
13
- * <Widget.Subtitle dimmed>2 devices offline</Widget.Subtitle>
14
- * ```
15
- */
16
- import type { JSX } from "solid-js";
17
- interface WidgetSubtitleProps {
18
- /** Whether to dim the subtitle */
19
- dimmed?: boolean;
20
- /** Additional CSS classes */
21
- class?: string;
22
- /** Subtitle text */
23
- children: JSX.Element;
24
- }
25
- /**
26
- * Widget subtitle component with auto-responsive typography
27
- */
28
- export declare function WidgetSubtitle(props: WidgetSubtitleProps): JSX.Element;
29
- export {};
@@ -1,46 +0,0 @@
1
- /**
2
- * Debug Data Hook
3
- *
4
- * Generates standardized debug data structure for widget dialogs.
5
- * Provides a consistent format for troubleshooting widget configuration and entity state.
6
- *
7
- * @example
8
- * ```tsx
9
- * const debugData = useDebugData({
10
- * widgetConfig: {
11
- * id: config.id,
12
- * type: config.type,
13
- * title: config.title,
14
- * entityIds: config.entityIds,
15
- * },
16
- * entities: () => coverEntities,
17
- * customEntityFields: (entity) => ({
18
- * current_position: entity.attributes?.current_position,
19
- * }),
20
- * });
21
- * ```
22
- */
23
- import { type Accessor } from "solid-js";
24
- import type { EntityView } from "../types";
25
- export interface UseDebugDataOptions {
26
- /** Widget configuration summary */
27
- widgetConfig: {
28
- id: string;
29
- type: string;
30
- title?: string;
31
- entityIds?: string[];
32
- };
33
- /** Reactive entities accessor */
34
- entities: Accessor<EntityView[]>;
35
- /** Additional data to include in debug output */
36
- additionalData?: Record<string, unknown>;
37
- /** Custom entity fields to include per entity */
38
- customEntityFields?: (entity: EntityView) => Record<string, unknown>;
39
- }
40
- /**
41
- * Hook for generating standardized debug data structure
42
- *
43
- * @param options - Debug data configuration
44
- * @returns Reactive debug data object or undefined if no entities
45
- */
46
- export declare function useDebugData(options: UseDebugDataOptions): Accessor<Record<string, unknown> | undefined>;
@@ -1,48 +0,0 @@
1
- /**
2
- * Widget Config Hook
3
- *
4
- * Generalized config management that accepts save/delete callbacks.
5
- * Host-agnostic: the host application provides the actual persistence logic.
6
- *
7
- * @example
8
- * ```tsx
9
- * const { save, remove, isSaving, isDeleting } = useWidgetConfig({
10
- * onSave: async (config) => {
11
- * await api.saveWidgetConfig(widgetId, config);
12
- * },
13
- * onDelete: async () => {
14
- * await api.deleteWidget(widgetId);
15
- * },
16
- * });
17
- *
18
- * // In a form submit handler:
19
- * save({ title: "My Widget", entityIds: ["sensor.temp"] });
20
- * ```
21
- */
22
- export interface UseWidgetConfigOptions<TConfig = Record<string, unknown>> {
23
- /** Callback to save widget configuration */
24
- onSave?: (config: TConfig) => void | Promise<void>;
25
- /** Callback to delete widget */
26
- onDelete?: () => void | Promise<void>;
27
- /** Callback after successful save */
28
- onSaveSuccess?: () => void;
29
- /** Callback after successful delete */
30
- onDeleteSuccess?: () => void;
31
- }
32
- export interface UseWidgetConfigReturn<TConfig = Record<string, unknown>> {
33
- /** Save widget configuration */
34
- save: (config: TConfig) => Promise<void>;
35
- /** Delete widget */
36
- remove: () => Promise<void>;
37
- /** Whether save is in progress */
38
- isSaving: () => boolean;
39
- /** Whether delete is in progress */
40
- isDeleting: () => boolean;
41
- }
42
- /**
43
- * Hook for managing widget configuration save/delete operations
44
- *
45
- * @param options - Configuration with save/delete callbacks
46
- * @returns Save and delete functions with loading states
47
- */
48
- export declare function useWidgetConfig<TConfig = Record<string, unknown>>(options?: UseWidgetConfigOptions<TConfig>): UseWidgetConfigReturn<TConfig>;
@@ -1,53 +0,0 @@
1
- /**
2
- * Widget Entity Hook
3
- *
4
- * Generalized single-entity data binding that accepts a signal-based data source.
5
- * The SDK does NOT import sync-layer -- the host provides entity data via Accessor.
6
- *
7
- * @example
8
- * ```tsx
9
- * // Host provides entity data as a signal
10
- * const entity = () => syncLayer.getEntity("sensor.temperature");
11
- *
12
- * const { data, emptyState, hasEntity } = useWidgetEntity({
13
- * entity,
14
- * calculateData: (e) => ({
15
- * temperature: parseFloat(e.state),
16
- * unit: e.unitOfMeasurement ?? "C",
17
- * }),
18
- * emptyStateConfig: {
19
- * icon: <Thermometer />,
20
- * title: "No climate entity",
21
- * message: "Configure this widget to add a climate device",
22
- * },
23
- * });
24
- * ```
25
- */
26
- import { type Accessor } from "solid-js";
27
- import type { EntityView } from "../types";
28
- import type { WidgetEmptyStateConfig } from "../utils/empty-state";
29
- export interface UseWidgetEntityOptions<TData> {
30
- /** Reactive entity accessor (null when not available) */
31
- entity: Accessor<EntityView | null>;
32
- /** Function to calculate widget-specific data from entity */
33
- calculateData: (entity: EntityView) => TData;
34
- /** Empty state configuration when entity is not available */
35
- emptyStateConfig: WidgetEmptyStateConfig;
36
- }
37
- export interface UseWidgetEntityResult<TData> {
38
- /** The entity (null if not found) */
39
- entity: Accessor<EntityView | null>;
40
- /** Calculated widget data (null if no entity) */
41
- data: Accessor<TData | null>;
42
- /** Empty state config (undefined if entity exists) */
43
- emptyState: Accessor<WidgetEmptyStateConfig | undefined>;
44
- /** Whether entity exists */
45
- hasEntity: Accessor<boolean>;
46
- }
47
- /**
48
- * Hook for single-entity widgets with integrated empty state support
49
- *
50
- * @param options - Entity source, data calculation, and empty state config
51
- * @returns Reactive entity data, empty state, and existence check
52
- */
53
- export declare function useWidgetEntity<TData>(options: UseWidgetEntityOptions<TData>): UseWidgetEntityResult<TData>;
@@ -1,79 +0,0 @@
1
- /**
2
- * Widget Form Hook
3
- *
4
- * Wraps @modular-forms/solid with zodForm validation for widget configuration forms.
5
- * This is the SolidJS equivalent of the React useWidgetForm that used react-hook-form.
6
- *
7
- * @example
8
- * ```tsx
9
- * import { z } from "zod";
10
- *
11
- * const schema = z.object({
12
- * title: z.string().optional(),
13
- * entityIds: z.array(z.string()).min(1),
14
- * showIcon: z.boolean(),
15
- * });
16
- *
17
- * type FormValues = z.infer<typeof schema>;
18
- *
19
- * function MyWidgetSettings() {
20
- * const { form, Form, Field, isDirty, handleSubmit } = useWidgetForm<FormValues>({
21
- * schema,
22
- * initialValues: {
23
- * title: config.title ?? "",
24
- * entityIds: config.entityIds ?? [],
25
- * showIcon: true,
26
- * },
27
- * onSubmit: async (values) => {
28
- * await saveConfig(values);
29
- * },
30
- * });
31
- *
32
- * return (
33
- * <Form onSubmit={handleSubmit}>
34
- * <Field name="title">
35
- * {(field, props) => (
36
- * <input {...props} value={field.value} />
37
- * )}
38
- * </Field>
39
- * </Form>
40
- * );
41
- * }
42
- * ```
43
- */
44
- import { type FieldValues, type FormStore, getValue, reset, type SubmitHandler, setValue } from "@modular-forms/solid";
45
- import type { z } from "zod";
46
- export interface UseWidgetFormOptions<TValues extends FieldValues> {
47
- /** Zod schema for form validation */
48
- schema: z.ZodType<TValues, any, any>;
49
- /** Initial form values */
50
- initialValues: TValues;
51
- /** Submit handler */
52
- onSubmit?: (values: TValues) => void | Promise<void>;
53
- }
54
- export interface UseWidgetFormReturn<TValues extends FieldValues> {
55
- /** The form store */
56
- form: FormStore<TValues, undefined>;
57
- /** Whether form has unsaved changes */
58
- isDirty: () => boolean;
59
- /** Whether form is currently submitting */
60
- isSubmitting: () => boolean;
61
- /** Handle form submission */
62
- handleSubmit: SubmitHandler<TValues>;
63
- /** Get a field value */
64
- getValue: typeof getValue;
65
- /** Set a field value */
66
- setValue: typeof setValue;
67
- /** Reset form to initial values */
68
- reset: typeof reset;
69
- }
70
- /**
71
- * Hook for widget configuration forms using @modular-forms/solid
72
- *
73
- * Callers use the returned form store with `<Form>` and `<Field>` components
74
- * imported directly from @modular-forms/solid.
75
- *
76
- * @param options - Form configuration with schema, initial values, and submit handler
77
- * @returns Form store, derived state, and utility functions
78
- */
79
- export declare function useWidgetForm<TValues extends FieldValues>(options: UseWidgetFormOptions<TValues>): UseWidgetFormReturn<TValues>;
@@ -1,41 +0,0 @@
1
- /**
2
- * Widget Responsive Hook
3
- *
4
- * Provides convenience utilities for responsive behavior based on widget size.
5
- * Uses createMemo for each derived boolean to avoid unnecessary recalculation.
6
- *
7
- * @example
8
- * ```tsx
9
- * const responsive = useWidgetResponsive();
10
- *
11
- * return (
12
- * <div>
13
- * <Show when={responsive.showDetail()}>
14
- * <DetailedMetrics />
15
- * </Show>
16
- * <Show when={responsive.isCompact()}>
17
- * <CompactView />
18
- * </Show>
19
- * </div>
20
- * );
21
- * ```
22
- */
23
- import type { WidgetSize } from "../types";
24
- export interface WidgetResponsiveUtils {
25
- /** xs or sm */
26
- isCompact: () => boolean;
27
- /** lg or xl */
28
- isLarge: () => boolean;
29
- /** md or larger */
30
- showDetail: () => boolean;
31
- /** Check if current size matches any of the provided sizes */
32
- showOn: (sizes: WidgetSize[]) => boolean;
33
- /** Check if current size does NOT match any of the provided sizes */
34
- hideOn: (sizes: WidgetSize[]) => boolean;
35
- /** Check if a size condition matches (e.g., "md+", "sm-") */
36
- matches: (condition: string) => boolean;
37
- }
38
- /**
39
- * Get responsive utilities based on widget context size
40
- */
41
- export declare function useWidgetResponsive(): WidgetResponsiveUtils;
@@ -1,29 +0,0 @@
1
- /**
2
- * WidgetStack Component
3
- *
4
- * Vertical flex layout with automatic responsive spacing.
5
- *
6
- * @example
7
- * ```tsx
8
- * <WidgetStack spacing="S2">
9
- * <Widget.Icon icon={<Power />} />
10
- * <Widget.Title>{title}</Widget.Title>
11
- * <Widget.Status>{status}</Widget.Status>
12
- * </WidgetStack>
13
- * ```
14
- */
15
- import type { JSX } from "solid-js";
16
- import type { SpacingScale } from "../types";
17
- interface WidgetStackProps {
18
- /** Spacing between items (default: "S2") */
19
- spacing?: SpacingScale;
20
- /** Additional CSS classes */
21
- class?: string;
22
- /** Child elements */
23
- children: JSX.Element;
24
- }
25
- /**
26
- * Vertical stack layout with responsive spacing
27
- */
28
- export declare function WidgetStack(props: WidgetStackProps): JSX.Element;
29
- export {};
@@ -1,59 +0,0 @@
1
- /**
2
- * Gradient preset type
3
- */
4
- export type GradientPreset = "ocean" | "sunset" | "forest" | "lavender" | "golden" | "midnight" | "rose" | "mint" | "slate" | "coral" | "aurora" | "ember" | "steel" | "twilight" | "sage" | "copper" | "dusk";
5
- /**
6
- * 17 gradient presets as Tailwind class strings
7
- * Using 20% opacity for subtle background that doesn't overpower content
8
- */
9
- export declare const GRADIENT_PRESETS: Record<GradientPreset, string>;
10
- /** Human-readable gradient names for UI display */
11
- export declare const GRADIENT_NAMES: Record<GradientPreset, string>;
12
- /** Array of all gradient preset keys */
13
- export declare const GRADIENT_PRESET_KEYS: GradientPreset[];
14
- /**
15
- * Get a consistent gradient preset for any string input
16
- * Uses a simple hash to deterministically select a gradient
17
- */
18
- export declare function getGradientFromString(input: string): GradientPreset;
19
- /**
20
- * Get gradient string
21
- * @param gradient - Preset name or gradient string
22
- * @param fallbackString - String to hash for default gradient selection
23
- */
24
- export declare function getGradient(gradient: GradientPreset | string | undefined, fallbackString: string): string;
25
- /**
26
- * Widget color preset with gradient, icon, glow, and text colors
27
- */
28
- export interface WidgetColorPreset {
29
- /** Gradient string (Tailwind classes) */
30
- gradient: string;
31
- /** Simple background color for pills/badges (Tailwind class) */
32
- bg: string;
33
- /** Icon background with dark: classes */
34
- icon: string;
35
- /** Glow/shadow with dark: classes */
36
- glow: string | undefined;
37
- /** Text colors */
38
- text: {
39
- primary: string;
40
- muted: string;
41
- };
42
- }
43
- /**
44
- * Map gradient presets to full color presets
45
- * Each preset includes gradient, icon, glow, and text colors
46
- */
47
- export declare const gradientColorPresets: Record<GradientPreset, WidgetColorPreset>;
48
- /**
49
- * Shared color palette for entity states
50
- * Uses gradient presets for consistency
51
- */
52
- export declare const stateColors: {
53
- readonly unavailable: WidgetColorPreset;
54
- readonly active: WidgetColorPreset;
55
- readonly inactive: WidgetColorPreset;
56
- readonly success: WidgetColorPreset;
57
- readonly warning: WidgetColorPreset;
58
- readonly error: WidgetColorPreset;
59
- };