@hashsome/ui 0.1.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.
Files changed (192) hide show
  1. package/LICENSE +674 -0
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/entities/action-button.d.ts +17 -0
  4. package/dist/entities/action-button.js +56 -0
  5. package/dist/entities/action-button.js.map +1 -0
  6. package/dist/entities/artwork-ring.d.ts +17 -0
  7. package/dist/entities/artwork-ring.js +89 -0
  8. package/dist/entities/artwork-ring.js.map +1 -0
  9. package/dist/entities/climate-tile.d.ts +20 -0
  10. package/dist/entities/climate-tile.js +98 -0
  11. package/dist/entities/climate-tile.js.map +1 -0
  12. package/dist/entities/light-color.d.ts +52 -0
  13. package/dist/entities/light-color.js +148 -0
  14. package/dist/entities/light-color.js.map +1 -0
  15. package/dist/entities/light-tile.d.ts +24 -0
  16. package/dist/entities/light-tile.js +139 -0
  17. package/dist/entities/light-tile.js.map +1 -0
  18. package/dist/entities/media-browser.d.ts +15 -0
  19. package/dist/entities/media-browser.js +67 -0
  20. package/dist/entities/media-browser.js.map +1 -0
  21. package/dist/entities/media-controls.d.ts +20 -0
  22. package/dist/entities/media-controls.js +53 -0
  23. package/dist/entities/media-controls.js.map +1 -0
  24. package/dist/entities/media-player-bar.d.ts +14 -0
  25. package/dist/entities/media-player-bar.js +78 -0
  26. package/dist/entities/media-player-bar.js.map +1 -0
  27. package/dist/entities/media-player-body.d.ts +16 -0
  28. package/dist/entities/media-player-body.js +18 -0
  29. package/dist/entities/media-player-body.js.map +1 -0
  30. package/dist/entities/media-player-column.d.ts +18 -0
  31. package/dist/entities/media-player-column.js +34 -0
  32. package/dist/entities/media-player-column.js.map +1 -0
  33. package/dist/entities/media-player-page.d.ts +12 -0
  34. package/dist/entities/media-player-page.js +13 -0
  35. package/dist/entities/media-player-page.js.map +1 -0
  36. package/dist/entities/media-progress.d.ts +7 -0
  37. package/dist/entities/media-progress.js +30 -0
  38. package/dist/entities/media-progress.js.map +1 -0
  39. package/dist/entities/media-seek.d.ts +9 -0
  40. package/dist/entities/media-seek.js +19 -0
  41. package/dist/entities/media-seek.js.map +1 -0
  42. package/dist/entities/nav-dock.d.ts +13 -0
  43. package/dist/entities/nav-dock.js +22 -0
  44. package/dist/entities/nav-dock.js.map +1 -0
  45. package/dist/entities/nav-rail.d.ts +19 -0
  46. package/dist/entities/nav-rail.js +18 -0
  47. package/dist/entities/nav-rail.js.map +1 -0
  48. package/dist/entities/now-playing.d.ts +20 -0
  49. package/dist/entities/now-playing.js +34 -0
  50. package/dist/entities/now-playing.js.map +1 -0
  51. package/dist/entities/scene-button.d.ts +13 -0
  52. package/dist/entities/scene-button.js +6 -0
  53. package/dist/entities/scene-button.js.map +1 -0
  54. package/dist/entities/seek-line.d.ts +9 -0
  55. package/dist/entities/seek-line.js +71 -0
  56. package/dist/entities/seek-line.js.map +1 -0
  57. package/dist/entities/sensor-readout.d.ts +28 -0
  58. package/dist/entities/sensor-readout.js +95 -0
  59. package/dist/entities/sensor-readout.js.map +1 -0
  60. package/dist/entities/top-bar.d.ts +68 -0
  61. package/dist/entities/top-bar.js +248 -0
  62. package/dist/entities/top-bar.js.map +1 -0
  63. package/dist/entity-handle.d.ts +21 -0
  64. package/dist/entity-handle.js +16 -0
  65. package/dist/entity-handle.js.map +1 -0
  66. package/dist/gallery/fixtures.d.ts +4 -0
  67. package/dist/gallery/fixtures.js +119 -0
  68. package/dist/gallery/fixtures.js.map +1 -0
  69. package/dist/gallery/gallery.d.ts +9 -0
  70. package/dist/gallery/gallery.js +355 -0
  71. package/dist/gallery/gallery.js.map +1 -0
  72. package/dist/gallery/index.d.ts +2 -0
  73. package/dist/gallery/index.js +2 -0
  74. package/dist/gallery/index.js.map +1 -0
  75. package/dist/gallery/props-data.d.ts +10 -0
  76. package/dist/gallery/props-data.js +718 -0
  77. package/dist/gallery/props-data.js.map +1 -0
  78. package/dist/hooks.d.ts +19 -0
  79. package/dist/hooks.js +53 -0
  80. package/dist/hooks.js.map +1 -0
  81. package/dist/icon-data.d.ts +6 -0
  82. package/dist/icon-data.js +59193 -0
  83. package/dist/icon-data.js.map +1 -0
  84. package/dist/icon.d.ts +9 -0
  85. package/dist/icon.js +28 -0
  86. package/dist/icon.js.map +1 -0
  87. package/dist/index.d.ts +30 -0
  88. package/dist/index.js +24 -0
  89. package/dist/index.js.map +1 -0
  90. package/dist/layout/cover.d.ts +5 -0
  91. package/dist/layout/cover.js +8 -0
  92. package/dist/layout/cover.js.map +1 -0
  93. package/dist/layout/date-time-field.d.ts +15 -0
  94. package/dist/layout/date-time-field.js +108 -0
  95. package/dist/layout/date-time-field.js.map +1 -0
  96. package/dist/layout/detail-provider.d.ts +22 -0
  97. package/dist/layout/detail-provider.js +26 -0
  98. package/dist/layout/detail-provider.js.map +1 -0
  99. package/dist/layout/drawer-controls.d.ts +46 -0
  100. package/dist/layout/drawer-controls.js +93 -0
  101. package/dist/layout/drawer-controls.js.map +1 -0
  102. package/dist/layout/energy-chart.d.ts +37 -0
  103. package/dist/layout/energy-chart.js +85 -0
  104. package/dist/layout/energy-chart.js.map +1 -0
  105. package/dist/layout/energy-usage.d.ts +6 -0
  106. package/dist/layout/energy-usage.js +18 -0
  107. package/dist/layout/energy-usage.js.map +1 -0
  108. package/dist/layout/entity-drawer.d.ts +15 -0
  109. package/dist/layout/entity-drawer.js +77 -0
  110. package/dist/layout/entity-drawer.js.map +1 -0
  111. package/dist/layout/fade-scroll.d.ts +14 -0
  112. package/dist/layout/fade-scroll.js +59 -0
  113. package/dist/layout/fade-scroll.js.map +1 -0
  114. package/dist/layout/grid.d.ts +9 -0
  115. package/dist/layout/grid.js +6 -0
  116. package/dist/layout/grid.js.map +1 -0
  117. package/dist/layout/history-section.d.ts +19 -0
  118. package/dist/layout/history-section.js +39 -0
  119. package/dist/layout/history-section.js.map +1 -0
  120. package/dist/layout/hold-progress.d.ts +2 -0
  121. package/dist/layout/hold-progress.js +9 -0
  122. package/dist/layout/hold-progress.js.map +1 -0
  123. package/dist/layout/icon-button-styles.d.ts +9 -0
  124. package/dist/layout/icon-button-styles.js +28 -0
  125. package/dist/layout/icon-button-styles.js.map +1 -0
  126. package/dist/layout/page.d.ts +17 -0
  127. package/dist/layout/page.js +29 -0
  128. package/dist/layout/page.js.map +1 -0
  129. package/dist/layout/plain-button.d.ts +11 -0
  130. package/dist/layout/plain-button.js +17 -0
  131. package/dist/layout/plain-button.js.map +1 -0
  132. package/dist/layout/room-header.d.ts +12 -0
  133. package/dist/layout/room-header.js +11 -0
  134. package/dist/layout/room-header.js.map +1 -0
  135. package/dist/layout/round-button.d.ts +13 -0
  136. package/dist/layout/round-button.js +19 -0
  137. package/dist/layout/round-button.js.map +1 -0
  138. package/dist/layout/sensor-history.d.ts +15 -0
  139. package/dist/layout/sensor-history.js +91 -0
  140. package/dist/layout/sensor-history.js.map +1 -0
  141. package/dist/layout/sensor-stats.d.ts +21 -0
  142. package/dist/layout/sensor-stats.js +79 -0
  143. package/dist/layout/sensor-stats.js.map +1 -0
  144. package/dist/layout/series-chart.d.ts +25 -0
  145. package/dist/layout/series-chart.js +46 -0
  146. package/dist/layout/series-chart.js.map +1 -0
  147. package/dist/layout/stepper.d.ts +10 -0
  148. package/dist/layout/stepper.js +12 -0
  149. package/dist/layout/stepper.js.map +1 -0
  150. package/dist/layout/swatch-row.d.ts +19 -0
  151. package/dist/layout/swatch-row.js +20 -0
  152. package/dist/layout/swatch-row.js.map +1 -0
  153. package/dist/layout/tile.d.ts +67 -0
  154. package/dist/layout/tile.js +207 -0
  155. package/dist/layout/tile.js.map +1 -0
  156. package/dist/layout/use-drawer.d.ts +33 -0
  157. package/dist/layout/use-drawer.js +34 -0
  158. package/dist/layout/use-drawer.js.map +1 -0
  159. package/dist/layout/use-hold.d.ts +21 -0
  160. package/dist/layout/use-hold.js +61 -0
  161. package/dist/layout/use-hold.js.map +1 -0
  162. package/dist/provider.d.ts +37 -0
  163. package/dist/provider.js +95 -0
  164. package/dist/provider.js.map +1 -0
  165. package/dist/status.d.ts +8 -0
  166. package/dist/status.js +27 -0
  167. package/dist/status.js.map +1 -0
  168. package/dist/theme/density.d.ts +16 -0
  169. package/dist/theme/density.js +7 -0
  170. package/dist/theme/density.js.map +1 -0
  171. package/dist/theme/global-styles.d.ts +5 -0
  172. package/dist/theme/global-styles.js +44 -0
  173. package/dist/theme/global-styles.js.map +1 -0
  174. package/dist/theme/index.d.ts +19 -0
  175. package/dist/theme/index.js +106 -0
  176. package/dist/theme/index.js.map +1 -0
  177. package/dist/theme/overrides.d.ts +28 -0
  178. package/dist/theme/overrides.js +24 -0
  179. package/dist/theme/overrides.js.map +1 -0
  180. package/dist/theme/tokens.d.ts +78 -0
  181. package/dist/theme/tokens.js +1 -0
  182. package/dist/theme/tokens.js.map +1 -0
  183. package/dist/theme/use-typography.d.ts +4 -0
  184. package/dist/theme/use-typography.js +9 -0
  185. package/dist/theme/use-typography.js.map +1 -0
  186. package/dist/use-entity-history.d.ts +12 -0
  187. package/dist/use-entity-history.js +43 -0
  188. package/dist/use-entity-history.js.map +1 -0
  189. package/dist/use-media-browser.d.ts +31 -0
  190. package/dist/use-media-browser.js +87 -0
  191. package/dist/use-media-browser.js.map +1 -0
  192. package/package.json +57 -0
@@ -0,0 +1,17 @@
1
+ import type { EntityRef } from '@hashsome/core';
2
+ import { type EntityHandle } from '../entity-handle.ts';
3
+ import type { IconName } from '../icon-data.ts';
4
+ export interface ActionButtonProps {
5
+ /** Button text. Defaults to the entity's name. */
6
+ label?: string;
7
+ /** Icon id, e.g. `lu:coffee`. */
8
+ icon?: IconName;
9
+ /** A second line of text under the label. */
10
+ secondary?: string;
11
+ /** What to trigger: an action entity (scene, script, button — it runs) or a switch (it flips), as a ref or a handle. */
12
+ entity?: EntityRef | EntityHandle<'action'> | EntityHandle<'switch'>;
13
+ /** A custom press for something no entity covers (a raw backend call, your own logic). Used instead of `entity`. */
14
+ onPress?: () => Promise<unknown>;
15
+ }
16
+ /** Any one-shot thing to trigger — a scene, script, button or switch, or your own `onPress` — with pending / done / error feedback. */
17
+ export declare function ActionButton({ label, icon, secondary, entity, onPress }: ActionButtonProps): import("react").JSX.Element;
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { fallbackName } from '../entity-handle.js';
4
+ import { useCommand, useEntity } from '../hooks.js';
5
+ import { Tile } from '../layout/tile.js';
6
+ import { entityStatus } from '../status.js';
7
+ /** Normalizes an entity ref or handle to what the button needs: status, name, and how to press it. */
8
+ function usePressable(entity) {
9
+ const ref = typeof entity === 'string' ? entity : undefined;
10
+ const live = useEntity(ref);
11
+ const send = useCommand(ref);
12
+ if (entity === undefined) {
13
+ return { status: 'missing', name: undefined, press: undefined };
14
+ }
15
+ if (typeof entity === 'string') {
16
+ const supported = live === undefined || live === null || live.kind === 'action' || live.kind === 'switch';
17
+ return {
18
+ status: supported ? entityStatus(live) : 'unsupported',
19
+ name: live?.name,
20
+ press: live ? () => send(live.kind === 'switch' ? 'toggle' : 'trigger') : undefined,
21
+ };
22
+ }
23
+ const found = entity.entity;
24
+ return {
25
+ status: entity.status,
26
+ name: found?.name,
27
+ press: found
28
+ ? () => found.kind === 'switch'
29
+ ? entity.command('toggle')
30
+ : entity.command('trigger')
31
+ : undefined,
32
+ };
33
+ }
34
+ /** Any one-shot thing to trigger — a scene, script, button or switch, or your own `onPress` — with pending / done / error feedback. */
35
+ export function ActionButton({ label, icon, secondary, entity, onPress }) {
36
+ const target = usePressable(onPress ? undefined : entity);
37
+ const [feedback, setFeedback] = useState();
38
+ const [error, setError] = useState();
39
+ const timer = useRef(undefined);
40
+ useEffect(() => () => clearTimeout(timer.current), []);
41
+ const run = onPress ?? target.press;
42
+ const press = () => {
43
+ setFeedback('pending');
44
+ setError(undefined);
45
+ Promise.resolve(run ? run() : Promise.reject(new Error('Nothing to trigger')))
46
+ .then(() => setFeedback('done'), (err) => {
47
+ setFeedback('error');
48
+ setError(err instanceof Error ? err.message : String(err));
49
+ })
50
+ .finally(() => {
51
+ clearTimeout(timer.current);
52
+ timer.current = setTimeout(() => setFeedback(undefined), 1200);
53
+ });
54
+ };
55
+ return (_jsx(Tile, { label: label ?? target.name ?? fallbackName(entity), ...(icon ? { icon } : {}), ...(secondary ? { secondary } : {}), status: onPress ? 'ready' : target.status, feedback: feedback, onPress: feedback === 'pending' ? undefined : press, ...(error ? { title: error } : {}) }));
56
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-button.js","sourceRoot":"","sources":["../../src/entities/action-button.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { SeekHold } from './media-seek.ts';
2
+ /** The player's artwork in a circle, like the one in the bar but larger: an inner outline around
3
+ * it, and an outer ring that shows how far along playback is. With `onSeek` the ring is a slider:
4
+ * drag around it, or use the arrow keys. Not exported from the package: `MediaPlayerColumn` and
5
+ * `MediaPlayerPage` draw it. */
6
+ export declare function ArtworkRing({ artworkUrl, seek, duration, seekable, onOpen, size: SIZE, }: {
7
+ artworkUrl?: string | undefined;
8
+ /** The position to draw and the way to change it, shared with whatever shows the time. */
9
+ seek: SeekHold;
10
+ /** Seconds. Without it the ring is only an outline. */
11
+ duration?: number | undefined;
12
+ seekable: boolean;
13
+ /** Makes the artwork itself a button, for opening something (the library). */
14
+ onOpen?: (() => void) | undefined;
15
+ /** The ring's diameter in px. Default 168. */
16
+ size?: number;
17
+ }): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,89 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
+ /** @jsxImportSource @emotion/react */
3
+ import { useRef } from 'react';
4
+ import { Box, Flex } from 'e-prim';
5
+ import { Icon } from '../icon.js';
6
+ import { Cover } from '../layout/cover.js';
7
+ /** The ring's diameter when none is given. */
8
+ const DEFAULT_SIZE = 168;
9
+ /** The player's artwork in a circle, like the one in the bar but larger: an inner outline around
10
+ * it, and an outer ring that shows how far along playback is. With `onSeek` the ring is a slider:
11
+ * drag around it, or use the arrow keys. Not exported from the package: `MediaPlayerColumn` and
12
+ * `MediaPlayerPage` draw it. */
13
+ export function ArtworkRing({ artworkUrl, seek, duration, seekable, onOpen, size: SIZE = DEFAULT_SIZE, }) {
14
+ const ring = useRef(null);
15
+ const dragging = useRef(false);
16
+ const total = seekable && duration !== undefined && duration > 0 ? duration : undefined;
17
+ const shown = seek.shown;
18
+ const fraction = shown !== undefined && duration ? Math.min(1, Math.max(0, shown / duration)) : undefined;
19
+ /** Where on the ring a pointer is, as a position in the item; `undefined` off the ring. */
20
+ const positionAt = (event) => {
21
+ const box = ring.current?.getBoundingClientRect();
22
+ if (!box || !duration) {
23
+ return undefined;
24
+ }
25
+ const dx = event.clientX - (box.left + box.width / 2);
26
+ const dy = event.clientY - (box.top + box.height / 2);
27
+ const turn = Math.atan2(dx, -dy) / (2 * Math.PI);
28
+ return Math.round(((turn + 1) % 1) * duration);
29
+ };
30
+ const onKeyDown = (event) => {
31
+ const step = event.key === 'ArrowRight' || event.key === 'ArrowUp' ? 5 : -5;
32
+ if (total === undefined ||
33
+ !['ArrowRight', 'ArrowUp', 'ArrowLeft', 'ArrowDown'].includes(event.key)) {
34
+ return;
35
+ }
36
+ event.preventDefault();
37
+ seek.commit(Math.min(total, Math.max(0, Math.round((shown ?? 0) + step))));
38
+ };
39
+ return (_jsxs(Box, { position: "relative", width: SIZE, height: SIZE, mx: "auto", css: { flex: 'none' }, children: [_jsx(Box, { ref: ring, position: "absolute", cursor: total !== undefined ? 'pointer' : 'default', ...(total !== undefined
40
+ ? {
41
+ role: 'slider',
42
+ tabIndex: 0,
43
+ 'aria-label': 'Position',
44
+ 'aria-valuemin': 0,
45
+ 'aria-valuemax': Math.round(total ?? 0),
46
+ 'aria-valuenow': Math.round(shown ?? 0),
47
+ onKeyDown,
48
+ onPointerDown: (event) => {
49
+ const box = event.currentTarget.getBoundingClientRect();
50
+ const distance = Math.hypot(event.clientX - (box.left + box.width / 2), event.clientY - (box.top + box.height / 2));
51
+ // Only the ring itself seeks, not the artwork inside it.
52
+ if (distance < box.width * 0.4) {
53
+ return;
54
+ }
55
+ dragging.current = true;
56
+ event.currentTarget.setPointerCapture?.(event.pointerId);
57
+ seek.preview(positionAt(event) ?? 0);
58
+ },
59
+ onPointerMove: (event) => {
60
+ if (dragging.current) {
61
+ seek.preview(positionAt(event) ?? 0);
62
+ }
63
+ },
64
+ onPointerUp: (event) => {
65
+ if (dragging.current) {
66
+ dragging.current = false;
67
+ const next = positionAt(event);
68
+ if (next !== undefined) {
69
+ seek.commit(next);
70
+ }
71
+ }
72
+ },
73
+ }
74
+ : {}), css: { inset: 0, touchAction: 'none' }, children: _jsxs("svg", { viewBox: "0 0 100 100", width: SIZE, height: SIZE, "aria-hidden": "true", children: [_jsx("circle", { cx: "50", cy: "50", r: "47", fill: "none", strokeWidth: "3", css: ({ palette }) => ({ stroke: palette.border }) }), fraction !== undefined ? (_jsx("circle", { cx: "50", cy: "50", r: "47", fill: "none", strokeWidth: "3", strokeLinecap: "round", pathLength: 100, strokeDasharray: `${fraction * 100} 100`, transform: "rotate(-90 50 50)", css: ({ palette }) => ({ stroke: palette.accent }) })) : null] }) }), _jsx(Box, { position: "absolute", radius: "full", border: true, css: { inset: '9%' } }), _jsx(Flex, { center: true, position: "absolute", radius: "full", overflow: "hidden", background: "surfaceRaised", color: "textMuted", cursor: onOpen ? 'pointer' : 'inherit', css: { inset: '14%' }, ...(onOpen
75
+ ? {
76
+ role: 'button',
77
+ tabIndex: 0,
78
+ 'aria-label': 'Open media browser',
79
+ title: 'Open media browser',
80
+ onClick: onOpen,
81
+ onKeyDown: (event) => {
82
+ if (event.key === 'Enter' || event.key === ' ') {
83
+ event.preventDefault();
84
+ onOpen();
85
+ }
86
+ },
87
+ }
88
+ : {}), children: artworkUrl ? _jsx(Cover, { src: artworkUrl }) : _jsx(Icon, { name: "lu:music", size: 40 }) })] }));
89
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artwork-ring.js","sourceRoot":"","sources":["../../src/entities/artwork-ring.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { EntityRef } from '@hashsome/core';
2
+ import type { IconName } from '../icon-data.ts';
3
+ import { type EntityHandle } from '../entity-handle.ts';
4
+ import type { EnergyChartProps } from '../layout/energy-chart.tsx';
5
+ import type { LogbookEntry } from '../layout/history-section.tsx';
6
+ export interface ClimateTileProps {
7
+ /** A thermostat or heater, as a ref like `ha:climate.living_room` or a handle (a custom source). */
8
+ entity: EntityRef | EntityHandle<'climate'>;
9
+ /** Defaults to the device's name. */
10
+ name?: string;
11
+ /** Icon id. Defaults to a thermometer. */
12
+ icon?: IconName;
13
+ /** Power-draw chart for the drawer, above `history`. No default source yet — pass explicitly. */
14
+ energy?: EnergyChartProps;
15
+ /** Recent activity, shown in the drawer. No default source yet — pass explicitly. */
16
+ history?: LogbookEntry[];
17
+ }
18
+ /** Heater / thermostat: a mode button that opens mode swatches in the card, a target temperature
19
+ * stepper, and (on hold) a drawer with modes, a target bar, presets, energy and history. */
20
+ export declare function ClimateTile({ entity, name, icon, energy, history }: ClimateTileProps): import("react").JSX.Element;
@@ -0,0 +1,98 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Flex, Typography } from 'e-prim';
3
+ import { useEffect, useRef, useState } from 'react';
4
+ import { fallbackName } from '../entity-handle.js';
5
+ import { useEntityHandle } from '../hooks.js';
6
+ import { ChipRow, StepButton } from '../layout/drawer-controls.js';
7
+ import { Stepper, StepperValue } from '../layout/stepper.js';
8
+ import { SwatchRow } from '../layout/swatch-row.js';
9
+ import { IconButton, Tile } from '../layout/tile.js';
10
+ const MODE_META = {
11
+ off: { icon: 'lu:power', color: '#6b6b73', label: 'Off' },
12
+ heat: { icon: 'lu:flame', color: '#ff7a45', label: 'Heat' },
13
+ cool: { icon: 'lu:snowflake', color: '#4dc9ff', label: 'Cool' },
14
+ auto: { icon: 'lu:refresh-cw', color: '#5fd17a', label: 'Auto' },
15
+ heatCool: { icon: 'lu:thermometer-sun', color: '#b36bff', label: 'Heat/Cool' },
16
+ dry: { icon: 'lu:droplets', color: '#fbbf24', label: 'Dry' },
17
+ fanOnly: { icon: 'lu:wind', color: '#2dd4bf', label: 'Fan' },
18
+ };
19
+ const FALLBACK_MODES = ['off', 'heat'];
20
+ function modeMeta(mode) {
21
+ return MODE_META[mode];
22
+ }
23
+ function title(text) {
24
+ return text.charAt(0).toUpperCase() + text.slice(1).replace(/_/g, ' ');
25
+ }
26
+ /** Heater / thermostat: a mode button that opens mode swatches in the card, a target temperature
27
+ * stepper, and (on hold) a drawer with modes, a target bar, presets, energy and history. */
28
+ export function ClimateTile({ entity, name, icon, energy, history }) {
29
+ const handle = useEntityHandle('climate', entity);
30
+ const [picking, setPicking] = useState(false);
31
+ const { status } = handle;
32
+ const climate = handle.entity;
33
+ const mode = climate?.mode ?? 'off';
34
+ const target = climate?.targetTemperature;
35
+ const current = climate?.currentTemperature;
36
+ const step = climate?.capabilities.step ?? 0.5;
37
+ const min = climate?.capabilities.range.min ?? 5;
38
+ const max = climate?.capabilities.range.max ?? 35;
39
+ const unit = climate?.unit ?? '°C';
40
+ const reported = climate?.capabilities.modes ?? [];
41
+ const modes = reported.length > 0 ? reported : FALLBACK_MODES;
42
+ const ready = status === 'ready';
43
+ const setTarget = (value) => void handle.command('setTargetTemperature', {
44
+ temperature: Math.min(max, Math.max(min, Math.round(value * 100) / 100)),
45
+ });
46
+ const setMode = (next) => void handle.command('setMode', { mode: next });
47
+ return (_jsx(Tile, { label: name ?? climate?.name ?? fallbackName(entity), icon: icon ?? 'lu:thermometer', kind: "Climate", status: status, secondary: current !== undefined ? `${current} ${unit}` : undefined, detail: _jsx(ClimateDetailBody, { climate: climate, mode: mode, modes: modes, target: target, current: current, step: step, min: min, max: max, unit: unit, onMode: setMode, onTarget: setTarget, onPreset: (preset) => void handle.command('setPreset', { preset }) }), ...(energy ? { energy } : {}), ...(history ? { history } : {}), ...(ready && picking
48
+ ? {
49
+ // A render prop `Tile` calls, not a component of its own.
50
+ // oxlint-disable-next-line react/no-unstable-nested-components
51
+ overlay: () => (_jsx(SwatchRow, { items: modes.map((m) => ({
52
+ key: m,
53
+ label: modeMeta(m).label,
54
+ selected: m === mode,
55
+ color: modeMeta(m).color,
56
+ icon: modeMeta(m).icon,
57
+ onPick: () => {
58
+ setMode(m);
59
+ setPicking(false);
60
+ },
61
+ })) })),
62
+ }
63
+ : {}), trailing: ready ? (_jsxs(_Fragment, { children: [_jsx(IconButton, { icon: picking ? 'lu:x' : modeMeta(mode).icon, label: picking ? 'Close modes' : 'Mode', active: !picking && mode !== 'off', onClick: () => setPicking((open) => !open), size: 16 }), target !== undefined ? (_jsxs(Stepper, { children: [_jsx(IconButton, { icon: "lu:minus", label: "Decrease", disabled: target <= min, onClick: () => setTarget(target - step) }), _jsxs(StepperValue, { children: [target, " ", unit] }), _jsx(IconButton, { icon: "lu:plus", label: "Increase", disabled: target >= max, onClick: () => setTarget(target + step) })] })) : null] })) : null }));
64
+ }
65
+ function ClimateDetailBody({ climate, mode, modes, target, current, step, min, max, unit, onMode, onTarget, onPreset, }) {
66
+ const [drag, setDrag] = useState(null);
67
+ if (drag !== null && drag === target) {
68
+ setDrag(null);
69
+ }
70
+ const shown = drag ?? target ?? min;
71
+ const latest = useRef(shown);
72
+ useEffect(() => {
73
+ latest.current = shown;
74
+ }, [shown]);
75
+ const commit = (next) => {
76
+ const clamped = Math.min(max, Math.max(min, Math.round(next * 100) / 100));
77
+ latest.current = clamped;
78
+ setDrag(clamped);
79
+ onTarget(clamped);
80
+ };
81
+ const nudge = (delta) => commit(latest.current + delta);
82
+ const action = climate?.action;
83
+ const humidity = climate?.humidity;
84
+ const presets = climate?.capabilities.presets ?? [];
85
+ const preset = climate?.preset;
86
+ const summary = [
87
+ action ? title(action) : mode === 'off' ? 'Off' : title(mode),
88
+ current !== undefined ? `${current} ${unit} now` : undefined,
89
+ humidity !== undefined ? `${humidity}% humidity` : undefined,
90
+ ]
91
+ .filter(Boolean)
92
+ .join(' · ');
93
+ return (_jsxs(Flex, { direction: "column", gap: 2, children: [_jsxs(Flex, { direction: "column", gap: 2, background: "surfaceRaised", radius: "row", py: 3.5, px: 4, children: [_jsxs(Flex, { direction: "column", children: [_jsx(Typography, { as: "span", variant: "bodyStrong", children: "Mode" }), _jsx(Typography, { as: "span", variant: "secondary", color: "textMuted", children: summary })] }), _jsx(ChipRow, { options: modes.map((m) => ({
94
+ value: m,
95
+ label: modeMeta(m).label,
96
+ icon: modeMeta(m).icon,
97
+ })), value: mode, onChange: (value) => onMode(value) })] }), target !== undefined ? (_jsxs(Flex, { justify: "space-between", align: "center", background: "surfaceRaised", radius: "row", py: 3.5, px: 4, children: [_jsxs(Flex, { direction: "column", children: [_jsx(Typography, { as: "span", variant: "bodyStrong", children: "Target" }), _jsx(Typography, { as: "span", variant: "secondary", color: "textMuted", children: "Hold a button to change faster" })] }), _jsxs(Stepper, { children: [_jsx(StepButton, { icon: "lu:minus", label: "Decrease target", delta: -step, holdDelta: -step * 4, onStep: nudge, disabled: shown <= min, size: 28 }), _jsxs(StepperValue, { children: [shown, " ", unit] }), _jsx(StepButton, { icon: "lu:plus", label: "Increase target", delta: step, holdDelta: step * 4, onStep: nudge, disabled: shown >= max, size: 28 })] })] })) : null, presets.length > 0 ? (_jsxs(Flex, { direction: "column", gap: 2, background: "surfaceRaised", radius: "row", py: 3.5, px: 4, children: [_jsx(Typography, { as: "span", variant: "bodyStrong", children: "Preset" }), _jsx(ChipRow, { options: presets.map((p) => ({ value: p, label: title(p) })), value: preset, onChange: onPreset })] })) : null] }));
98
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"climate-tile.js","sourceRoot":"","sources":["../../src/entities/climate-tile.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import type { LightEntity } from '@hashsome/core';
2
+ export interface Rgb {
3
+ r: number;
4
+ g: number;
5
+ b: number;
6
+ }
7
+ /** A pre-defined color shown as a swatch in a light tile's color overlay. */
8
+ export interface LightColorPreset {
9
+ label: string;
10
+ /** A white temperature, for lights that support `color_temp`. */
11
+ kelvin?: number;
12
+ /** Hue (0–360) and saturation (0–100), for lights that only support color. */
13
+ hs?: [number, number];
14
+ /** Literal CSS color for the swatch; derived from `kelvin`/`hs` when omitted. */
15
+ color?: string;
16
+ }
17
+ export declare const DEFAULT_COLOR_PRESETS: LightColorPreset[];
18
+ /** Approximate blackbody color for a white temperature (Tanner Helland's curve fit). */
19
+ export declare function kelvinToRgb(kelvin: number): Rgb;
20
+ export declare function hsToRgb(hue: number, saturation: number): Rgb;
21
+ export declare function rgbToHs({ r, g, b }: Rgb): [number, number];
22
+ export declare function rgbToHex({ r, g, b }: Rgb): string;
23
+ export declare function hexToRgb(hex: string): Rgb | undefined;
24
+ export declare function rgbCss({ r, g, b }: Rgb): string;
25
+ export declare function contrastRatio(a: Rgb, b: Rgb): number;
26
+ /** `fg`, pushed darker (on a light `bg`) or lighter (on a dark one) until it reaches `min` contrast
27
+ * against `bg` — so a pale light color (warm white) stays visible as an icon in the light theme. */
28
+ export declare function ensureContrast(fg: Rgb, bg: Rgb, min?: number): Rgb;
29
+ /** The light's current color as displayed. The model's `color` already says which mode is live, so
30
+ * there is no stale attribute to second-guess. */
31
+ export declare function resolveLightColor(light: LightEntity | undefined): Rgb | undefined;
32
+ export declare function currentHs(light: LightEntity | undefined): [number, number];
33
+ /** A command (and its arguments) that applies a preset to a light. */
34
+ export type PresetApplication = {
35
+ command: 'setColorTemperature';
36
+ args: {
37
+ kelvin: number;
38
+ };
39
+ } | {
40
+ command: 'setColor';
41
+ args: {
42
+ hue: number;
43
+ saturation: number;
44
+ };
45
+ };
46
+ /** How a preset would be applied to a light with these capabilities, or `undefined` if it can't be. */
47
+ export declare function applyPreset(preset: LightColorPreset, caps: {
48
+ colorTemp: boolean;
49
+ hs: boolean;
50
+ }): PresetApplication | undefined;
51
+ export declare function presetCss(preset: LightColorPreset): string;
52
+ export declare function isPresetActive(application: PresetApplication, light: LightEntity | undefined): boolean;
@@ -0,0 +1,148 @@
1
+ export const DEFAULT_COLOR_PRESETS = [
2
+ { label: 'Candle', kelvin: 2200 },
3
+ { label: 'Warm white', kelvin: 2700 },
4
+ { label: 'Neutral white', kelvin: 4000 },
5
+ { label: 'Daylight', kelvin: 6500 },
6
+ ];
7
+ const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
8
+ /** Approximate blackbody color for a white temperature (Tanner Helland's curve fit). */
9
+ export function kelvinToRgb(kelvin) {
10
+ const t = clamp(kelvin, 1000, 40000) / 100;
11
+ const r = t <= 66 ? 255 : 329.698727446 * (t - 60) ** -0.1332047592;
12
+ const g = t <= 66
13
+ ? 99.4708025861 * Math.log(t) - 161.1195681661
14
+ : 288.1221695283 * (t - 60) ** -0.0755148492;
15
+ const b = t >= 66 ? 255 : t <= 19 ? 0 : 138.5177312231 * Math.log(t - 10) - 305.0447927307;
16
+ return {
17
+ r: Math.round(clamp(r, 0, 255)),
18
+ g: Math.round(clamp(g, 0, 255)),
19
+ b: Math.round(clamp(b, 0, 255)),
20
+ };
21
+ }
22
+ export function hsToRgb(hue, saturation) {
23
+ const s = clamp(saturation, 0, 100) / 100;
24
+ const h = (((hue % 360) + 360) % 360) / 60;
25
+ const c = s;
26
+ const x = c * (1 - Math.abs((h % 2) - 1));
27
+ const [r1, g1, b1] = h < 1
28
+ ? [c, x, 0]
29
+ : h < 2
30
+ ? [x, c, 0]
31
+ : h < 3
32
+ ? [0, c, x]
33
+ : h < 4
34
+ ? [0, x, c]
35
+ : h < 5
36
+ ? [x, 0, c]
37
+ : [c, 0, x];
38
+ const m = 1 - c;
39
+ return {
40
+ r: Math.round((r1 + m) * 255),
41
+ g: Math.round((g1 + m) * 255),
42
+ b: Math.round((b1 + m) * 255),
43
+ };
44
+ }
45
+ export function rgbToHs({ r, g, b }) {
46
+ const max = Math.max(r, g, b) / 255;
47
+ const min = Math.min(r, g, b) / 255;
48
+ const d = max - min;
49
+ let h = 0;
50
+ if (d !== 0) {
51
+ const rn = r / 255;
52
+ const gn = g / 255;
53
+ const bn = b / 255;
54
+ h = max === rn ? ((gn - bn) / d) % 6 : max === gn ? (bn - rn) / d + 2 : (rn - gn) / d + 4;
55
+ h *= 60;
56
+ if (h < 0) {
57
+ h += 360;
58
+ }
59
+ }
60
+ return [Math.round(h), Math.round(max === 0 ? 0 : (d / max) * 100)];
61
+ }
62
+ export function rgbToHex({ r, g, b }) {
63
+ return `#${[r, g, b].map((n) => clamp(Math.round(n), 0, 255).toString(16).padStart(2, '0')).join('')}`;
64
+ }
65
+ export function hexToRgb(hex) {
66
+ const match = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
67
+ if (!match) {
68
+ return undefined;
69
+ }
70
+ const n = parseInt(match[1], 16);
71
+ return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };
72
+ }
73
+ export function rgbCss({ r, g, b }) {
74
+ return `rgb(${r}, ${g}, ${b})`;
75
+ }
76
+ const lin = (v) => {
77
+ const c = v / 255;
78
+ return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
79
+ };
80
+ function luminance({ r, g, b }) {
81
+ return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
82
+ }
83
+ export function contrastRatio(a, b) {
84
+ const [hi, lo] = [luminance(a), luminance(b)].toSorted((x, y) => y - x);
85
+ return (hi + 0.05) / (lo + 0.05);
86
+ }
87
+ /** `fg`, pushed darker (on a light `bg`) or lighter (on a dark one) until it reaches `min` contrast
88
+ * against `bg` — so a pale light color (warm white) stays visible as an icon in the light theme. */
89
+ export function ensureContrast(fg, bg, min = 3) {
90
+ const target = luminance(bg) > 0.4 ? 0 : 255;
91
+ let out = fg;
92
+ for (let i = 0; i < 20 && contrastRatio(out, bg) < min; i++) {
93
+ out = {
94
+ r: Math.round(out.r + (target - out.r) * 0.12),
95
+ g: Math.round(out.g + (target - out.g) * 0.12),
96
+ b: Math.round(out.b + (target - out.b) * 0.12),
97
+ };
98
+ }
99
+ return out;
100
+ }
101
+ /** The light's current color as displayed. The model's `color` already says which mode is live, so
102
+ * there is no stale attribute to second-guess. */
103
+ export function resolveLightColor(light) {
104
+ const color = light?.color;
105
+ if (!color) {
106
+ return undefined;
107
+ }
108
+ if (color.mode === 'temperature') {
109
+ return kelvinToRgb(color.kelvin);
110
+ }
111
+ return color.rgb
112
+ ? { r: color.rgb[0], g: color.rgb[1], b: color.rgb[2] }
113
+ : hsToRgb(color.hue, color.saturation);
114
+ }
115
+ export function currentHs(light) {
116
+ return light?.color?.mode === 'color' ? [light.color.hue, light.color.saturation] : [0, 100];
117
+ }
118
+ /** How a preset would be applied to a light with these capabilities, or `undefined` if it can't be. */
119
+ export function applyPreset(preset, caps) {
120
+ if (preset.kelvin !== undefined && caps.colorTemp) {
121
+ return { command: 'setColorTemperature', args: { kelvin: preset.kelvin } };
122
+ }
123
+ if (caps.hs) {
124
+ const hs = preset.hs ?? (preset.kelvin !== undefined ? rgbToHs(kelvinToRgb(preset.kelvin)) : undefined);
125
+ if (hs) {
126
+ return { command: 'setColor', args: { hue: hs[0], saturation: hs[1] } };
127
+ }
128
+ }
129
+ return undefined;
130
+ }
131
+ export function presetCss(preset) {
132
+ if (preset.color) {
133
+ return preset.color;
134
+ }
135
+ if (preset.kelvin !== undefined) {
136
+ return rgbCss(kelvinToRgb(preset.kelvin));
137
+ }
138
+ return preset.hs ? rgbCss(hsToRgb(preset.hs[0], preset.hs[1])) : '#ffffff';
139
+ }
140
+ export function isPresetActive(application, light) {
141
+ const color = light?.color;
142
+ if (application.command === 'setColorTemperature') {
143
+ return color?.mode === 'temperature' && color.kelvin === application.args.kelvin;
144
+ }
145
+ return (color?.mode === 'color' &&
146
+ Math.round(color.hue) === Math.round(application.args.hue) &&
147
+ Math.round(color.saturation) === Math.round(application.args.saturation));
148
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"light-color.js","sourceRoot":"","sources":["../../src/entities/light-color.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /** @jsxImportSource @emotion/react */
2
+ import type { EntityRef } from '@hashsome/core';
3
+ import { type EntityHandle } from '../entity-handle.ts';
4
+ import type { IconName } from '../icon-data.ts';
5
+ import type { EnergyChartProps } from '../layout/energy-chart.tsx';
6
+ import type { LogbookEntry } from '../layout/history-section.tsx';
7
+ import { type LightColorPreset } from './light-color.ts';
8
+ export interface LightTileProps {
9
+ /** A light, as a ref like `ha:light.kitchen_ceiling` or a handle (a custom source). */
10
+ entity: EntityRef | EntityHandle<'light'>;
11
+ /** Defaults to the light's name. */
12
+ name?: string;
13
+ /** Icon id. Defaults to a bulb. */
14
+ icon?: IconName;
15
+ /** Power-draw chart (e.g. a Shelly's energy monitoring), shown in the drawer above `history`.
16
+ * No default source yet — pass explicitly. */
17
+ energy?: EnergyChartProps;
18
+ /** Recent activity, shown in the drawer. No default source yet — pass explicitly. */
19
+ history?: LogbookEntry[];
20
+ /** Swatches shown when the palette button is opened. Default: four white temperatures. Each takes `kelvin` (color-temp lights) and/or `hs` (color lights) and is skipped if the light can't apply it. */
21
+ colors?: LightColorPreset[];
22
+ }
23
+ /** Toggle, drag-to-dim (if dimmable) and a color overlay + drawer picker (if color capable). */
24
+ export declare function LightTile({ entity, name, icon, energy, history, colors, }: LightTileProps): import("@emotion/react/jsx-runtime").JSX.Element;