@glasshome/widget-sdk 1.16.0 → 1.17.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/data.d.ts +1 -1
- package/dist/framework/components/WidgetContent.d.ts +7 -1
- package/dist/framework/components/anatomy.d.ts +78 -0
- package/dist/framework/config/index.d.ts +18 -9
- package/dist/framework/core/Widget.d.ts +14 -1
- package/dist/framework/dialogs/WidgetDialog.d.ts +16 -1
- package/dist/framework/dialogs/index.d.ts +1 -1
- package/dist/framework/gestures/use-widget-gestures.d.ts +12 -1
- package/dist/framework/hooks/index.d.ts +1 -0
- package/dist/framework/hooks/use-confirm.d.ts +13 -0
- package/dist/framework/hooks/use-daylight.d.ts +25 -0
- package/dist/framework/hooks/use-widget-context.d.ts +4 -0
- package/dist/framework/hooks/use-widget-dialog.d.ts +5 -3
- package/dist/framework/hooks/widget-registry.d.ts +19 -0
- package/dist/framework/image-src.d.ts +3 -0
- package/dist/framework/index.d.ts +9 -9
- package/dist/framework/panel/panel-entity.d.ts +18 -0
- package/dist/framework/panel/panel.d.ts +55 -0
- package/dist/host/index.js +42 -24
- package/dist/index.js +1744 -836
- package/dist/ui.d.ts +1 -1
- package/dist/vite/index.d.ts +26 -0
- package/dist/vite/index.js +186 -152
- package/package.json +5 -5
package/dist/data.d.ts
CHANGED
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
* store. Phase 4 routes these through capability checks.
|
|
7
7
|
*/
|
|
8
8
|
export { getForecasts, getStream, getWebRtcClientConfig, hassMediaUrl, sendWebRtcCandidate, startWebRtcSession, state, trackEntityHistory, untrackEntityHistory, } from "@glasshome/sync-layer";
|
|
9
|
-
export type { AreaView, CalendarEvent, CalendarEventsData, CalendarWindowOptions, } from "@glasshome/sync-layer";
|
|
9
|
+
export type { AreaView, CalendarEvent, CalendarEventsData, CalendarWindowOptions, ForecastType, WeatherForecast, } from "@glasshome/sync-layer";
|
|
10
10
|
export { byDomain, useArea, useCalendarEvents, useCamera, useConnection, useCurrency, useEntities, useEntity, useEntityHistory, useEntityStatistics, useForecast, useHassConfig, useLocale, useStore, useTemperatureUnit, useUnitSystem, } from "@glasshome/sync-layer/solid";
|
|
11
11
|
export { useService, useToggle, useTurnOff, useTurnOn } from "./framework/hooks/use-service";
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type JSX } from "solid-js";
|
|
2
2
|
interface WidgetContentProps {
|
|
3
|
+
/** Colour for this content and the widget's sheet, over the shell's `tone`/`color`. */
|
|
4
|
+
accent?: string;
|
|
3
5
|
class?: string;
|
|
4
6
|
children: JSX.Element;
|
|
5
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* The widget's layout. With anatomy parts inside (`Widget.Head`, `Widget.Hero`, `Widget.Controls`,
|
|
10
|
+
* `Widget.Backdrop`, `Widget.Layer`, `Widget.Glyph`) it lays them out as a tile; with none it is the original column.
|
|
11
|
+
*/
|
|
6
12
|
export declare function WidgetContent(props: WidgetContentProps): JSX.Element;
|
|
7
13
|
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type JSX } from "solid-js";
|
|
2
|
+
import { type Confirm } from "../hooks/use-confirm";
|
|
3
|
+
/** True for a moment after `<Widget confirmed>`: the head icon and glyph read as a check. */
|
|
4
|
+
export declare const WidgetConfirmedCtx: import("solid-js").Context<() => boolean>;
|
|
5
|
+
export declare function WidgetHead(props: {
|
|
6
|
+
/** Iconify name; also the icon the widget's sheet wears. */
|
|
7
|
+
icon?: string;
|
|
8
|
+
/** Small line above the name: a state, a count, a reading. Hidden when it repeats the name. */
|
|
9
|
+
eyebrow?: JSX.Element;
|
|
10
|
+
name: JSX.Element;
|
|
11
|
+
/** Chips at the head's end, on tiles tall enough. */
|
|
12
|
+
aside?: JSX.Element;
|
|
13
|
+
/** Draws the icon in the widget's colour instead of muted. */
|
|
14
|
+
active?: boolean;
|
|
15
|
+
/** Entities behind the tile; 2 and 3 stack the icon. */
|
|
16
|
+
count?: number;
|
|
17
|
+
}): JSX.Element;
|
|
18
|
+
export declare function WidgetHero(props: {
|
|
19
|
+
value: JSX.Element;
|
|
20
|
+
unit?: string;
|
|
21
|
+
/** Small line above the value. */
|
|
22
|
+
sub?: JSX.Element;
|
|
23
|
+
/** The tile's object art, bottom right, behind the words. */
|
|
24
|
+
art?: JSX.Element;
|
|
25
|
+
class?: string;
|
|
26
|
+
}): JSX.Element;
|
|
27
|
+
/** The tile's control row: beside the value on a wide tile, under it on a narrow one, hidden on a short one. */
|
|
28
|
+
export declare function WidgetControls(props: {
|
|
29
|
+
children: JSX.Element;
|
|
30
|
+
}): JSX.Element;
|
|
31
|
+
export declare function WidgetStepper(props: {
|
|
32
|
+
label: string;
|
|
33
|
+
onStep: (direction: -1 | 1) => void;
|
|
34
|
+
}): JSX.Element;
|
|
35
|
+
export declare function WidgetChoice(props: {
|
|
36
|
+
label: string;
|
|
37
|
+
tone?: string;
|
|
38
|
+
value: string;
|
|
39
|
+
options: {
|
|
40
|
+
value: string;
|
|
41
|
+
icon: string;
|
|
42
|
+
label: string;
|
|
43
|
+
}[];
|
|
44
|
+
onChange: (value: string) => void;
|
|
45
|
+
}): JSX.Element;
|
|
46
|
+
/**
|
|
47
|
+
* A control for an action that leaves no state to show (run a scene, press a button, stop a blind):
|
|
48
|
+
* it ticks after the call succeeds. Pass `confirm` to share one with the tile (`<Widget confirmed>`).
|
|
49
|
+
*/
|
|
50
|
+
export declare function WidgetAction(props: {
|
|
51
|
+
icon: string;
|
|
52
|
+
/** Visible label; without one the action is a square icon control named by `aria-label`. */
|
|
53
|
+
children?: JSX.Element;
|
|
54
|
+
"aria-label"?: string;
|
|
55
|
+
run: () => Promise<unknown> | unknown;
|
|
56
|
+
confirm?: Confirm;
|
|
57
|
+
/** Key within a shared `confirm`; defaults to the label or icon. */
|
|
58
|
+
id?: string;
|
|
59
|
+
class?: string;
|
|
60
|
+
}): JSX.Element;
|
|
61
|
+
export declare function WidgetChip(props: {
|
|
62
|
+
icon?: string;
|
|
63
|
+
tone?: string;
|
|
64
|
+
children: JSX.Element;
|
|
65
|
+
}): JSX.Element;
|
|
66
|
+
/** A layer over the whole tile, edge to edge and behind the words: a picture, a scene, a chart band. */
|
|
67
|
+
export declare function WidgetLayer(props: {
|
|
68
|
+
class?: string;
|
|
69
|
+
children: JSX.Element;
|
|
70
|
+
}): JSX.Element;
|
|
71
|
+
/** A picture behind the whole tile, under a scrim that keeps the words readable. */
|
|
72
|
+
export declare function WidgetBackdrop(props: {
|
|
73
|
+
children: JSX.Element;
|
|
74
|
+
}): JSX.Element;
|
|
75
|
+
/** The icon large and faint in the corner: all a compact tile shows, and a big tile without art. */
|
|
76
|
+
export declare function WidgetGlyph(props: {
|
|
77
|
+
icon: string;
|
|
78
|
+
}): JSX.Element;
|
|
@@ -46,6 +46,8 @@ type ChoiceOpts<T extends string> = {
|
|
|
46
46
|
default?: T;
|
|
47
47
|
/** Display names for the options; the raw value shows without them. */
|
|
48
48
|
labels?: Partial<Record<T, string>>;
|
|
49
|
+
/** Icon per option (e.g. "mdi:floor-lamp"); set, the host shows the options as icon cards. */
|
|
50
|
+
icons?: Partial<Record<T, string>>;
|
|
49
51
|
};
|
|
50
52
|
type EntitiesOpts = {
|
|
51
53
|
title?: string;
|
|
@@ -97,19 +99,26 @@ declare function icon(o?: {
|
|
|
97
99
|
title?: string;
|
|
98
100
|
description?: string;
|
|
99
101
|
}): z.ZodOptional<z.ZodString>;
|
|
100
|
-
/**
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
/** A built-in picture: `thumb` travels in the manifest for the picker, `src` stays in the bundle. */
|
|
103
|
+
export interface ImagePresetSource {
|
|
104
|
+
label: string;
|
|
105
|
+
src: string;
|
|
106
|
+
thumb: string;
|
|
107
|
+
}
|
|
108
|
+
type ImageOpts = {
|
|
105
109
|
title?: string;
|
|
106
110
|
description?: string;
|
|
111
|
+
/** Built-in pictures the picker offers before the household's uploads. */
|
|
112
|
+
presets?: Record<string, ImagePresetSource>;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Image id (an opaque handle, not a URL), or a picked preset. The host renders
|
|
116
|
+
* its picker; the widget resolves the value with `imageSrc()`.
|
|
117
|
+
*/
|
|
118
|
+
declare function image(o: ImageOpts & {
|
|
107
119
|
default: string;
|
|
108
120
|
}): z.ZodDefault<z.ZodString>;
|
|
109
|
-
declare function image(o?:
|
|
110
|
-
title?: string;
|
|
111
|
-
description?: string;
|
|
112
|
-
}): z.ZodOptional<z.ZodString>;
|
|
121
|
+
declare function image(o?: ImageOpts): z.ZodOptional<z.ZodString>;
|
|
113
122
|
declare function stringList(o: {
|
|
114
123
|
title: string;
|
|
115
124
|
description?: string;
|
|
@@ -15,7 +15,8 @@ import type { WidgetIcon as WidgetIconType } from "../components/WidgetIcon";
|
|
|
15
15
|
import type { WidgetStatus as WidgetStatusType } from "../components/WidgetStatus";
|
|
16
16
|
import type { WidgetTitle as WidgetTitleType } from "../components/WidgetTitle";
|
|
17
17
|
import type { WidgetValue as WidgetValueType } from "../components/WidgetValue";
|
|
18
|
-
import type
|
|
18
|
+
import { type GestureHandlers } from "../gestures/use-widget-gestures";
|
|
19
|
+
import * as Anatomy from "../components/anatomy";
|
|
19
20
|
import type { Tone } from "../theming/tone";
|
|
20
21
|
import type { WidgetVariantConfig } from "../types";
|
|
21
22
|
interface WidgetEmptyStateConfig {
|
|
@@ -40,6 +41,8 @@ interface WidgetProps {
|
|
|
40
41
|
emptyState?: WidgetEmptyStateConfig;
|
|
41
42
|
/** Gesture handlers from `useWidgetGestures`. */
|
|
42
43
|
gestures?: GestureHandlers;
|
|
44
|
+
/** An action that leaves no state just ran: the head icon and glyph turn into a check for a moment. */
|
|
45
|
+
confirmed?: boolean;
|
|
43
46
|
children?: JSX.Element;
|
|
44
47
|
}
|
|
45
48
|
interface WidgetComponent {
|
|
@@ -50,6 +53,16 @@ interface WidgetComponent {
|
|
|
50
53
|
Status: typeof WidgetStatusType;
|
|
51
54
|
Value: typeof WidgetValueType;
|
|
52
55
|
SliderFill: typeof WidgetSliderFillType;
|
|
56
|
+
Head: typeof Anatomy.WidgetHead;
|
|
57
|
+
Hero: typeof Anatomy.WidgetHero;
|
|
58
|
+
Controls: typeof Anatomy.WidgetControls;
|
|
59
|
+
Stepper: typeof Anatomy.WidgetStepper;
|
|
60
|
+
Choice: typeof Anatomy.WidgetChoice;
|
|
61
|
+
Action: typeof Anatomy.WidgetAction;
|
|
62
|
+
Chip: typeof Anatomy.WidgetChip;
|
|
63
|
+
Backdrop: typeof Anatomy.WidgetBackdrop;
|
|
64
|
+
Layer: typeof Anatomy.WidgetLayer;
|
|
65
|
+
Glyph: typeof Anatomy.WidgetGlyph;
|
|
53
66
|
}
|
|
54
67
|
export declare const Widget: WidgetComponent;
|
|
55
68
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ResponsiveDialogBody, ResponsiveDialogFooter, Tabs, TabsContent, TabsList, TabsTrigger } from "@glasshome/ui/solid";
|
|
2
1
|
import type { ModalSize, Button as UIButton, ResponsiveDialog as UIResponsiveDialog, ResponsiveDialogContent as UIResponsiveDialogContent, ResponsiveDialogDescription as UIResponsiveDialogDescription, ResponsiveDialogHeader as UIResponsiveDialogHeader, ResponsiveDialogTitle as UIResponsiveDialogTitle, SchemaForm as UISchemaForm } from "@glasshome/ui/solid";
|
|
2
|
+
import { ResponsiveDialogBody, ResponsiveDialogFooter, Tabs, TabsContent, TabsList, TabsTrigger } from "@glasshome/ui/solid";
|
|
3
3
|
import { type JSX } from "solid-js";
|
|
4
4
|
import type { ZodType } from "zod";
|
|
5
5
|
/** Widths a widget could name before ui's modal size scale existed. */
|
|
@@ -10,6 +10,14 @@ export interface WidgetDialogTab {
|
|
|
10
10
|
icon: JSX.Element;
|
|
11
11
|
content: JSX.Element;
|
|
12
12
|
}
|
|
13
|
+
export interface SheetTile {
|
|
14
|
+
/** Iconify name, the tile's own icon. */
|
|
15
|
+
icon?: string;
|
|
16
|
+
/** The tile's colour: a CSS colour or `var(--tone-*)`. */
|
|
17
|
+
tone?: string;
|
|
18
|
+
/** URL of the tile's picture. */
|
|
19
|
+
backdrop?: string;
|
|
20
|
+
}
|
|
13
21
|
export interface WidgetDialogProps {
|
|
14
22
|
open: boolean;
|
|
15
23
|
onOpenChange: (open: boolean) => void;
|
|
@@ -21,6 +29,13 @@ export interface WidgetDialogProps {
|
|
|
21
29
|
onDelete?: () => void;
|
|
22
30
|
editContent?: JSX.Element;
|
|
23
31
|
controlsContent?: JSX.Element;
|
|
32
|
+
/** What holding the tile opens: only what the tile cannot show (a group's members, colours, modes),
|
|
33
|
+
as `PanelSection`s. It opens beside the tile, or from the bottom on a phone. A widget with nothing
|
|
34
|
+
the tile lacks passes none, and holding it opens nothing. */
|
|
35
|
+
sheet?: () => JSX.Element;
|
|
36
|
+
/** The tile's look, worn by its sheet so the tile reads as growing open: its icon in the head,
|
|
37
|
+
its tone in the glass, its picture (a room, an album cover) as a band behind the head. */
|
|
38
|
+
tile?: SheetTile;
|
|
24
39
|
debugContent?: JSX.Element;
|
|
25
40
|
debugData?: string | Record<string, unknown>;
|
|
26
41
|
tabs?: WidgetDialogTab[];
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* Dialog Components - Barrel Export
|
|
3
3
|
*/
|
|
4
4
|
export { buildDebugData, WidgetDebugTab, WidgetDebugView, type WidgetDebugData, type WidgetDebugEntity, } from "./debug-view";
|
|
5
|
-
export { WidgetDialog, type WidgetDialogProps, type WidgetDialogTab } from "./WidgetDialog";
|
|
5
|
+
export { type SheetTile, WidgetDialog, type WidgetDialogProps, type WidgetDialogTab, } from "./WidgetDialog";
|
|
@@ -24,6 +24,17 @@ export interface GestureHandlers {
|
|
|
24
24
|
touchAction: () => string;
|
|
25
25
|
/** Cancel any pending hold timer. Call on component unmount via onCleanup. */
|
|
26
26
|
dispose: () => void;
|
|
27
|
+
/** Where a hold is filling from, relative to the element; `fired` once it opened. */
|
|
28
|
+
hold?: () => HoldFlood | null;
|
|
29
|
+
/** Keyboard door: Enter or Space taps, the context-menu key or Shift+F10 holds. */
|
|
30
|
+
onKeyDown?: (e: KeyboardEvent) => void;
|
|
27
31
|
}
|
|
28
|
-
export
|
|
32
|
+
export interface HoldFlood {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
/** Radius that reaches the farthest corner, so the fill ends as the hold fires. */
|
|
36
|
+
r: number;
|
|
37
|
+
fired: boolean;
|
|
38
|
+
}
|
|
39
|
+
export declare function useWidgetGestures(wired: () => GestureConfig, orientation?: () => GestureOrientation): GestureHandlers;
|
|
29
40
|
export {};
|
|
@@ -8,6 +8,7 @@ export { useWidgetDashboard } from "./use-widget-dashboard";
|
|
|
8
8
|
export { useWidgetViewer } from "./use-widget-viewer";
|
|
9
9
|
export { useWidgetDimensions, type WidgetDimensionsAccessor, WidgetSizeCtx, } from "./use-widget-dimensions";
|
|
10
10
|
export { useIntersectionPause } from "./use-intersection-pause";
|
|
11
|
+
export { type Daylight, type DaylightPhase, useDaylight } from "./use-daylight";
|
|
11
12
|
export { useReducedMotion } from "./use-reduced-motion";
|
|
12
13
|
export { useWidgetDialog, type WidgetDialogReturn } from "./use-widget-dialog";
|
|
13
14
|
export { type AggregationPreset, type UseWidgetEntityGroupOptions, type UseWidgetEntityGroupResult, useWidgetEntityGroup, } from "./use-widget-entity-group";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface Confirm {
|
|
2
|
+
/** Whether this key ran a moment ago. */
|
|
3
|
+
has: (key: string) => boolean;
|
|
4
|
+
/** Whether anything ran a moment ago. */
|
|
5
|
+
any: () => boolean;
|
|
6
|
+
/** Runs the action; resolves whether it succeeded. */
|
|
7
|
+
run: (keys: string[], action: () => Promise<unknown> | unknown) => Promise<boolean>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* For actions that leave no state to show (a scene, a button press, a stop): the keys that just ran,
|
|
11
|
+
* for a moment. Confirms only after the call succeeds; a failed call is toasted by the host instead.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useConfirm(): Confirm;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Accessor } from "solid-js";
|
|
2
|
+
export type DaylightPhase = "day" | "dusk" | "night" | "dawn";
|
|
3
|
+
export interface Daylight {
|
|
4
|
+
phase: DaylightPhase;
|
|
5
|
+
isNight: boolean;
|
|
6
|
+
/** Sun elevation in degrees; undefined when the phase comes from the clock. */
|
|
7
|
+
elevation?: number;
|
|
8
|
+
/** 0..1 through the current day (sunrise to sunset) while the sun is up, else through the night; undefined without `sun.sun`'s rising and setting times. */
|
|
9
|
+
progress?: number;
|
|
10
|
+
}
|
|
11
|
+
interface SunReading {
|
|
12
|
+
state: string;
|
|
13
|
+
elevation?: number;
|
|
14
|
+
rising?: boolean;
|
|
15
|
+
next_rising?: string;
|
|
16
|
+
next_setting?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function daylightFrom(sun: SunReading | undefined, now: Date): Daylight;
|
|
19
|
+
/**
|
|
20
|
+
* Household daylight: from Home Assistant's `sun.sun` when present, else the
|
|
21
|
+
* local clock when the home has no sun entity. Reads `sun.sun`, so the widget
|
|
22
|
+
* declares `{ domain: "sun", access: "read" }`; the build refuses it otherwise.
|
|
23
|
+
*/
|
|
24
|
+
export declare function useDaylight(): Accessor<Daylight>;
|
|
25
|
+
export {};
|
|
@@ -46,6 +46,10 @@ export interface ReactiveWidgetContext {
|
|
|
46
46
|
dashboard?: () => WidgetDashboard;
|
|
47
47
|
/** Who is looking. Absent on hosts that predate this field. */
|
|
48
48
|
viewer?: () => WidgetViewer;
|
|
49
|
+
/** True when the household turned on Developer Mode; widget dialogs show Debug only then. */
|
|
50
|
+
developer?: () => boolean;
|
|
51
|
+
/** The tile's box on the page, so a held tile's sheet opens beside it. Absent: it opens centred. */
|
|
52
|
+
anchor?: () => HTMLElement | undefined;
|
|
49
53
|
}
|
|
50
54
|
export declare const WidgetCtx: import("solid-js").Context<ReactiveWidgetContext | undefined>;
|
|
51
55
|
export declare function useWidgetContext(): ReactiveWidgetContext;
|
|
@@ -9,19 +9,21 @@
|
|
|
9
9
|
* @example
|
|
10
10
|
* ```tsx
|
|
11
11
|
* function MyWidget() {
|
|
12
|
-
* const {
|
|
12
|
+
* const { dialogProps } = useWidgetDialog();
|
|
13
13
|
*
|
|
14
14
|
* return (
|
|
15
15
|
* <>
|
|
16
|
-
* <Widget
|
|
16
|
+
* <Widget>
|
|
17
17
|
* {/* widget content *\/}
|
|
18
18
|
* </Widget>
|
|
19
|
-
* <WidgetDialog {...dialogProps} />
|
|
19
|
+
* <WidgetDialog {...dialogProps} sheet={() => <MySheet />} />
|
|
20
20
|
* </>
|
|
21
21
|
* );
|
|
22
22
|
* }
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
|
+
/** Each widget's dialog opener, keyed by its host context, so `Widget` can open settings from an empty tile. */
|
|
26
|
+
export declare const dialogOpeners: WeakMap<object, (tab?: string) => void>;
|
|
25
27
|
export interface WidgetDialogReturn {
|
|
26
28
|
/** Current dialog open state accessor */
|
|
27
29
|
showDialog: () => boolean;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Accessor, type Setter } from "solid-js";
|
|
2
|
+
/** What a widget's parts tell each other: whether its dialog has a sheet, and the look the sheet wears. */
|
|
3
|
+
export interface WidgetRegistry {
|
|
4
|
+
hasSheet: Accessor<boolean>;
|
|
5
|
+
setHasSheet: Setter<boolean>;
|
|
6
|
+
/** The shell's colour (`tone` / `color` on `<Widget>`). */
|
|
7
|
+
tone: Accessor<string | undefined>;
|
|
8
|
+
setTone: Setter<string | undefined>;
|
|
9
|
+
/** A `Widget.Content` accent, which wins over the shell's colour. */
|
|
10
|
+
accent: Accessor<string | undefined>;
|
|
11
|
+
setAccent: Setter<string | undefined>;
|
|
12
|
+
/** The head's icon. */
|
|
13
|
+
icon: Accessor<string | undefined>;
|
|
14
|
+
setIcon: Setter<string | undefined>;
|
|
15
|
+
}
|
|
16
|
+
/** `<Widget>` hands its parts a copy of the host context; this points the copy back at the original. */
|
|
17
|
+
export declare const REGISTRY_KEY: unique symbol;
|
|
18
|
+
/** The registry for a widget, keyed by its host context; created on first use. */
|
|
19
|
+
export declare function widgetRegistry(ctx: object | undefined): WidgetRegistry | undefined;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ImagePresetSource } from "./config";
|
|
2
|
+
/** The URL a `field.image` value shows: the picked preset's picture, or the uploaded image. */
|
|
3
|
+
export declare function imageSrc(value: string | null | undefined, presets?: Record<string, ImagePresetSource>): string | undefined;
|
|
@@ -9,15 +9,10 @@
|
|
|
9
9
|
* import {
|
|
10
10
|
* Widget,
|
|
11
11
|
* useWidgetGestures,
|
|
12
|
-
* useWidgetDialog,
|
|
13
12
|
* } from "@glasshome/widget-sdk";
|
|
14
13
|
*
|
|
15
14
|
* export function MyWidget(props) {
|
|
16
|
-
* const {
|
|
17
|
-
* const gestures = useWidgetGestures(
|
|
18
|
-
* () => ({ tap: handleTap, hold: { action: openDialog } }),
|
|
19
|
-
* () => ctx.orientation(),
|
|
20
|
-
* );
|
|
15
|
+
* const gestures = useWidgetGestures(() => ({ tap: handleTap }));
|
|
21
16
|
*
|
|
22
17
|
* return (
|
|
23
18
|
* <Widget>
|
|
@@ -35,12 +30,17 @@ export { WidgetIcon } from "./components/WidgetIcon";
|
|
|
35
30
|
export { WidgetStatus } from "./components/WidgetStatus";
|
|
36
31
|
export { WidgetTitle } from "./components/WidgetTitle";
|
|
37
32
|
export { WidgetValue } from "./components/WidgetValue";
|
|
33
|
+
export { WidgetAction, WidgetBackdrop, WidgetChip, WidgetChoice, WidgetControls, WidgetGlyph, WidgetHead, WidgetHero, WidgetLayer, WidgetStepper, } from "./components/anatomy";
|
|
34
|
+
export { type Confirm, useConfirm } from "./hooks/use-confirm";
|
|
38
35
|
export { WidgetSliderFill } from "./backgrounds/WidgetSliderFill";
|
|
39
|
-
export {
|
|
40
|
-
export {
|
|
36
|
+
export { type PanelFact, PanelFacts, PanelRow, type PanelRowProps, PanelRows, PanelSection, type PanelSlide, } from "./panel/panel";
|
|
37
|
+
export { isPanelControllable, PanelEntityRow } from "./panel/panel-entity";
|
|
38
|
+
export { buildDebugData, WidgetDebugTab, type WidgetDebugData, type WidgetDebugEntity, WidgetDebugView, WidgetDialog, type SheetTile, type WidgetDialogProps, type WidgetDialogTab, } from "./dialogs";
|
|
39
|
+
export { type AggregationPreset, type ReactiveWidgetContext, type ServiceCallFn, type UseWidgetEntityGroupOptions, type UseWidgetEntityGroupResult, type Daylight, type DaylightPhase, useDaylight, useIntersectionPause, useReducedMotion, useWidgetContext, useWidgetDashboard, useWidgetViewer, useWidgetDialog, useWidgetDimensions, useWidgetEntityGroup, WidgetCtx, type WidgetDashboard, type WidgetViewer, type WidgetDialogReturn, type WidgetDimensions, type WidgetDimensionsAccessor, WidgetSizeCtx, } from "./hooks";
|
|
41
40
|
export { type GestureHandlers, useWidgetGestures } from "./gestures/use-widget-gestures";
|
|
42
41
|
export { injectTokens, type SvgColorKey, svgColors, type Tone, ToneSchema, } from "./theming";
|
|
43
42
|
export { widgetFields } from "./fields";
|
|
44
|
-
export { type ConfigShape, defineConfig, field, type Field, type Infer, } from "./config";
|
|
43
|
+
export { type ConfigShape, defineConfig, field, type Field, type ImagePresetSource, type Infer, } from "./config";
|
|
44
|
+
export { imageSrc } from "./image-src";
|
|
45
45
|
export { calculateLightGroup, calculateSensorGroup, type CopyState, copyText, countActiveEntities, getEntityAttribute, isEntityActive, type LightGroupResult, type SensorGroupResult, type SensorGroupType, useCopyText, } from "./utils";
|
|
46
46
|
export type { EntityView, WidgetStyles, WidgetVariantConfig, } from "./types";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type JSX } from "solid-js";
|
|
2
|
+
/** Whether a domain has a row with something to press (sensors read as facts instead). */
|
|
3
|
+
export declare function isPanelControllable(domain: string): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* A row for any entity, drawn and wired from its domain: a light dims, a cover
|
|
6
|
+
* opens, a lock locks. The same row the area panel and every group panel use.
|
|
7
|
+
*/
|
|
8
|
+
export declare function PanelEntityRow(props: {
|
|
9
|
+
entityId: string;
|
|
10
|
+
/** Overrides the entity's own name ("Ceiling" instead of "Living room ceiling"). */
|
|
11
|
+
name?: string;
|
|
12
|
+
/** A place the panel already names; dropped from the front of the entity's name. */
|
|
13
|
+
within?: string;
|
|
14
|
+
/** Overrides the domain's icon and tone, so a row matches the widget it sits in. */
|
|
15
|
+
icon?: string;
|
|
16
|
+
tone?: string;
|
|
17
|
+
onHold?: () => void;
|
|
18
|
+
}): JSX.Element;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type JSX } from "solid-js";
|
|
2
|
+
/** A continuous value the whole stage (or a row) sets by dragging. */
|
|
3
|
+
export interface PanelSlide {
|
|
4
|
+
value: number;
|
|
5
|
+
min?: number;
|
|
6
|
+
max?: number;
|
|
7
|
+
onChange: (value: number) => void;
|
|
8
|
+
/** Fires once when the drag ends, with the last value. */
|
|
9
|
+
onCommit?: (value: number) => void;
|
|
10
|
+
/** Names the value for screen readers and the keyboard handle ("Brightness"). */
|
|
11
|
+
label?: string;
|
|
12
|
+
/** Keyboard step; the drag reports whole numbers. */
|
|
13
|
+
step?: number;
|
|
14
|
+
}
|
|
15
|
+
/** A labelled group in the panel's aside ("Lights", "Playing on"). */
|
|
16
|
+
export declare function PanelSection(props: {
|
|
17
|
+
label: string;
|
|
18
|
+
children: JSX.Element;
|
|
19
|
+
}): JSX.Element;
|
|
20
|
+
/** Rows side by side, as many as fit (three lamps, two blinds). */
|
|
21
|
+
export declare function PanelRows(props: {
|
|
22
|
+
children: JSX.Element;
|
|
23
|
+
}): JSX.Element;
|
|
24
|
+
export interface PanelRowProps {
|
|
25
|
+
icon: string;
|
|
26
|
+
name: string;
|
|
27
|
+
/** The small line under the name ("70%", "Heating to 22°"). */
|
|
28
|
+
state?: JSX.Element;
|
|
29
|
+
/** The device's tone; tints its icon and fill while it is on. */
|
|
30
|
+
tone?: string;
|
|
31
|
+
on: boolean;
|
|
32
|
+
/** 0-100 fill; dragging across the row sets it. */
|
|
33
|
+
slide?: PanelSlide;
|
|
34
|
+
/** A 0-100 fill for a row that only reads (a battery level, a share of power). */
|
|
35
|
+
fill?: number;
|
|
36
|
+
onTap?: () => void;
|
|
37
|
+
onHold?: () => void;
|
|
38
|
+
/** A control at the row's end (Unlock, + Add). */
|
|
39
|
+
trailing?: JSX.Element;
|
|
40
|
+
"aria-label"?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* One device: a small tile made of button glass. Tap switches it, drag sets its level.
|
|
44
|
+
* A row with nothing to press (no tap, slide or hold) wears the same glass but is not a button.
|
|
45
|
+
*/
|
|
46
|
+
export declare function PanelRow(props: PanelRowProps): JSX.Element;
|
|
47
|
+
export interface PanelFact {
|
|
48
|
+
icon: string;
|
|
49
|
+
label: string;
|
|
50
|
+
value: JSX.Element;
|
|
51
|
+
}
|
|
52
|
+
/** Readings in one strip (window, CO₂, motion): read, never pressed. */
|
|
53
|
+
export declare function PanelFacts(props: {
|
|
54
|
+
items: PanelFact[];
|
|
55
|
+
}): JSX.Element;
|
package/dist/host/index.js
CHANGED
|
@@ -1,51 +1,69 @@
|
|
|
1
1
|
import { ErrorBoundary as e, createComponent as t } from "solid-js";
|
|
2
|
-
import {
|
|
3
|
-
import { WidgetCtx as
|
|
2
|
+
import { DelegatedEvents as n, clearDelegatedEvents as r, delegateEvents as i, render as a } from "solid-js/web";
|
|
3
|
+
import { WidgetCtx as o, injectTokens as s } from "@glasshome/widget-sdk";
|
|
4
4
|
//#region src/host/instantiate-widget.ts
|
|
5
|
-
var
|
|
6
|
-
function
|
|
7
|
-
let t =
|
|
5
|
+
var c = /* @__PURE__ */ new Map();
|
|
6
|
+
function l(e) {
|
|
7
|
+
let t = c.get(e);
|
|
8
8
|
if (t) return t;
|
|
9
9
|
let n = new CSSStyleSheet();
|
|
10
|
-
return n.replaceSync(e),
|
|
10
|
+
return n.replaceSync(e), c.set(e, n), n;
|
|
11
11
|
}
|
|
12
|
-
var
|
|
13
|
-
function
|
|
12
|
+
var u = /* @__PURE__ */ new Set(), d = /* @__PURE__ */ new Map(), f = !1;
|
|
13
|
+
function p(e, t) {
|
|
14
14
|
for (let n of t) e.classList.toggle(n, document.documentElement.classList.contains(n));
|
|
15
15
|
}
|
|
16
|
-
function
|
|
17
|
-
for (let e of t)
|
|
18
|
-
return
|
|
19
|
-
for (let [e, t] of
|
|
16
|
+
function m(e, t) {
|
|
17
|
+
for (let e of t) u.add(e);
|
|
18
|
+
return d.set(e, t), p(e, t), f || (f = !0, new MutationObserver(() => {
|
|
19
|
+
for (let [e, t] of d) p(e, t);
|
|
20
20
|
}).observe(document.documentElement, {
|
|
21
21
|
attributes: !0,
|
|
22
22
|
attributeFilter: ["class"]
|
|
23
23
|
})), () => {
|
|
24
|
-
|
|
24
|
+
d.delete(e);
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
var h = (e) => {
|
|
28
|
+
Reflect.deleteProperty(e, "target"), Reflect.deleteProperty(e, "currentTarget");
|
|
29
|
+
};
|
|
30
|
+
if (typeof document < "u") {
|
|
31
|
+
let e = [...n];
|
|
32
|
+
i(e);
|
|
33
|
+
for (let t of e) document.addEventListener(t, h);
|
|
34
|
+
}
|
|
35
|
+
function g(e) {
|
|
36
|
+
if (e.mode !== "closed") return () => {};
|
|
37
|
+
let t = [...n], a = e;
|
|
38
|
+
i(t, a);
|
|
39
|
+
for (let n of t) e.addEventListener(n, h);
|
|
40
|
+
return () => {
|
|
41
|
+
r(a);
|
|
42
|
+
for (let n of t) e.removeEventListener(n, h);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function _(n, r) {
|
|
46
|
+
let i = n.attachShadow({ mode: "closed" }), c = g(i), u = m(n, r.mirrorClasses ?? ["dark"]);
|
|
47
|
+
s(i), r.cssText !== null && (i.adoptedStyleSheets = [...i.adoptedStyleSheets, l(r.cssText)]), r.extraSheets?.length && (i.adoptedStyleSheets = [...i.adoptedStyleSheets, ...r.extraSheets]);
|
|
48
|
+
let d = a(() => t(o.Provider, {
|
|
49
|
+
value: r.ctx,
|
|
32
50
|
get children() {
|
|
33
51
|
return t(e, {
|
|
34
52
|
fallback: (e) => {
|
|
35
53
|
let t = e instanceof Error ? e : Error(String(e));
|
|
36
|
-
return queueMicrotask(() =>
|
|
54
|
+
return queueMicrotask(() => r.onCrash(t)), null;
|
|
37
55
|
},
|
|
38
56
|
get children() {
|
|
39
|
-
return t(
|
|
40
|
-
return
|
|
57
|
+
return t(r.definition.component, { get config() {
|
|
58
|
+
return r.config();
|
|
41
59
|
} });
|
|
42
60
|
}
|
|
43
61
|
});
|
|
44
62
|
}
|
|
45
|
-
}),
|
|
63
|
+
}), i);
|
|
46
64
|
return { dispose: () => {
|
|
47
|
-
|
|
65
|
+
u(), d(), c();
|
|
48
66
|
} };
|
|
49
67
|
}
|
|
50
68
|
//#endregion
|
|
51
|
-
export {
|
|
69
|
+
export { _ as instantiateWidget };
|