@camstack/ui-library 1.2.342 → 1.2.344
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/CHANGELOG.md +12 -0
- package/dist/composites/battery-badge.d.ts +1 -1
- package/dist/composites/breadcrumb.d.ts +1 -1
- package/dist/composites/network-link-badge.d.ts +1 -1
- package/dist/hooks/use-device-network-link.d.ts +2 -2
- package/dist/index.cjs +54 -54
- package/dist/index.js +54 -54
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.344] - 2026-10-28
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- The breadcrumb usage example links to the new per-addon integration URL
|
|
15
|
+
|
|
16
|
+
## [1.2.343] - 2026-10-28
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Device value fields are named after their quantity instead of their unit; run the quantity-field migration after updating
|
|
21
|
+
|
|
10
22
|
## [1.2.342] - 2026-10-28
|
|
11
23
|
|
|
12
24
|
### Changed
|
|
@@ -15,7 +15,7 @@ import type { JSX } from "react";
|
|
|
15
15
|
export interface BatteryStatusLike {
|
|
16
16
|
/** `null` means no reading has landed yet (cold seed) — NOT a flat 0 %
|
|
17
17
|
* (D315). Render "Unknown", never a red critical badge. */
|
|
18
|
-
readonly
|
|
18
|
+
readonly level: number | null;
|
|
19
19
|
readonly charging: "dc" | "solar" | "none" | "unknown";
|
|
20
20
|
readonly sleeping: boolean;
|
|
21
21
|
/** True for a binary LOW_BAT source with no real % — render "Normal"/"Low"
|
|
@@ -18,7 +18,7 @@ export interface BreadcrumbProps {
|
|
|
18
18
|
* ```tsx
|
|
19
19
|
* <Breadcrumb items={[
|
|
20
20
|
* { label: 'Integrations', onClick: () => navigate('/integrations') },
|
|
21
|
-
* { label: 'RTSP Cameras', onClick: () => navigate('/integrations/int_0001') },
|
|
21
|
+
* { label: 'RTSP Cameras', onClick: () => navigate('/integrations/provider-rtsp?instance=int_0001') },
|
|
22
22
|
* { label: 'Front Door' },
|
|
23
23
|
* ]} />
|
|
24
24
|
* ```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type JSX } from "react";
|
|
2
2
|
export interface NetworkLinkStatusLike {
|
|
3
3
|
readonly type: "wifi" | "ethernet" | "cellular" | "unknown";
|
|
4
|
-
readonly
|
|
4
|
+
readonly signal: number | null;
|
|
5
5
|
readonly ssid?: string;
|
|
6
6
|
}
|
|
7
7
|
export interface NetworkLinkBadgeProps {
|
|
@@ -10,8 +10,8 @@ import { type UseDeviceProxyTrpc } from "./use-device-proxy";
|
|
|
10
10
|
export interface NetworkLinkStatus {
|
|
11
11
|
readonly type: "wifi" | "ethernet" | "cellular" | "unknown";
|
|
12
12
|
/** `null` = not known or not applicable (a wired link has no signal). */
|
|
13
|
-
readonly
|
|
14
|
-
readonly
|
|
13
|
+
readonly signal: number | null;
|
|
14
|
+
readonly rssi?: number;
|
|
15
15
|
readonly ssid?: string;
|
|
16
16
|
readonly lastUpdated: number;
|
|
17
17
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -36006,7 +36006,7 @@ function levelColor(percentage, charging) {
|
|
|
36006
36006
|
function BatteryBadge({ status, variant = "compact", className }) {
|
|
36007
36007
|
const t = useUiText();
|
|
36008
36008
|
if (!status) return null;
|
|
36009
|
-
const { percentage, charging, sleeping, binary } = status;
|
|
36009
|
+
const { level: percentage, charging, sleeping, binary } = status;
|
|
36010
36010
|
if (percentage === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
36011
36011
|
className: cn("inline-flex items-center gap-1 text-[10px] font-medium text-foreground-subtle", className),
|
|
36012
36012
|
title: t("uiLibrary.batteryBadge.titleUnknown", "Battery: unknown"),
|
|
@@ -36169,15 +36169,15 @@ function NetworkLinkBadge({ status, className }) {
|
|
|
36169
36169
|
title: t("uiLibrary.networkLinkBadge.ethernet", "Network: ethernet"),
|
|
36170
36170
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Cable, { className: "h-3.5 w-3.5" })
|
|
36171
36171
|
});
|
|
36172
|
-
const Icon = status.type === "cellular" ? RadioTower : pickWifiIcon(status.
|
|
36173
|
-
const signal = status.
|
|
36172
|
+
const Icon = status.type === "cellular" ? RadioTower : pickWifiIcon(status.signal);
|
|
36173
|
+
const signal = status.signal === null ? null : Math.round(status.signal);
|
|
36174
36174
|
const networkText = status.ssid ? t("uiLibrary.networkLinkBadge.typeSsid", "Network: {{type}} ({{ssid}})", {
|
|
36175
36175
|
type: status.type,
|
|
36176
36176
|
ssid: status.ssid
|
|
36177
36177
|
}) : t("uiLibrary.networkLinkBadge.type", "Network: {{type}}", { type: status.type });
|
|
36178
36178
|
const title = signal === null ? networkText : `${networkText} · ${t("uiLibrary.networkLinkBadge.signal", "signal {{percent}}%", { percent: signal })}`;
|
|
36179
36179
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
36180
|
-
className: cn("inline-flex items-center gap-1 text-[10px] font-medium", signalColor(status.
|
|
36180
|
+
className: cn("inline-flex items-center gap-1 text-[10px] font-medium", signalColor(status.signal), className),
|
|
36181
36181
|
title,
|
|
36182
36182
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { className: "h-3.5 w-3.5" }), signal !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [signal, "%"] })]
|
|
36183
36183
|
});
|
|
@@ -36348,7 +36348,7 @@ function RoleNodePill({ roleLabel, roleId, nodeName, colorId, emphasized = false
|
|
|
36348
36348
|
* ```tsx
|
|
36349
36349
|
* <Breadcrumb items={[
|
|
36350
36350
|
* { label: 'Integrations', onClick: () => navigate('/integrations') },
|
|
36351
|
-
* { label: 'RTSP Cameras', onClick: () => navigate('/integrations/int_0001') },
|
|
36351
|
+
* { label: 'RTSP Cameras', onClick: () => navigate('/integrations/provider-rtsp?instance=int_0001') },
|
|
36352
36352
|
* { label: 'Front Door' },
|
|
36353
36353
|
* ]} />
|
|
36354
36354
|
* ```
|
|
@@ -47427,16 +47427,16 @@ function BrightnessPanel({ trpc, deviceId, layout, optimistic }) {
|
|
|
47427
47427
|
min: 0,
|
|
47428
47428
|
max: 100,
|
|
47429
47429
|
step: 1,
|
|
47430
|
-
value: display.
|
|
47430
|
+
value: display.level,
|
|
47431
47431
|
disabled: busy,
|
|
47432
47432
|
onChange: (e) => {
|
|
47433
47433
|
const pct = Number(e.target.value);
|
|
47434
|
-
applyOptimistic({
|
|
47435
|
-
if (!busy) cap?.setBrightness({
|
|
47434
|
+
applyOptimistic({ level: pct });
|
|
47435
|
+
if (!busy) cap?.setBrightness({ level: pct });
|
|
47436
47436
|
}
|
|
47437
47437
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
47438
47438
|
className: "tabular-nums w-8 text-right",
|
|
47439
|
-
children: [display.
|
|
47439
|
+
children: [display.level, "%"]
|
|
47440
47440
|
})]
|
|
47441
47441
|
});
|
|
47442
47442
|
}
|
|
@@ -47467,17 +47467,17 @@ function FanPanel({ trpc, deviceId, features, layout, optimistic }) {
|
|
|
47467
47467
|
min: 0,
|
|
47468
47468
|
max: 100,
|
|
47469
47469
|
step,
|
|
47470
|
-
value: display.
|
|
47470
|
+
value: display.speed ?? 0,
|
|
47471
47471
|
disabled: busy,
|
|
47472
47472
|
onChange: (e) => {
|
|
47473
47473
|
const raw = Number(e.target.value);
|
|
47474
47474
|
const pct = Math.min(100, Math.max(0, Math.round(raw / step) * step));
|
|
47475
|
-
applyOptimistic({
|
|
47476
|
-
if (!busy) cap?.setPercentage({
|
|
47475
|
+
applyOptimistic({ speed: pct });
|
|
47476
|
+
if (!busy) cap?.setPercentage({ speed: pct });
|
|
47477
47477
|
}
|
|
47478
47478
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
47479
47479
|
className: "tabular-nums w-8 text-right",
|
|
47480
|
-
children: [display.
|
|
47480
|
+
children: [display.speed ?? "—", "%"]
|
|
47481
47481
|
})]
|
|
47482
47482
|
}), showPreset && display.availablePresets.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
47483
47483
|
className: "flex items-center gap-2 text-xs text-foreground-subtle",
|
|
@@ -48565,25 +48565,25 @@ function hasBatteryNumericValue(slice, field) {
|
|
|
48565
48565
|
var ROLE_DESCRIPTOR = {
|
|
48566
48566
|
"temperature-sensor": {
|
|
48567
48567
|
kind: "numeric",
|
|
48568
|
-
field: "
|
|
48568
|
+
field: "temperature",
|
|
48569
48569
|
quantity: "temperature",
|
|
48570
48570
|
getSliceHandle: (s) => s.temperatureSensor
|
|
48571
48571
|
},
|
|
48572
48572
|
"humidity-sensor": {
|
|
48573
48573
|
kind: "numeric",
|
|
48574
|
-
field: "
|
|
48574
|
+
field: "humidity",
|
|
48575
48575
|
quantity: "humidity",
|
|
48576
48576
|
getSliceHandle: (s) => s.humiditySensor
|
|
48577
48577
|
},
|
|
48578
48578
|
"ambient-light-sensor": {
|
|
48579
48579
|
kind: "numeric",
|
|
48580
|
-
field: "
|
|
48580
|
+
field: "illuminance",
|
|
48581
48581
|
quantity: "illuminance",
|
|
48582
48582
|
getSliceHandle: (s) => s.ambientLightSensor
|
|
48583
48583
|
},
|
|
48584
48584
|
"pressure-sensor": {
|
|
48585
48585
|
kind: "numeric",
|
|
48586
|
-
field: "
|
|
48586
|
+
field: "pressure",
|
|
48587
48587
|
quantity: "pressure",
|
|
48588
48588
|
getSliceHandle: (s) => s.pressureSensor
|
|
48589
48589
|
},
|
|
@@ -48625,25 +48625,25 @@ var ROLE_DESCRIPTOR = {
|
|
|
48625
48625
|
},
|
|
48626
48626
|
"power-sensor": {
|
|
48627
48627
|
kind: "numeric",
|
|
48628
|
-
field: "
|
|
48628
|
+
field: "power",
|
|
48629
48629
|
quantity: "power",
|
|
48630
48630
|
getSliceHandle: (s) => s.powerMeter
|
|
48631
48631
|
},
|
|
48632
48632
|
"energy-sensor": {
|
|
48633
48633
|
kind: "numeric",
|
|
48634
|
-
field: "
|
|
48634
|
+
field: "energy",
|
|
48635
48635
|
quantity: "energy",
|
|
48636
48636
|
getSliceHandle: (s) => s.powerMeter
|
|
48637
48637
|
},
|
|
48638
48638
|
"voltage-sensor": {
|
|
48639
48639
|
kind: "numeric",
|
|
48640
|
-
field: "
|
|
48640
|
+
field: "voltage",
|
|
48641
48641
|
quantity: "voltage",
|
|
48642
48642
|
getSliceHandle: (s) => s.powerMeter
|
|
48643
48643
|
},
|
|
48644
48644
|
"current-sensor": {
|
|
48645
48645
|
kind: "numeric",
|
|
48646
|
-
field: "
|
|
48646
|
+
field: "current",
|
|
48647
48647
|
quantity: "current",
|
|
48648
48648
|
getSliceHandle: (s) => s.powerMeter
|
|
48649
48649
|
},
|
|
@@ -49415,16 +49415,16 @@ function capSlice(caps, capName) {
|
|
|
49415
49415
|
return caps[capName];
|
|
49416
49416
|
}
|
|
49417
49417
|
/**
|
|
49418
|
-
* A battery group writes `battery.
|
|
49418
|
+
* A battery group writes `battery.level`. The role's usual cap is
|
|
49419
49419
|
* `numeric-sensor.value`. Hand the renderer a slice whose `value` is that
|
|
49420
49420
|
* percentage so one numeric path draws both.
|
|
49421
49421
|
*/
|
|
49422
49422
|
function batteryPercentageSlice(caps) {
|
|
49423
49423
|
const battery = capSlice(caps, "battery");
|
|
49424
|
-
if (!isRecord$2(battery) || typeof battery["
|
|
49424
|
+
if (!isRecord$2(battery) || typeof battery["level"] !== "number") return void 0;
|
|
49425
49425
|
return {
|
|
49426
49426
|
...battery,
|
|
49427
|
-
value: battery["
|
|
49427
|
+
value: battery["level"]
|
|
49428
49428
|
};
|
|
49429
49429
|
}
|
|
49430
49430
|
function snapshotSlice(input) {
|
|
@@ -50184,17 +50184,17 @@ function VacuumHeroCard({ trpc, deviceId }) {
|
|
|
50184
50184
|
children: meta.label
|
|
50185
50185
|
}), slice?.batteryLevel != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BatteryBadge$2, { level: slice.batteryLevel })]
|
|
50186
50186
|
}),
|
|
50187
|
-
slice?.
|
|
50187
|
+
slice?.progress != null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
50188
50188
|
className: "flex items-center gap-2",
|
|
50189
50189
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
50190
50190
|
className: "h-1.5 flex-1 rounded bg-surface-hover overflow-hidden",
|
|
50191
50191
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
50192
50192
|
className: "h-full bg-primary transition-[width] duration-500",
|
|
50193
|
-
style: { width: `${Math.max(0, Math.min(100, slice.
|
|
50193
|
+
style: { width: `${Math.max(0, Math.min(100, slice.progress))}%` }
|
|
50194
50194
|
})
|
|
50195
50195
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
50196
50196
|
className: "tabular-nums text-xs text-foreground-subtle",
|
|
50197
|
-
children: [Math.round(slice.
|
|
50197
|
+
children: [Math.round(slice.progress), "%"]
|
|
50198
50198
|
})]
|
|
50199
50199
|
}),
|
|
50200
50200
|
slice?.errorCode != null && slice.errorCode !== 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -50703,7 +50703,7 @@ function LawnMowerHeroCard({ trpc, deviceId }) {
|
|
|
50703
50703
|
children: meta.label
|
|
50704
50704
|
}), slice?.batteryLevel != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BatteryBadge$1, { level: slice.batteryLevel })]
|
|
50705
50705
|
}),
|
|
50706
|
-
slice?.
|
|
50706
|
+
slice?.progress != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProgressBar, { percent: slice.progress }),
|
|
50707
50707
|
slice?.currentCode != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodeLine, {
|
|
50708
50708
|
code: slice.currentCode,
|
|
50709
50709
|
label: slice.currentCodeLabel,
|
|
@@ -53354,9 +53354,9 @@ function DishwasherPanel({ trpc, deviceId, layout }) {
|
|
|
53354
53354
|
title: display.program,
|
|
53355
53355
|
children: featureLabel(display.program)
|
|
53356
53356
|
}),
|
|
53357
|
-
display.
|
|
53357
|
+
display.remaining != null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
53358
53358
|
className: "inline-flex items-center gap-0.5 text-xs text-foreground-subtle tabular-nums shrink-0",
|
|
53359
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Timer, { className: "h-3 w-3" }), formatDuration(display.
|
|
53359
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Timer, { className: "h-3 w-3" }), formatDuration(display.remaining, t)]
|
|
53360
53360
|
}),
|
|
53361
53361
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DishwasherIconButton, {
|
|
53362
53362
|
label: t("uiLibrary.dishwasher.start", "Start"),
|
|
@@ -53382,7 +53382,7 @@ function DishwasherPanel({ trpc, deviceId, layout }) {
|
|
|
53382
53382
|
className: "flex items-start gap-4",
|
|
53383
53383
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DishwasherGraphic, {
|
|
53384
53384
|
running,
|
|
53385
|
-
progressPercent: display.
|
|
53385
|
+
progressPercent: display.progress
|
|
53386
53386
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
53387
53387
|
className: "flex min-w-0 flex-1 flex-col gap-2",
|
|
53388
53388
|
children: [
|
|
@@ -53401,25 +53401,25 @@ function DishwasherPanel({ trpc, deviceId, layout }) {
|
|
|
53401
53401
|
title: display.program,
|
|
53402
53402
|
children: featureLabel(display.program)
|
|
53403
53403
|
}),
|
|
53404
|
-
display.
|
|
53404
|
+
display.remaining != null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
53405
53405
|
className: "inline-flex items-center gap-1 text-sm text-foreground-subtle tabular-nums",
|
|
53406
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Timer, { className: "h-3.5 w-3.5" }), t("uiLibrary.dishwasher.remaining", "{{time}} left", { time: formatDuration(display.
|
|
53406
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Timer, { className: "h-3.5 w-3.5" }), t("uiLibrary.dishwasher.remaining", "{{time}} left", { time: formatDuration(display.remaining, t) })]
|
|
53407
53407
|
}),
|
|
53408
|
-
display.
|
|
53408
|
+
display.delayedStart != null && display.delayedStart > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
53409
53409
|
className: "text-xs text-foreground-subtle tabular-nums",
|
|
53410
|
-
children: t("uiLibrary.dishwasher.startsIn", "Starts in {{time}}", { time: formatDuration(display.
|
|
53410
|
+
children: t("uiLibrary.dishwasher.startsIn", "Starts in {{time}}", { time: formatDuration(display.delayedStart, t) })
|
|
53411
53411
|
}),
|
|
53412
|
-
display.
|
|
53412
|
+
display.progress != null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
53413
53413
|
className: "flex items-center gap-2",
|
|
53414
53414
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
53415
53415
|
className: "h-1.5 flex-1 rounded bg-surface-hover overflow-hidden",
|
|
53416
53416
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
53417
53417
|
className: "h-full bg-primary transition-[width] duration-500",
|
|
53418
|
-
style: { width: `${Math.max(0, Math.min(100, display.
|
|
53418
|
+
style: { width: `${Math.max(0, Math.min(100, display.progress))}%` }
|
|
53419
53419
|
})
|
|
53420
53420
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
53421
53421
|
className: "tabular-nums text-xs text-foreground-subtle",
|
|
53422
|
-
children: [Math.round(display.
|
|
53422
|
+
children: [Math.round(display.progress), "%"]
|
|
53423
53423
|
})]
|
|
53424
53424
|
}),
|
|
53425
53425
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -54814,12 +54814,12 @@ function LightHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
54814
54814
|
if (swOpt.display === void 0) return null;
|
|
54815
54815
|
const on = swOpt.display.on === true;
|
|
54816
54816
|
const swBusy = !sw.available;
|
|
54817
|
-
const percentage = brightOpt.display?.
|
|
54817
|
+
const percentage = brightOpt.display?.level ?? 0;
|
|
54818
54818
|
const brightBusy = !bright.available;
|
|
54819
54819
|
const fraction = on ? percentage / 100 : 0;
|
|
54820
54820
|
const arcColor = on ? ARC_COLOR_ON$1 : ARC_COLOR_OFF$1;
|
|
54821
54821
|
const supportsCt = (features?.includes(_camstack_types.DeviceFeature.LightColorMired) ?? false) && color.cap !== void 0;
|
|
54822
|
-
const ctMireds = colorOpt.display?.
|
|
54822
|
+
const ctMireds = colorOpt.display?.colorTemperature;
|
|
54823
54823
|
const ctBusy = !color.available;
|
|
54824
54824
|
const handleToggle = () => {
|
|
54825
54825
|
if (swBusy) return;
|
|
@@ -54864,8 +54864,8 @@ function LightHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
54864
54864
|
disabled: brightBusy || !on,
|
|
54865
54865
|
onChange: (e) => {
|
|
54866
54866
|
const pct = Number(e.target.value);
|
|
54867
|
-
brightOpt.applyOptimistic({
|
|
54868
|
-
if (!brightBusy) bright.cap?.setBrightness({
|
|
54867
|
+
brightOpt.applyOptimistic({ level: pct });
|
|
54868
|
+
if (!brightBusy) bright.cap?.setBrightness({ level: pct });
|
|
54869
54869
|
}
|
|
54870
54870
|
}),
|
|
54871
54871
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
@@ -54912,11 +54912,11 @@ function LightHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
54912
54912
|
const mireds = Number(e.target.value);
|
|
54913
54913
|
colorOpt.applyOptimistic({
|
|
54914
54914
|
mode: "mired",
|
|
54915
|
-
mireds
|
|
54915
|
+
colorTemperature: mireds
|
|
54916
54916
|
});
|
|
54917
54917
|
if (!ctBusy) color.cap?.setColor({ color: {
|
|
54918
54918
|
mode: "mired",
|
|
54919
|
-
mireds
|
|
54919
|
+
colorTemperature: mireds
|
|
54920
54920
|
} });
|
|
54921
54921
|
}
|
|
54922
54922
|
}),
|
|
@@ -54976,7 +54976,7 @@ function FanHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
54976
54976
|
if (swOpt.display === void 0) return null;
|
|
54977
54977
|
const on = swOpt.display.on === true;
|
|
54978
54978
|
const swBusy = !sw.available;
|
|
54979
|
-
const percentage = fanOpt.display?.
|
|
54979
|
+
const percentage = fanOpt.display?.speed ?? 0;
|
|
54980
54980
|
const fanBusy = !fan.available;
|
|
54981
54981
|
const fraction = on ? percentage / 100 : 0;
|
|
54982
54982
|
const arcColor = on ? ARC_COLOR_ON : ARC_COLOR_OFF;
|
|
@@ -55005,8 +55005,8 @@ function FanHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
55005
55005
|
if (slice === void 0) return;
|
|
55006
55006
|
const step = slice.percentageStep !== void 0 && slice.percentageStep > 0 ? slice.percentageStep : 1;
|
|
55007
55007
|
const pct = Math.min(100, Math.max(0, Math.round(f * 100 / step) * step));
|
|
55008
|
-
fanOpt.applyOptimistic({
|
|
55009
|
-
fan.cap?.setPercentage({
|
|
55008
|
+
fanOpt.applyOptimistic({ speed: pct });
|
|
55009
|
+
fan.cap?.setPercentage({ speed: pct });
|
|
55010
55010
|
};
|
|
55011
55011
|
const handlePreset = (preset) => {
|
|
55012
55012
|
if (fanBusy || preset === "") return;
|
|
@@ -55228,7 +55228,7 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
55228
55228
|
if (display === void 0) return null;
|
|
55229
55229
|
const busy = !available;
|
|
55230
55230
|
const action = toggleAction(display.state);
|
|
55231
|
-
const supportsSeek = (features?.includes(_camstack_types.DeviceFeature.MediaPlayerSeek) ?? false) && display.
|
|
55231
|
+
const supportsSeek = (features?.includes(_camstack_types.DeviceFeature.MediaPlayerSeek) ?? false) && display.duration !== null && display.duration > 0;
|
|
55232
55232
|
const supportsNext = features?.includes(_camstack_types.DeviceFeature.MediaPlayerNext) ?? false;
|
|
55233
55233
|
const supportsPrevious = features?.includes(_camstack_types.DeviceFeature.MediaPlayerPrevious) ?? false;
|
|
55234
55234
|
const supportsVolume = (features?.includes(_camstack_types.DeviceFeature.MediaPlayerVolume) ?? false) && display.volumeLevel !== null;
|
|
@@ -55243,7 +55243,7 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
55243
55243
|
}
|
|
55244
55244
|
};
|
|
55245
55245
|
const subtitle = display.currentMedia?.artist ?? display.currentMedia?.album ?? null;
|
|
55246
|
-
const seekFraction = progressFraction(display.
|
|
55246
|
+
const seekFraction = progressFraction(display.position, display.duration);
|
|
55247
55247
|
const volumeLevel = display.volumeLevel ?? 0;
|
|
55248
55248
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55249
55249
|
className: "flex flex-col items-stretch gap-4 rounded-lg border border-border bg-surface p-6",
|
|
@@ -55266,16 +55266,16 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
55266
55266
|
"aria-label": t("uiLibrary.mediaPlayerHero.seek", "Seek"),
|
|
55267
55267
|
type: "range",
|
|
55268
55268
|
min: 0,
|
|
55269
|
-
max: display.
|
|
55269
|
+
max: display.duration ?? 0,
|
|
55270
55270
|
step: 1e3,
|
|
55271
55271
|
className: "absolute inset-0 h-4 w-full cursor-pointer opacity-0",
|
|
55272
|
-
value: display.
|
|
55272
|
+
value: display.position ?? 0,
|
|
55273
55273
|
disabled: busy,
|
|
55274
55274
|
onChange: (e) => {
|
|
55275
55275
|
if (busy) return;
|
|
55276
55276
|
const positionMs = Number(e.target.value);
|
|
55277
|
-
applyOptimistic({ positionMs });
|
|
55278
|
-
cap.seek({ positionMs });
|
|
55277
|
+
applyOptimistic({ position: positionMs });
|
|
55278
|
+
cap.seek({ position: positionMs });
|
|
55279
55279
|
}
|
|
55280
55280
|
}),
|
|
55281
55281
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -55285,7 +55285,7 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
55285
55285
|
]
|
|
55286
55286
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55287
55287
|
className: "flex justify-between text-[11px] tabular-nums text-foreground-subtle",
|
|
55288
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatClock(display.
|
|
55288
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatClock(display.position) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatClock(display.duration) })]
|
|
55289
55289
|
})]
|
|
55290
55290
|
}),
|
|
55291
55291
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
package/dist/index.js
CHANGED
|
@@ -35982,7 +35982,7 @@ function levelColor(percentage, charging) {
|
|
|
35982
35982
|
function BatteryBadge({ status, variant = "compact", className }) {
|
|
35983
35983
|
const t = useUiText();
|
|
35984
35984
|
if (!status) return null;
|
|
35985
|
-
const { percentage, charging, sleeping, binary } = status;
|
|
35985
|
+
const { level: percentage, charging, sleeping, binary } = status;
|
|
35986
35986
|
if (percentage === null) return /* @__PURE__ */ jsxs("span", {
|
|
35987
35987
|
className: cn("inline-flex items-center gap-1 text-[10px] font-medium text-foreground-subtle", className),
|
|
35988
35988
|
title: t("uiLibrary.batteryBadge.titleUnknown", "Battery: unknown"),
|
|
@@ -36145,15 +36145,15 @@ function NetworkLinkBadge({ status, className }) {
|
|
|
36145
36145
|
title: t("uiLibrary.networkLinkBadge.ethernet", "Network: ethernet"),
|
|
36146
36146
|
children: /* @__PURE__ */ jsx(Cable, { className: "h-3.5 w-3.5" })
|
|
36147
36147
|
});
|
|
36148
|
-
const Icon = status.type === "cellular" ? RadioTower : pickWifiIcon(status.
|
|
36149
|
-
const signal = status.
|
|
36148
|
+
const Icon = status.type === "cellular" ? RadioTower : pickWifiIcon(status.signal);
|
|
36149
|
+
const signal = status.signal === null ? null : Math.round(status.signal);
|
|
36150
36150
|
const networkText = status.ssid ? t("uiLibrary.networkLinkBadge.typeSsid", "Network: {{type}} ({{ssid}})", {
|
|
36151
36151
|
type: status.type,
|
|
36152
36152
|
ssid: status.ssid
|
|
36153
36153
|
}) : t("uiLibrary.networkLinkBadge.type", "Network: {{type}}", { type: status.type });
|
|
36154
36154
|
const title = signal === null ? networkText : `${networkText} · ${t("uiLibrary.networkLinkBadge.signal", "signal {{percent}}%", { percent: signal })}`;
|
|
36155
36155
|
return /* @__PURE__ */ jsxs("span", {
|
|
36156
|
-
className: cn("inline-flex items-center gap-1 text-[10px] font-medium", signalColor(status.
|
|
36156
|
+
className: cn("inline-flex items-center gap-1 text-[10px] font-medium", signalColor(status.signal), className),
|
|
36157
36157
|
title,
|
|
36158
36158
|
children: [/* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" }), signal !== null && /* @__PURE__ */ jsxs("span", { children: [signal, "%"] })]
|
|
36159
36159
|
});
|
|
@@ -36324,7 +36324,7 @@ function RoleNodePill({ roleLabel, roleId, nodeName, colorId, emphasized = false
|
|
|
36324
36324
|
* ```tsx
|
|
36325
36325
|
* <Breadcrumb items={[
|
|
36326
36326
|
* { label: 'Integrations', onClick: () => navigate('/integrations') },
|
|
36327
|
-
* { label: 'RTSP Cameras', onClick: () => navigate('/integrations/int_0001') },
|
|
36327
|
+
* { label: 'RTSP Cameras', onClick: () => navigate('/integrations/provider-rtsp?instance=int_0001') },
|
|
36328
36328
|
* { label: 'Front Door' },
|
|
36329
36329
|
* ]} />
|
|
36330
36330
|
* ```
|
|
@@ -47403,16 +47403,16 @@ function BrightnessPanel({ trpc, deviceId, layout, optimistic }) {
|
|
|
47403
47403
|
min: 0,
|
|
47404
47404
|
max: 100,
|
|
47405
47405
|
step: 1,
|
|
47406
|
-
value: display.
|
|
47406
|
+
value: display.level,
|
|
47407
47407
|
disabled: busy,
|
|
47408
47408
|
onChange: (e) => {
|
|
47409
47409
|
const pct = Number(e.target.value);
|
|
47410
|
-
applyOptimistic({
|
|
47411
|
-
if (!busy) cap?.setBrightness({
|
|
47410
|
+
applyOptimistic({ level: pct });
|
|
47411
|
+
if (!busy) cap?.setBrightness({ level: pct });
|
|
47412
47412
|
}
|
|
47413
47413
|
}), /* @__PURE__ */ jsxs("span", {
|
|
47414
47414
|
className: "tabular-nums w-8 text-right",
|
|
47415
|
-
children: [display.
|
|
47415
|
+
children: [display.level, "%"]
|
|
47416
47416
|
})]
|
|
47417
47417
|
});
|
|
47418
47418
|
}
|
|
@@ -47443,17 +47443,17 @@ function FanPanel({ trpc, deviceId, features, layout, optimistic }) {
|
|
|
47443
47443
|
min: 0,
|
|
47444
47444
|
max: 100,
|
|
47445
47445
|
step,
|
|
47446
|
-
value: display.
|
|
47446
|
+
value: display.speed ?? 0,
|
|
47447
47447
|
disabled: busy,
|
|
47448
47448
|
onChange: (e) => {
|
|
47449
47449
|
const raw = Number(e.target.value);
|
|
47450
47450
|
const pct = Math.min(100, Math.max(0, Math.round(raw / step) * step));
|
|
47451
|
-
applyOptimistic({
|
|
47452
|
-
if (!busy) cap?.setPercentage({
|
|
47451
|
+
applyOptimistic({ speed: pct });
|
|
47452
|
+
if (!busy) cap?.setPercentage({ speed: pct });
|
|
47453
47453
|
}
|
|
47454
47454
|
}), /* @__PURE__ */ jsxs("span", {
|
|
47455
47455
|
className: "tabular-nums w-8 text-right",
|
|
47456
|
-
children: [display.
|
|
47456
|
+
children: [display.speed ?? "—", "%"]
|
|
47457
47457
|
})]
|
|
47458
47458
|
}), showPreset && display.availablePresets.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
47459
47459
|
className: "flex items-center gap-2 text-xs text-foreground-subtle",
|
|
@@ -48541,25 +48541,25 @@ function hasBatteryNumericValue(slice, field) {
|
|
|
48541
48541
|
var ROLE_DESCRIPTOR = {
|
|
48542
48542
|
"temperature-sensor": {
|
|
48543
48543
|
kind: "numeric",
|
|
48544
|
-
field: "
|
|
48544
|
+
field: "temperature",
|
|
48545
48545
|
quantity: "temperature",
|
|
48546
48546
|
getSliceHandle: (s) => s.temperatureSensor
|
|
48547
48547
|
},
|
|
48548
48548
|
"humidity-sensor": {
|
|
48549
48549
|
kind: "numeric",
|
|
48550
|
-
field: "
|
|
48550
|
+
field: "humidity",
|
|
48551
48551
|
quantity: "humidity",
|
|
48552
48552
|
getSliceHandle: (s) => s.humiditySensor
|
|
48553
48553
|
},
|
|
48554
48554
|
"ambient-light-sensor": {
|
|
48555
48555
|
kind: "numeric",
|
|
48556
|
-
field: "
|
|
48556
|
+
field: "illuminance",
|
|
48557
48557
|
quantity: "illuminance",
|
|
48558
48558
|
getSliceHandle: (s) => s.ambientLightSensor
|
|
48559
48559
|
},
|
|
48560
48560
|
"pressure-sensor": {
|
|
48561
48561
|
kind: "numeric",
|
|
48562
|
-
field: "
|
|
48562
|
+
field: "pressure",
|
|
48563
48563
|
quantity: "pressure",
|
|
48564
48564
|
getSliceHandle: (s) => s.pressureSensor
|
|
48565
48565
|
},
|
|
@@ -48601,25 +48601,25 @@ var ROLE_DESCRIPTOR = {
|
|
|
48601
48601
|
},
|
|
48602
48602
|
"power-sensor": {
|
|
48603
48603
|
kind: "numeric",
|
|
48604
|
-
field: "
|
|
48604
|
+
field: "power",
|
|
48605
48605
|
quantity: "power",
|
|
48606
48606
|
getSliceHandle: (s) => s.powerMeter
|
|
48607
48607
|
},
|
|
48608
48608
|
"energy-sensor": {
|
|
48609
48609
|
kind: "numeric",
|
|
48610
|
-
field: "
|
|
48610
|
+
field: "energy",
|
|
48611
48611
|
quantity: "energy",
|
|
48612
48612
|
getSliceHandle: (s) => s.powerMeter
|
|
48613
48613
|
},
|
|
48614
48614
|
"voltage-sensor": {
|
|
48615
48615
|
kind: "numeric",
|
|
48616
|
-
field: "
|
|
48616
|
+
field: "voltage",
|
|
48617
48617
|
quantity: "voltage",
|
|
48618
48618
|
getSliceHandle: (s) => s.powerMeter
|
|
48619
48619
|
},
|
|
48620
48620
|
"current-sensor": {
|
|
48621
48621
|
kind: "numeric",
|
|
48622
|
-
field: "
|
|
48622
|
+
field: "current",
|
|
48623
48623
|
quantity: "current",
|
|
48624
48624
|
getSliceHandle: (s) => s.powerMeter
|
|
48625
48625
|
},
|
|
@@ -49391,16 +49391,16 @@ function capSlice(caps, capName) {
|
|
|
49391
49391
|
return caps[capName];
|
|
49392
49392
|
}
|
|
49393
49393
|
/**
|
|
49394
|
-
* A battery group writes `battery.
|
|
49394
|
+
* A battery group writes `battery.level`. The role's usual cap is
|
|
49395
49395
|
* `numeric-sensor.value`. Hand the renderer a slice whose `value` is that
|
|
49396
49396
|
* percentage so one numeric path draws both.
|
|
49397
49397
|
*/
|
|
49398
49398
|
function batteryPercentageSlice(caps) {
|
|
49399
49399
|
const battery = capSlice(caps, "battery");
|
|
49400
|
-
if (!isRecord$2(battery) || typeof battery["
|
|
49400
|
+
if (!isRecord$2(battery) || typeof battery["level"] !== "number") return void 0;
|
|
49401
49401
|
return {
|
|
49402
49402
|
...battery,
|
|
49403
|
-
value: battery["
|
|
49403
|
+
value: battery["level"]
|
|
49404
49404
|
};
|
|
49405
49405
|
}
|
|
49406
49406
|
function snapshotSlice(input) {
|
|
@@ -50160,17 +50160,17 @@ function VacuumHeroCard({ trpc, deviceId }) {
|
|
|
50160
50160
|
children: meta.label
|
|
50161
50161
|
}), slice?.batteryLevel != null && /* @__PURE__ */ jsx(BatteryBadge$2, { level: slice.batteryLevel })]
|
|
50162
50162
|
}),
|
|
50163
|
-
slice?.
|
|
50163
|
+
slice?.progress != null && /* @__PURE__ */ jsxs("div", {
|
|
50164
50164
|
className: "flex items-center gap-2",
|
|
50165
50165
|
children: [/* @__PURE__ */ jsx("div", {
|
|
50166
50166
|
className: "h-1.5 flex-1 rounded bg-surface-hover overflow-hidden",
|
|
50167
50167
|
children: /* @__PURE__ */ jsx("div", {
|
|
50168
50168
|
className: "h-full bg-primary transition-[width] duration-500",
|
|
50169
|
-
style: { width: `${Math.max(0, Math.min(100, slice.
|
|
50169
|
+
style: { width: `${Math.max(0, Math.min(100, slice.progress))}%` }
|
|
50170
50170
|
})
|
|
50171
50171
|
}), /* @__PURE__ */ jsxs("span", {
|
|
50172
50172
|
className: "tabular-nums text-xs text-foreground-subtle",
|
|
50173
|
-
children: [Math.round(slice.
|
|
50173
|
+
children: [Math.round(slice.progress), "%"]
|
|
50174
50174
|
})]
|
|
50175
50175
|
}),
|
|
50176
50176
|
slice?.errorCode != null && slice.errorCode !== 0 && /* @__PURE__ */ jsxs("div", {
|
|
@@ -50679,7 +50679,7 @@ function LawnMowerHeroCard({ trpc, deviceId }) {
|
|
|
50679
50679
|
children: meta.label
|
|
50680
50680
|
}), slice?.batteryLevel != null && /* @__PURE__ */ jsx(BatteryBadge$1, { level: slice.batteryLevel })]
|
|
50681
50681
|
}),
|
|
50682
|
-
slice?.
|
|
50682
|
+
slice?.progress != null && /* @__PURE__ */ jsx(ProgressBar, { percent: slice.progress }),
|
|
50683
50683
|
slice?.currentCode != null && /* @__PURE__ */ jsx(CodeLine, {
|
|
50684
50684
|
code: slice.currentCode,
|
|
50685
50685
|
label: slice.currentCodeLabel,
|
|
@@ -53330,9 +53330,9 @@ function DishwasherPanel({ trpc, deviceId, layout }) {
|
|
|
53330
53330
|
title: display.program,
|
|
53331
53331
|
children: featureLabel(display.program)
|
|
53332
53332
|
}),
|
|
53333
|
-
display.
|
|
53333
|
+
display.remaining != null && /* @__PURE__ */ jsxs("span", {
|
|
53334
53334
|
className: "inline-flex items-center gap-0.5 text-xs text-foreground-subtle tabular-nums shrink-0",
|
|
53335
|
-
children: [/* @__PURE__ */ jsx(Timer, { className: "h-3 w-3" }), formatDuration(display.
|
|
53335
|
+
children: [/* @__PURE__ */ jsx(Timer, { className: "h-3 w-3" }), formatDuration(display.remaining, t)]
|
|
53336
53336
|
}),
|
|
53337
53337
|
/* @__PURE__ */ jsx(DishwasherIconButton, {
|
|
53338
53338
|
label: t("uiLibrary.dishwasher.start", "Start"),
|
|
@@ -53358,7 +53358,7 @@ function DishwasherPanel({ trpc, deviceId, layout }) {
|
|
|
53358
53358
|
className: "flex items-start gap-4",
|
|
53359
53359
|
children: [/* @__PURE__ */ jsx(DishwasherGraphic, {
|
|
53360
53360
|
running,
|
|
53361
|
-
progressPercent: display.
|
|
53361
|
+
progressPercent: display.progress
|
|
53362
53362
|
}), /* @__PURE__ */ jsxs("div", {
|
|
53363
53363
|
className: "flex min-w-0 flex-1 flex-col gap-2",
|
|
53364
53364
|
children: [
|
|
@@ -53377,25 +53377,25 @@ function DishwasherPanel({ trpc, deviceId, layout }) {
|
|
|
53377
53377
|
title: display.program,
|
|
53378
53378
|
children: featureLabel(display.program)
|
|
53379
53379
|
}),
|
|
53380
|
-
display.
|
|
53380
|
+
display.remaining != null && /* @__PURE__ */ jsxs("span", {
|
|
53381
53381
|
className: "inline-flex items-center gap-1 text-sm text-foreground-subtle tabular-nums",
|
|
53382
|
-
children: [/* @__PURE__ */ jsx(Timer, { className: "h-3.5 w-3.5" }), t("uiLibrary.dishwasher.remaining", "{{time}} left", { time: formatDuration(display.
|
|
53382
|
+
children: [/* @__PURE__ */ jsx(Timer, { className: "h-3.5 w-3.5" }), t("uiLibrary.dishwasher.remaining", "{{time}} left", { time: formatDuration(display.remaining, t) })]
|
|
53383
53383
|
}),
|
|
53384
|
-
display.
|
|
53384
|
+
display.delayedStart != null && display.delayedStart > 0 && /* @__PURE__ */ jsx("span", {
|
|
53385
53385
|
className: "text-xs text-foreground-subtle tabular-nums",
|
|
53386
|
-
children: t("uiLibrary.dishwasher.startsIn", "Starts in {{time}}", { time: formatDuration(display.
|
|
53386
|
+
children: t("uiLibrary.dishwasher.startsIn", "Starts in {{time}}", { time: formatDuration(display.delayedStart, t) })
|
|
53387
53387
|
}),
|
|
53388
|
-
display.
|
|
53388
|
+
display.progress != null && /* @__PURE__ */ jsxs("div", {
|
|
53389
53389
|
className: "flex items-center gap-2",
|
|
53390
53390
|
children: [/* @__PURE__ */ jsx("div", {
|
|
53391
53391
|
className: "h-1.5 flex-1 rounded bg-surface-hover overflow-hidden",
|
|
53392
53392
|
children: /* @__PURE__ */ jsx("div", {
|
|
53393
53393
|
className: "h-full bg-primary transition-[width] duration-500",
|
|
53394
|
-
style: { width: `${Math.max(0, Math.min(100, display.
|
|
53394
|
+
style: { width: `${Math.max(0, Math.min(100, display.progress))}%` }
|
|
53395
53395
|
})
|
|
53396
53396
|
}), /* @__PURE__ */ jsxs("span", {
|
|
53397
53397
|
className: "tabular-nums text-xs text-foreground-subtle",
|
|
53398
|
-
children: [Math.round(display.
|
|
53398
|
+
children: [Math.round(display.progress), "%"]
|
|
53399
53399
|
})]
|
|
53400
53400
|
}),
|
|
53401
53401
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -54790,12 +54790,12 @@ function LightHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
54790
54790
|
if (swOpt.display === void 0) return null;
|
|
54791
54791
|
const on = swOpt.display.on === true;
|
|
54792
54792
|
const swBusy = !sw.available;
|
|
54793
|
-
const percentage = brightOpt.display?.
|
|
54793
|
+
const percentage = brightOpt.display?.level ?? 0;
|
|
54794
54794
|
const brightBusy = !bright.available;
|
|
54795
54795
|
const fraction = on ? percentage / 100 : 0;
|
|
54796
54796
|
const arcColor = on ? ARC_COLOR_ON$1 : ARC_COLOR_OFF$1;
|
|
54797
54797
|
const supportsCt = (features?.includes(DeviceFeature.LightColorMired) ?? false) && color.cap !== void 0;
|
|
54798
|
-
const ctMireds = colorOpt.display?.
|
|
54798
|
+
const ctMireds = colorOpt.display?.colorTemperature;
|
|
54799
54799
|
const ctBusy = !color.available;
|
|
54800
54800
|
const handleToggle = () => {
|
|
54801
54801
|
if (swBusy) return;
|
|
@@ -54840,8 +54840,8 @@ function LightHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
54840
54840
|
disabled: brightBusy || !on,
|
|
54841
54841
|
onChange: (e) => {
|
|
54842
54842
|
const pct = Number(e.target.value);
|
|
54843
|
-
brightOpt.applyOptimistic({
|
|
54844
|
-
if (!brightBusy) bright.cap?.setBrightness({
|
|
54843
|
+
brightOpt.applyOptimistic({ level: pct });
|
|
54844
|
+
if (!brightBusy) bright.cap?.setBrightness({ level: pct });
|
|
54845
54845
|
}
|
|
54846
54846
|
}),
|
|
54847
54847
|
/* @__PURE__ */ jsxs("span", {
|
|
@@ -54888,11 +54888,11 @@ function LightHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
54888
54888
|
const mireds = Number(e.target.value);
|
|
54889
54889
|
colorOpt.applyOptimistic({
|
|
54890
54890
|
mode: "mired",
|
|
54891
|
-
mireds
|
|
54891
|
+
colorTemperature: mireds
|
|
54892
54892
|
});
|
|
54893
54893
|
if (!ctBusy) color.cap?.setColor({ color: {
|
|
54894
54894
|
mode: "mired",
|
|
54895
|
-
mireds
|
|
54895
|
+
colorTemperature: mireds
|
|
54896
54896
|
} });
|
|
54897
54897
|
}
|
|
54898
54898
|
}),
|
|
@@ -54952,7 +54952,7 @@ function FanHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
54952
54952
|
if (swOpt.display === void 0) return null;
|
|
54953
54953
|
const on = swOpt.display.on === true;
|
|
54954
54954
|
const swBusy = !sw.available;
|
|
54955
|
-
const percentage = fanOpt.display?.
|
|
54955
|
+
const percentage = fanOpt.display?.speed ?? 0;
|
|
54956
54956
|
const fanBusy = !fan.available;
|
|
54957
54957
|
const fraction = on ? percentage / 100 : 0;
|
|
54958
54958
|
const arcColor = on ? ARC_COLOR_ON : ARC_COLOR_OFF;
|
|
@@ -54981,8 +54981,8 @@ function FanHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
54981
54981
|
if (slice === void 0) return;
|
|
54982
54982
|
const step = slice.percentageStep !== void 0 && slice.percentageStep > 0 ? slice.percentageStep : 1;
|
|
54983
54983
|
const pct = Math.min(100, Math.max(0, Math.round(f * 100 / step) * step));
|
|
54984
|
-
fanOpt.applyOptimistic({
|
|
54985
|
-
fan.cap?.setPercentage({
|
|
54984
|
+
fanOpt.applyOptimistic({ speed: pct });
|
|
54985
|
+
fan.cap?.setPercentage({ speed: pct });
|
|
54986
54986
|
};
|
|
54987
54987
|
const handlePreset = (preset) => {
|
|
54988
54988
|
if (fanBusy || preset === "") return;
|
|
@@ -55204,7 +55204,7 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
55204
55204
|
if (display === void 0) return null;
|
|
55205
55205
|
const busy = !available;
|
|
55206
55206
|
const action = toggleAction(display.state);
|
|
55207
|
-
const supportsSeek = (features?.includes(DeviceFeature.MediaPlayerSeek) ?? false) && display.
|
|
55207
|
+
const supportsSeek = (features?.includes(DeviceFeature.MediaPlayerSeek) ?? false) && display.duration !== null && display.duration > 0;
|
|
55208
55208
|
const supportsNext = features?.includes(DeviceFeature.MediaPlayerNext) ?? false;
|
|
55209
55209
|
const supportsPrevious = features?.includes(DeviceFeature.MediaPlayerPrevious) ?? false;
|
|
55210
55210
|
const supportsVolume = (features?.includes(DeviceFeature.MediaPlayerVolume) ?? false) && display.volumeLevel !== null;
|
|
@@ -55219,7 +55219,7 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
55219
55219
|
}
|
|
55220
55220
|
};
|
|
55221
55221
|
const subtitle = display.currentMedia?.artist ?? display.currentMedia?.album ?? null;
|
|
55222
|
-
const seekFraction = progressFraction(display.
|
|
55222
|
+
const seekFraction = progressFraction(display.position, display.duration);
|
|
55223
55223
|
const volumeLevel = display.volumeLevel ?? 0;
|
|
55224
55224
|
return /* @__PURE__ */ jsxs("div", {
|
|
55225
55225
|
className: "flex flex-col items-stretch gap-4 rounded-lg border border-border bg-surface p-6",
|
|
@@ -55242,16 +55242,16 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
55242
55242
|
"aria-label": t("uiLibrary.mediaPlayerHero.seek", "Seek"),
|
|
55243
55243
|
type: "range",
|
|
55244
55244
|
min: 0,
|
|
55245
|
-
max: display.
|
|
55245
|
+
max: display.duration ?? 0,
|
|
55246
55246
|
step: 1e3,
|
|
55247
55247
|
className: "absolute inset-0 h-4 w-full cursor-pointer opacity-0",
|
|
55248
|
-
value: display.
|
|
55248
|
+
value: display.position ?? 0,
|
|
55249
55249
|
disabled: busy,
|
|
55250
55250
|
onChange: (e) => {
|
|
55251
55251
|
if (busy) return;
|
|
55252
55252
|
const positionMs = Number(e.target.value);
|
|
55253
|
-
applyOptimistic({ positionMs });
|
|
55254
|
-
cap.seek({ positionMs });
|
|
55253
|
+
applyOptimistic({ position: positionMs });
|
|
55254
|
+
cap.seek({ position: positionMs });
|
|
55255
55255
|
}
|
|
55256
55256
|
}),
|
|
55257
55257
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -55261,7 +55261,7 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
55261
55261
|
]
|
|
55262
55262
|
}), /* @__PURE__ */ jsxs("div", {
|
|
55263
55263
|
className: "flex justify-between text-[11px] tabular-nums text-foreground-subtle",
|
|
55264
|
-
children: [/* @__PURE__ */ jsx("span", { children: formatClock(display.
|
|
55264
|
+
children: [/* @__PURE__ */ jsx("span", { children: formatClock(display.position) }), /* @__PURE__ */ jsx("span", { children: formatClock(display.duration) })]
|
|
55265
55265
|
})]
|
|
55266
55266
|
}),
|
|
55267
55267
|
/* @__PURE__ */ jsxs("div", {
|