@camstack/ui-library 1.2.320 → 1.2.322

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/index.cjs CHANGED
@@ -12229,6 +12229,8 @@ var useRecordingOnboardSetSettings = trpc.recordingOnboard.setSettings.useMutati
12229
12229
  var useRecordingOnboardGetStatus = trpc.recordingOnboard.getStatus.useQuery;
12230
12230
  /** Generated alias around `trpc.recordingSignal.getStatus.useQuery`. */
12231
12231
  var useRecordingSignalGetStatus = trpc.recordingSignal.getStatus.useQuery;
12232
+ /** Generated alias around `trpc.runningState.getStatus.useQuery`. */
12233
+ var useRunningStateGetStatus = trpc.runningState.getStatus.useQuery;
12232
12234
  /** Generated alias around `trpc.sceneMonitor.listScenes.useQuery`. */
12233
12235
  var useSceneMonitorListScenes = trpc.sceneMonitor.listScenes.useQuery;
12234
12236
  /** Generated alias around `trpc.sceneMonitor.listScenesBatch.useQuery`. */
@@ -13026,7 +13028,7 @@ function selectedDeviceOptions(options, selected) {
13026
13028
  * select. Both are inline in ui-library (like `node-select`) so any host that
13027
13029
  * renders the shared form field gets them without extra registration.
13028
13030
  */
13029
- var INPUT_CLASS$1 = "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none disabled:opacity-50 disabled:cursor-not-allowed";
13031
+ var INPUT_CLASS$2 = "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none disabled:opacity-50 disabled:cursor-not-allowed";
13030
13032
  var INPUT_SHELL$1 = "flex items-center gap-1.5 rounded-md border border-border bg-background px-2 py-1.5 focus-within:border-primary focus-within:ring-1 focus-within:ring-primary/30";
13031
13033
  var LABEL_CLASS$3 = "block text-[11px] font-medium text-foreground mb-1 break-words";
13032
13034
  var DESC_CLASS$2 = "text-[10px] text-foreground-subtle mt-0.5 break-words";
@@ -13156,7 +13158,7 @@ function DeviceSelectField({ field, value, onChange, disabled, translationFn })
13156
13158
  required: field.required,
13157
13159
  translationFn,
13158
13160
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
13159
- className: INPUT_CLASS$1,
13161
+ className: INPUT_CLASS$2,
13160
13162
  value: current,
13161
13163
  disabled: disabled || field.disabled,
13162
13164
  onChange: (e) => onChange(e.target.value),
@@ -14382,6 +14384,282 @@ function useCustomFieldRenderer(type) {
14382
14384
  return (0, react$1.useContext)(CustomFieldRenderersContext)[type] ?? null;
14383
14385
  }
14384
14386
  //#endregion
14387
+ //#region src/primitives/button.tsx
14388
+ var buttonVariants = cva("inline-flex items-center justify-center rounded-md font-medium transition-colors cursor-pointer disabled:opacity-50 disabled:pointer-events-none", {
14389
+ variants: {
14390
+ variant: {
14391
+ primary: "bg-primary text-primary-foreground hover:bg-primary/90",
14392
+ secondary: "bg-surface text-foreground hover:bg-surface-hover",
14393
+ ghost: "hover:bg-surface-hover text-foreground-muted",
14394
+ danger: "bg-danger text-white hover:bg-danger/90",
14395
+ outline: "border border-border bg-transparent text-foreground hover:bg-surface-hover"
14396
+ },
14397
+ size: {
14398
+ sm: "h-7 px-2.5 text-xs gap-1.5",
14399
+ md: "h-8 px-3 text-sm gap-2",
14400
+ lg: "h-9 px-4 text-sm gap-2"
14401
+ }
14402
+ },
14403
+ defaultVariants: {
14404
+ variant: "primary",
14405
+ size: "sm"
14406
+ }
14407
+ });
14408
+ var Button = (0, react$1.forwardRef)(({ className, variant, size, ...props }, ref) => {
14409
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
14410
+ ref,
14411
+ className: cn(buttonVariants({
14412
+ variant,
14413
+ size
14414
+ }), className),
14415
+ ...props
14416
+ });
14417
+ });
14418
+ Button.displayName = "Button";
14419
+ //#endregion
14420
+ //#region src/composites/account-sign-in-field.tsx
14421
+ var INPUT_CLASS$1 = "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none disabled:opacity-50 disabled:cursor-not-allowed";
14422
+ var BARE_CODE = /^[A-Za-z0-9._~-]{8,}$/;
14423
+ function isRecord$3(value) {
14424
+ return typeof value === "object" && value !== null && !Array.isArray(value);
14425
+ }
14426
+ function isPresent(value) {
14427
+ if (typeof value === "string") return value.trim().length > 0;
14428
+ if ((0, _camstack_types.isSecretFieldView)(value) || (0, _camstack_types.isSecretMarker)(value)) return true;
14429
+ return false;
14430
+ }
14431
+ function accountText(value) {
14432
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : "";
14433
+ }
14434
+ function countFromValue(value) {
14435
+ if (typeof value === "number" && Number.isFinite(value)) return value;
14436
+ if (Array.isArray(value)) return value.length;
14437
+ if (typeof value === "string" && value.trim().startsWith("[")) try {
14438
+ const parsed = JSON.parse(value);
14439
+ if (Array.isArray(parsed)) return parsed.length;
14440
+ } catch {
14441
+ return null;
14442
+ }
14443
+ return null;
14444
+ }
14445
+ function nounFor(count, noun) {
14446
+ return count === 1 ? noun : `${noun}s`;
14447
+ }
14448
+ function choicesOf(value) {
14449
+ if (!Array.isArray(value)) return [];
14450
+ const out = [];
14451
+ for (const row of value) {
14452
+ if (!isRecord$3(row) || typeof row["value"] !== "string" || typeof row["label"] !== "string") continue;
14453
+ out.push({
14454
+ value: row["value"],
14455
+ label: row["label"],
14456
+ ...typeof row["brand"] === "string" ? { brand: row["brand"] } : {},
14457
+ ...typeof row["region"] === "string" ? { region: row["region"] } : {}
14458
+ });
14459
+ }
14460
+ return out;
14461
+ }
14462
+ function selectedChoice(value) {
14463
+ return typeof value === "string" ? value : "";
14464
+ }
14465
+ function shouldComplete(text) {
14466
+ const trimmed = text.trim();
14467
+ if (trimmed.length === 0) return false;
14468
+ if (trimmed.includes("code=") || trimmed.includes("://") || trimmed.includes("error=")) return true;
14469
+ return BARE_CODE.test(trimmed);
14470
+ }
14471
+ function AccountSignInField({ field, values, disabled, onAction, onChangeMany }) {
14472
+ const t = useUiText();
14473
+ const [phase, setPhase] = (0, react$1.useState)("idle");
14474
+ const [attemptId, setAttemptId] = (0, react$1.useState)(null);
14475
+ const [authorizeUrl, setAuthorizeUrl] = (0, react$1.useState)(null);
14476
+ const [paste, setPaste] = (0, react$1.useState)("");
14477
+ const [error, setError] = (0, react$1.useState)(null);
14478
+ const [working, setWorking] = (0, react$1.useState)(false);
14479
+ const [choices, setChoices] = (0, react$1.useState)([]);
14480
+ const inFlight = (0, react$1.useRef)(false);
14481
+ const account = accountText(values[field.accountKey]);
14482
+ const tokenPresent = field.secretKeys.some((key) => isPresent(values[key]));
14483
+ const signedIn = account.length > 0 || tokenPresent;
14484
+ const count = (field.countKey !== void 0 ? countFromValue(values[field.countKey]) : null) ?? (field.countFromKey !== void 0 ? countFromValue(values[field.countFromKey]) : null);
14485
+ const showPaste = phase === "pasting" || !signedIn && attemptId !== null;
14486
+ const applyResult = (result) => {
14487
+ const patch = {};
14488
+ for (const [formKey, resultKey] of Object.entries(field.assignResult ?? {})) {
14489
+ const assigned = result[resultKey];
14490
+ if (typeof assigned === "string" || typeof assigned === "number") patch[formKey] = assigned;
14491
+ }
14492
+ if (Object.keys(patch).length > 0) onChangeMany?.(patch);
14493
+ const nextChoices = choicesOf(result["choices"]);
14494
+ setChoices(nextChoices.length > 1 ? nextChoices : []);
14495
+ setPhase("idle");
14496
+ setPaste("");
14497
+ setAttemptId(null);
14498
+ setAuthorizeUrl(null);
14499
+ };
14500
+ const begin = async () => {
14501
+ if (!onAction || working) return;
14502
+ setWorking(true);
14503
+ setError(null);
14504
+ try {
14505
+ const result = await onAction(field.beginAction, field.key, {});
14506
+ if (!isRecord$3(result) || typeof result["authorizeUrl"] !== "string" || typeof result["attemptId"] !== "string") {
14507
+ setError(t("uiLibrary.accountSignIn.noLink", "The sign-in page could not be opened. Try again."));
14508
+ return;
14509
+ }
14510
+ if ("verifier" in result || "state" in result) {
14511
+ setError(t("uiLibrary.accountSignIn.noLink", "The sign-in page could not be opened. Try again."));
14512
+ return;
14513
+ }
14514
+ setAttemptId(result["attemptId"]);
14515
+ setAuthorizeUrl(result["authorizeUrl"]);
14516
+ setPhase("pasting");
14517
+ window.open(result["authorizeUrl"], "_blank", "noopener,noreferrer");
14518
+ } catch (err) {
14519
+ setError(err instanceof Error ? err.message : String(err));
14520
+ } finally {
14521
+ setWorking(false);
14522
+ }
14523
+ };
14524
+ const complete = async (callback) => {
14525
+ if (!onAction || attemptId === null || inFlight.current) return;
14526
+ inFlight.current = true;
14527
+ setWorking(true);
14528
+ setError(null);
14529
+ try {
14530
+ const result = await onAction(field.completeAction, field.key, {
14531
+ attemptId,
14532
+ callback
14533
+ });
14534
+ if (!isRecord$3(result)) {
14535
+ setError(t("uiLibrary.accountSignIn.rejected", "The sign-in was not accepted. Start again."));
14536
+ return;
14537
+ }
14538
+ applyResult(result);
14539
+ } catch (err) {
14540
+ setError(err instanceof Error ? err.message : String(err));
14541
+ } finally {
14542
+ inFlight.current = false;
14543
+ setWorking(false);
14544
+ }
14545
+ };
14546
+ const signOut = async () => {
14547
+ if (!onAction || working) return;
14548
+ setWorking(true);
14549
+ setError(null);
14550
+ try {
14551
+ await onAction(field.signOutAction, field.key, {});
14552
+ const patch = { [field.accountKey]: "" };
14553
+ if (field.countKey !== void 0) patch[field.countKey] = 0;
14554
+ if (field.choiceKey !== void 0) patch[field.choiceKey] = "";
14555
+ if (field.countFromKey !== void 0) patch[field.countFromKey] = [];
14556
+ for (const key of field.secretKeys) patch[key] = _camstack_types.SECRET_CLEAR;
14557
+ onChangeMany?.(patch);
14558
+ setChoices([]);
14559
+ setPhase("idle");
14560
+ setAttemptId(null);
14561
+ setPaste("");
14562
+ } catch (err) {
14563
+ setError(err instanceof Error ? err.message : String(err));
14564
+ } finally {
14565
+ setWorking(false);
14566
+ }
14567
+ };
14568
+ const pick = (value) => {
14569
+ const chosen = choices.find((row) => row.value === value);
14570
+ if (chosen === void 0 || field.choiceKey === void 0) return;
14571
+ const patch = { [field.choiceKey]: chosen.value };
14572
+ if (chosen.brand !== void 0) patch["brand"] = chosen.brand;
14573
+ if (chosen.region !== void 0) patch["region"] = chosen.region;
14574
+ onChangeMany?.(patch);
14575
+ };
14576
+ const statusAccount = account.length > 0 ? account : t("uiLibrary.accountSignIn.yourAccount", "your account");
14577
+ const status = count === null ? t("uiLibrary.accountSignIn.signedIn", "Signed in as {{account}}", { account: statusAccount }) : t("uiLibrary.accountSignIn.signedInCount", "Signed in as {{account}} · {{detail}}", {
14578
+ account: statusAccount,
14579
+ detail: field.countNoun !== void 0 ? `${count} ${nounFor(count, field.countNoun)}` : String(count)
14580
+ });
14581
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14582
+ className: "col-span-1 flex min-w-0 flex-col gap-2",
14583
+ children: [
14584
+ signedIn && phase === "idle" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14585
+ className: "flex flex-col gap-2",
14586
+ children: [
14587
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
14588
+ className: "text-xs text-foreground",
14589
+ children: status
14590
+ }),
14591
+ choices.length > 1 && field.choiceKey !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Select, {
14592
+ "aria-label": field.choiceLabel ?? t("uiLibrary.accountSignIn.choose", "Choose"),
14593
+ options: choices.map((row) => ({
14594
+ value: row.value,
14595
+ label: row.label
14596
+ })),
14597
+ value: selectedChoice(values[field.choiceKey]),
14598
+ onChange: (event) => pick(event.target.value),
14599
+ disabled: disabled || working
14600
+ }),
14601
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14602
+ className: "flex flex-wrap gap-2",
14603
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
14604
+ type: "button",
14605
+ variant: "outline",
14606
+ size: "sm",
14607
+ disabled: disabled || working,
14608
+ onClick: () => void begin(),
14609
+ children: t("uiLibrary.accountSignIn.again", "Sign in again")
14610
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
14611
+ type: "button",
14612
+ variant: "ghost",
14613
+ size: "sm",
14614
+ disabled: disabled || working,
14615
+ onClick: () => void signOut(),
14616
+ children: t("uiLibrary.accountSignIn.signOut", "Sign out")
14617
+ })]
14618
+ })
14619
+ ]
14620
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
14621
+ type: "button",
14622
+ variant: "primary",
14623
+ size: "sm",
14624
+ disabled: disabled || working,
14625
+ onClick: () => void begin(),
14626
+ children: working && phase !== "pasting" ? t("uiLibrary.accountSignIn.working", "Working…") : t("uiLibrary.accountSignIn.signInWith", "Sign in with {{provider}}", { provider: field.providerLabel })
14627
+ }),
14628
+ showPaste && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14629
+ className: "flex flex-col gap-1.5",
14630
+ children: [authorizeUrl !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
14631
+ className: "text-[11px] text-primary break-all",
14632
+ href: authorizeUrl,
14633
+ target: "_blank",
14634
+ rel: "noopener noreferrer",
14635
+ children: t("uiLibrary.accountSignIn.open", "Open the sign-in page")
14636
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
14637
+ className: `${INPUT_CLASS$1} min-h-[60px] resize-y`,
14638
+ "aria-label": t("uiLibrary.accountSignIn.paste", "Redirect address or code"),
14639
+ placeholder: field.pastePlaceholder,
14640
+ value: paste,
14641
+ disabled: disabled || working,
14642
+ onChange: (event) => {
14643
+ const next = event.target.value;
14644
+ setPaste(next);
14645
+ if (shouldComplete(next)) complete(next);
14646
+ }
14647
+ })]
14648
+ }),
14649
+ error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
14650
+ className: "text-[11px] text-danger",
14651
+ children: error
14652
+ })
14653
+ ]
14654
+ });
14655
+ }
14656
+ function SecretPresenceField({ field, values }) {
14657
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
14658
+ className: "col-span-1 text-xs text-foreground",
14659
+ children: isPresent(values[field.sourceKey]) ? field.yesLabel : field.noLabel
14660
+ });
14661
+ }
14662
+ //#endregion
14385
14663
  //#region src/composites/confirm-dialog.tsx
14386
14664
  /**
14387
14665
  * The ONE modal dialog of the product — confirm, alert and prompt.
@@ -20685,39 +20963,6 @@ var Skeleton = (0, react$1.forwardRef)(({ className, ...props }, ref) => {
20685
20963
  });
20686
20964
  Skeleton.displayName = "Skeleton";
20687
20965
  //#endregion
20688
- //#region src/primitives/button.tsx
20689
- var buttonVariants = cva("inline-flex items-center justify-center rounded-md font-medium transition-colors cursor-pointer disabled:opacity-50 disabled:pointer-events-none", {
20690
- variants: {
20691
- variant: {
20692
- primary: "bg-primary text-primary-foreground hover:bg-primary/90",
20693
- secondary: "bg-surface text-foreground hover:bg-surface-hover",
20694
- ghost: "hover:bg-surface-hover text-foreground-muted",
20695
- danger: "bg-danger text-white hover:bg-danger/90",
20696
- outline: "border border-border bg-transparent text-foreground hover:bg-surface-hover"
20697
- },
20698
- size: {
20699
- sm: "h-7 px-2.5 text-xs gap-1.5",
20700
- md: "h-8 px-3 text-sm gap-2",
20701
- lg: "h-9 px-4 text-sm gap-2"
20702
- }
20703
- },
20704
- defaultVariants: {
20705
- variant: "primary",
20706
- size: "sm"
20707
- }
20708
- });
20709
- var Button = (0, react$1.forwardRef)(({ className, variant, size, ...props }, ref) => {
20710
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
20711
- ref,
20712
- className: cn(buttonVariants({
20713
- variant,
20714
- size
20715
- }), className),
20716
- ...props
20717
- });
20718
- });
20719
- Button.displayName = "Button";
20720
- //#endregion
20721
20966
  //#region src/composites/cap-settings/consumable-rows.tsx
20722
20967
  /** `value` null = unknown (D393) — renders an em-dash, never a fake `0`. */
20723
20968
  function formatRemaining(t, r) {
@@ -29962,7 +30207,7 @@ function ProbeField({ field, value, onChange, disabled, translationFn, onTestFie
29962
30207
  ]
29963
30208
  });
29964
30209
  }
29965
- function GroupField({ field, values, onChange, disabled, translationFn, onTestField }) {
30210
+ function GroupField({ field, values, onChange, onChangeMany, disabled, translationFn, onTestField, onAction }) {
29966
30211
  const [collapsed, setCollapsed] = (0, react$1.useState)(field.defaultCollapsed ?? false);
29967
30212
  const isAccordion = field.style === "accordion";
29968
30213
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -29986,9 +30231,11 @@ function GroupField({ field, values, onChange, disabled, translationFn, onTestFi
29986
30231
  field: subField,
29987
30232
  values,
29988
30233
  onChange,
30234
+ onChangeMany,
29989
30235
  disabled,
29990
30236
  translationFn,
29991
- onTestField
30237
+ onTestField,
30238
+ onAction
29992
30239
  }, subField.key))
29993
30240
  })]
29994
30241
  })
@@ -30404,6 +30651,10 @@ function AddonActionSelectField({ field, value, values, onChange, disabled, onAc
30404
30651
  }
30405
30652
  }
30406
30653
  setOptions(list);
30654
+ if (field.hideWhenFewerThan !== void 0 && list.length === 1 && (typeof value !== "string" || value.length === 0)) {
30655
+ const only = list[0]?.[valueKey];
30656
+ if (typeof only === "string" && only.length > 0) onChange(only);
30657
+ }
30407
30658
  }).catch((err) => {
30408
30659
  if (cancelled) return;
30409
30660
  setError(err instanceof Error ? err.message : String(err));
@@ -30423,6 +30674,8 @@ function AddonActionSelectField({ field, value, values, onChange, disabled, onAc
30423
30674
  const valueKey = field.mapOption.value;
30424
30675
  const labelKey = field.mapOption.label;
30425
30676
  const descKey = field.mapOption.description;
30677
+ if (!onAction && field.hideWhenFewerThan !== void 0) return null;
30678
+ if (field.hideWhenFewerThan !== void 0 && options !== null && options.length < field.hideWhenFewerThan) return null;
30426
30679
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldWrapper, {
30427
30680
  label: field.label,
30428
30681
  description: field.description,
@@ -31055,9 +31308,11 @@ function FormField({ field, values, onChange, onChangeMany, disabled, translatio
31055
31308
  field,
31056
31309
  values,
31057
31310
  onChange,
31311
+ onChangeMany,
31058
31312
  disabled,
31059
31313
  translationFn,
31060
- onTestField
31314
+ onTestField,
31315
+ onAction
31061
31316
  });
31062
31317
  case "sub-tabs": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SubTabsField, {
31063
31318
  field,
@@ -31086,22 +31341,36 @@ function FormField({ field, values, onChange, onChangeMany, disabled, translatio
31086
31341
  disabled,
31087
31342
  onAction
31088
31343
  });
31089
- case "addon-action-select": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AddonActionSelectField, {
31344
+ case "addon-action-select": {
31345
+ const storedKey = field.writesKey ?? field.key;
31346
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AddonActionSelectField, {
31347
+ field,
31348
+ value: values[storedKey],
31349
+ values,
31350
+ onChange: (next) => onChange(storedKey, next),
31351
+ disabled,
31352
+ onAction
31353
+ });
31354
+ }
31355
+ case "addon-action-button": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AddonActionButtonField, {
31090
31356
  field,
31091
- value,
31092
31357
  values,
31093
- onChange: handleChange,
31094
31358
  disabled,
31095
- onAction
31359
+ onAction,
31360
+ onChange,
31361
+ onChangeMany
31096
31362
  });
31097
- case "addon-action-button": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AddonActionButtonField, {
31363
+ case "account-sign-in": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountSignInField, {
31098
31364
  field,
31099
31365
  values,
31100
31366
  disabled,
31101
31367
  onAction,
31102
- onChange,
31103
31368
  onChangeMany
31104
31369
  });
31370
+ case "secret-presence": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretPresenceField, {
31371
+ field,
31372
+ values
31373
+ });
31105
31374
  case "device-action-button": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceActionButtonField, {
31106
31375
  field,
31107
31376
  values,
@@ -33644,6 +33913,99 @@ function BatteryBadge({ status, variant = "compact", className }) {
33644
33913
  });
33645
33914
  }
33646
33915
  //#endregion
33916
+ //#region src/composites/running-status.ts
33917
+ function trimmedPhase(phase) {
33918
+ if (phase === null) return void 0;
33919
+ const trimmed = phase.trim();
33920
+ return trimmed === "" ? void 0 : trimmed;
33921
+ }
33922
+ /** Minutes elapsed since `since`, at least 1; null when `since` is not usable. */
33923
+ function runningDurationSince(since, now) {
33924
+ if (since === null || !Number.isFinite(since) || since <= 0) return null;
33925
+ const ms = now - since;
33926
+ if (ms <= 0) return null;
33927
+ const totalMinutes = Math.floor(ms / 6e4);
33928
+ if (totalMinutes < 60) return { minutes: Math.max(1, totalMinutes) };
33929
+ return { hours: Math.floor(totalMinutes / 60) };
33930
+ }
33931
+ function runningStatusParts(running, since, phase, now) {
33932
+ const phaseLabel = trimmedPhase(phase);
33933
+ if (running === null) return { key: "unknown" };
33934
+ if (running === false) return phaseLabel === void 0 ? { key: "idle" } : {
33935
+ key: "idle",
33936
+ phase: phaseLabel
33937
+ };
33938
+ const duration = runningDurationSince(since, now);
33939
+ if (duration === null) return phaseLabel === void 0 ? { key: "running" } : {
33940
+ key: "running",
33941
+ phase: phaseLabel
33942
+ };
33943
+ return {
33944
+ key: "running",
33945
+ duration,
33946
+ ...phaseLabel === void 0 ? {} : { phase: phaseLabel }
33947
+ };
33948
+ }
33949
+ //#endregion
33950
+ //#region src/composites/running-badge.tsx
33951
+ function RunningBadge({ running, children, className }) {
33952
+ const t = useUiText();
33953
+ if (running === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
33954
+ "data-running": "unknown",
33955
+ className: cn("inline-flex shrink-0", className),
33956
+ children
33957
+ });
33958
+ if (running === true) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
33959
+ "data-running": "running",
33960
+ className: cn("relative inline-flex shrink-0 rounded-full p-0.5", className),
33961
+ "aria-label": t("uiLibrary.runningBadge.running", "Running"),
33962
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
33963
+ className: "pointer-events-none absolute inset-0 rounded-full border border-primary animate-pulse",
33964
+ "aria-hidden": true
33965
+ }), children]
33966
+ });
33967
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
33968
+ "data-running": "idle",
33969
+ className: cn("relative inline-flex shrink-0", className),
33970
+ "aria-label": t("uiLibrary.runningBadge.idle", "Idle"),
33971
+ children: [children, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
33972
+ className: "pointer-events-none absolute -bottom-px -right-px h-1.5 w-1.5 rounded-full bg-foreground-subtle",
33973
+ "aria-hidden": true
33974
+ })]
33975
+ });
33976
+ }
33977
+ function RunningStatusLine({ running, since, phase, className, now = Date.now() }) {
33978
+ const t = useUiText();
33979
+ const parts = runningStatusParts(running, since, phase, now);
33980
+ if (parts.key === "unknown") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
33981
+ className: cn("text-[11px] text-foreground-subtle", className),
33982
+ children: t("uiLibrary.runningStatus.unknown", "Unknown")
33983
+ });
33984
+ if (parts.key === "idle") {
33985
+ const base = t("uiLibrary.runningStatus.idle", "Idle");
33986
+ const text = parts.phase === void 0 ? base : t("uiLibrary.runningStatus.withPhase", "{{state}} · {{phase}}", {
33987
+ state: base,
33988
+ phase: parts.phase
33989
+ });
33990
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
33991
+ className: cn("text-[11px] text-foreground-muted", className),
33992
+ children: text
33993
+ });
33994
+ }
33995
+ let base;
33996
+ if (parts.duration === void 0) base = t("uiLibrary.runningStatus.running", "Running");
33997
+ else if ("minutes" in parts.duration) base = t("uiLibrary.runningStatus.runningForMinutes", "Running for {{count}} min", { count: parts.duration.minutes });
33998
+ else base = t("uiLibrary.runningStatus.runningForHours", "Running for {{count}} h", { count: parts.duration.hours });
33999
+ const text = parts.phase === void 0 ? base : t("uiLibrary.runningStatus.withPhase", "{{state}} · {{phase}}", {
34000
+ state: base,
34001
+ phase: parts.phase
34002
+ });
34003
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
34004
+ className: cn("text-[11px] text-foreground-muted", className),
34005
+ children: text
34006
+ });
34007
+ }
34008
+ //#endregion
33647
34009
  //#region src/composites/network-link-badge.tsx
33648
34010
  /**
33649
34011
  * NetworkLinkBadge — compact link indicator for device rows and headers.
@@ -50584,6 +50946,18 @@ function dishwasherHeadline(status, t = defaultUiText) {
50584
50946
  function featureLabel(key) {
50585
50947
  return (key.split(".").pop() ?? key).replace(/([a-z0-9])([A-Z])/g, "$1 $2");
50586
50948
  }
50949
+ /**
50950
+ * Salt and rinse aid are consumable items (D915). Their events must not
50951
+ * reappear on the hero — the Consumables section is the only surface.
50952
+ */
50953
+ function isConsumableDishwasherEvent(event) {
50954
+ const short = (event.split(".").pop() ?? event).toLowerCase();
50955
+ return short.includes("salt") || short.includes("rinse");
50956
+ }
50957
+ /** Raised events the hero may name. Consumable events are dropped. */
50958
+ function visibleDishwasherEvents(events) {
50959
+ return events.filter((event) => !isConsumableDishwasherEvent(event));
50960
+ }
50587
50961
  /** Whole seconds as a short duration: `1 h 24 min`, `42 min`, `30 s`. */
50588
50962
  function formatDuration(seconds, t = defaultUiText) {
50589
50963
  if (seconds < 60) return t("uiLibrary.dishwasher.durationSeconds", "{{n}} s", { n: seconds });
@@ -50740,7 +51114,7 @@ function DishwasherPanel({ trpc, deviceId, layout }) {
50740
51114
  children: [display.doorOpen === true && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
50741
51115
  className: "inline-flex items-center gap-1 text-xs text-warning",
50742
51116
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DoorOpen, { className: "h-3.5 w-3.5" }), t("uiLibrary.dishwasher.doorOpen", "Door open")]
50743
- }), display.activeEvents.map((event) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
51117
+ }), visibleDishwasherEvents(display.activeEvents).map((event) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
50744
51118
  className: "text-xs text-warning",
50745
51119
  title: event,
50746
51120
  children: featureLabel(event)
@@ -55230,6 +55604,8 @@ function ChildRow$1({ trpc, child, onNavigate, parentName }) {
55230
55604
  const showMotionTrigger = enabled && hasMotionTriggerFeature(child);
55231
55605
  const roleDefaults = useRoleDisplayDefaults();
55232
55606
  useIconGlyphsVersion();
55607
+ const ChildIcon = deviceLeadIcon(child, roleDefaults);
55608
+ const runningSlice = useDeviceState(trpc, child.id, (s) => s.runningState);
55233
55609
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
55234
55610
  onClick: (e) => {
55235
55611
  e.stopPropagation();
@@ -55237,7 +55613,10 @@ function ChildRow$1({ trpc, child, onNavigate, parentName }) {
55237
55613
  },
55238
55614
  className: "w-full flex items-center gap-2 px-3 py-1.5 text-left hover:bg-surface-hover transition-colors cursor-pointer",
55239
55615
  children: [
55240
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(deviceLeadIcon(child, roleDefaults), { className: "h-3 w-3 text-foreground-subtle flex-shrink-0" }),
55616
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RunningBadge, {
55617
+ running: runningSlice === void 0 || runningSlice.running === null ? null : runningSlice.running,
55618
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChildIcon, { className: "h-3 w-3 text-foreground-subtle flex-shrink-0" })
55619
+ }),
55241
55620
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
55242
55621
  className: "text-[10.5px] text-foreground flex-1 truncate",
55243
55622
  children: childListName(child, parentName)
@@ -55631,13 +56010,16 @@ var CHEVRON_SLOT_CLASS = {
55631
56010
  horizontal: "h-3.5 w-3.5",
55632
56011
  stacked: "h-4 w-4 mt-0.5"
55633
56012
  };
55634
- function DeviceItemHeader({ device, variant, flags, parent, integrationIcon, hasChildren, expanded, onToggleExpand, onNavigateToParent, stacked = false, nameOverflow = "truncate" }) {
56013
+ function DeviceItemHeader({ trpc, device, variant, flags, parent, integrationIcon, hasChildren, expanded, onToggleExpand, onNavigateToParent, stacked = false, nameOverflow = "truncate" }) {
55635
56014
  const t = useUiText();
55636
56015
  const containerChildren = useContainerChildren(device.id);
55637
56016
  const roleDefaults = useRoleDisplayDefaults();
55638
56017
  useIconGlyphsVersion();
55639
56018
  const Icon = deviceLeadIcon(effectiveIconDevice(device, containerChildren), roleDefaults);
56019
+ const runningSlice = useDeviceState(trpc, device.id, (s) => s.runningState);
56020
+ const runningBadge = runningSlice === void 0 || runningSlice.running === null ? null : runningSlice.running;
55640
56021
  const slotClass = stacked ? CHEVRON_SLOT_CLASS.stacked : CHEVRON_SLOT_CLASS.horizontal;
56022
+ const iconClass = cn("text-foreground-subtle flex-shrink-0", stacked ? "h-4 w-4 mt-0.5" : variant === "minimal" ? "h-3 w-3" : "h-3.5 w-3.5");
55641
56023
  const lineClass = nameOverflow === "scroll" ? NAME_TEXT_CLASS : "truncate";
55642
56024
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
55643
56025
  className: cn(stacked ? "flex items-start gap-2 w-full min-w-0" : "flex items-center gap-2 flex-1 min-w-0"),
@@ -55657,7 +56039,10 @@ function DeviceItemHeader({ device, variant, flags, parent, integrationIcon, has
55657
56039
  "data-testid": "chevron-slot",
55658
56040
  className: cn("flex-shrink-0", slotClass)
55659
56041
  }) : null,
55660
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { className: cn("text-foreground-subtle flex-shrink-0", stacked ? "h-4 w-4 mt-0.5" : variant === "minimal" ? "h-3 w-3" : "h-3.5 w-3.5") }),
56042
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RunningBadge, {
56043
+ running: runningBadge,
56044
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { className: iconClass })
56045
+ }),
55661
56046
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
55662
56047
  className: "flex-1 min-w-0",
55663
56048
  children: [
@@ -56151,6 +56536,7 @@ function DeviceItem(props) {
56151
56536
  className: "flex-shrink-0"
56152
56537
  }),
56153
56538
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceItemHeader, {
56539
+ trpc,
56154
56540
  device,
56155
56541
  variant,
56156
56542
  flags,
@@ -56227,6 +56613,7 @@ function DeviceItem(props) {
56227
56613
  className: "flex-shrink-0 mt-0.5"
56228
56614
  }),
56229
56615
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceItemHeader, {
56616
+ trpc,
56230
56617
  device,
56231
56618
  variant,
56232
56619
  flags,
@@ -56318,6 +56705,7 @@ function DeviceItemTableRow(props) {
56318
56705
  "aria-label": t("uiLibrary.deviceItem.select", "Select {{name}}", { name: device.name }),
56319
56706
  className: "flex-shrink-0"
56320
56707
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceItemHeader, {
56708
+ trpc,
56321
56709
  device,
56322
56710
  variant,
56323
56711
  flags,
@@ -64939,7 +65327,7 @@ function noItemsSentence(noun, emptyMeansAll, t) {
64939
65327
  noun: pickerNounLabel(noun, t)
64940
65328
  });
64941
65329
  }
64942
- function DevicePicker({ devices: devicesIn, listState, fleet, value, onChange, emptyMeansAll = false, savedHadDevices = false, noun = "camera", groupTitle: groupTitleProp, emptyLabel, annotate, disabled = false, testId, showAll = false, lockedIds, lockedNote: lockedNoteProp }) {
65330
+ function DevicePicker({ devices: devicesIn, listState, fleet, value, onChange, selection = "multiple", groupBy: pinnedGroupBy, emptyMeansAll = false, savedHadDevices = false, noun = "camera", groupTitle: groupTitleProp, emptyLabel, annotate, disabled = false, testId, showAll = false, lockedIds, lockedNote: lockedNoteProp }) {
64943
65331
  const t = useUiText();
64944
65332
  const groupTitle = groupTitleProp ?? ((group) => deviceGroupTitle(group, t));
64945
65333
  const lockedNote = lockedNoteProp ?? t("uiLibrary.devicePicker.alreadyAdded", "Already added");
@@ -64972,7 +65360,7 @@ function DevicePicker({ devices: devicesIn, listState, fleet, value, onChange, e
64972
65360
  children: [
64973
65361
  listState === "pending" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DevicesLoadingLine, { noun: plural }),
64974
65362
  listState === "failed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DevicesFailedLine, { noun: noun === "camera" ? "devices" : plural }),
64975
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
65363
+ !(selection === "single" && chips.length === 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
64976
65364
  className: "flex flex-wrap items-center gap-1",
64977
65365
  children: [
64978
65366
  chips.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -65016,7 +65404,9 @@ function DevicePicker({ devices: devicesIn, listState, fleet, value, onChange, e
65016
65404
  groupTitle,
65017
65405
  noun,
65018
65406
  disabled,
65019
- showAll
65407
+ showAll,
65408
+ selection,
65409
+ ...pinnedGroupBy !== void 0 ? { pinnedGroupBy } : {}
65020
65410
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PickerPanel, {
65021
65411
  devices,
65022
65412
  value,
@@ -65027,7 +65417,8 @@ function DevicePicker({ devices: devicesIn, listState, fleet, value, onChange, e
65027
65417
  groupTitle,
65028
65418
  noun,
65029
65419
  disabled,
65030
- showAll
65420
+ showAll,
65421
+ selection
65031
65422
  })),
65032
65423
  widening && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DevicesWidenWarning, { noun })
65033
65424
  ]
@@ -65038,13 +65429,23 @@ function DevicePicker({ devices: devicesIn, listState, fleet, value, onChange, e
65038
65429
  * read below happens only then (for Zone grouping and the Zone filter).
65039
65430
  */
65040
65431
  function GroupedPickerPanel(props) {
65041
- const { groupBy, setGroupBy } = useStoredGroupBy();
65432
+ const stored = useStoredGroupBy();
65433
+ const [localGroupBy, setLocalGroupBy] = (0, react$1.useState)(null);
65434
+ const pinned = props.pinnedGroupBy;
65435
+ const groupBy = pinned !== void 0 ? localGroupBy ?? pinned : stored.groupBy;
65436
+ const onGroupByChange = (next) => {
65437
+ if (pinned !== void 0) {
65438
+ setLocalGroupBy(next);
65439
+ return;
65440
+ }
65441
+ stored.setGroupBy(next);
65442
+ };
65042
65443
  const zones = usePickerSiteZones(true);
65043
65444
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PickerPanel, {
65044
65445
  ...props,
65045
65446
  grouping: {
65046
65447
  groupBy,
65047
- onGroupByChange: setGroupBy,
65448
+ onGroupByChange,
65048
65449
  zones
65049
65450
  }
65050
65451
  });
@@ -65062,8 +65463,9 @@ var NO_ZONES = {
65062
65463
  zones: []
65063
65464
  };
65064
65465
  /** The searchable, grouped list — rendered one page at a time. */
65065
- function PickerPanel({ devices, value, onChange, annotate, groupTitle, noun, disabled, locked, lockedNote, showAll, grouping }) {
65466
+ function PickerPanel({ devices, value, onChange, annotate, groupTitle, noun, disabled, locked, lockedNote, showAll, selection, grouping }) {
65066
65467
  const t = useUiText();
65468
+ const radioName = (0, react$1.useId)();
65067
65469
  const [filters, setFilters] = (0, react$1.useState)(PICKER_NO_FILTERS);
65068
65470
  const [toggles, setToggles] = (0, react$1.useState)(/* @__PURE__ */ new Map());
65069
65471
  const [shown, setShown] = (0, react$1.useState)(60);
@@ -65137,7 +65539,10 @@ function PickerPanel({ devices, value, onChange, annotate, groupTitle, noun, dis
65137
65539
  }),
65138
65540
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
65139
65541
  className: "mt-1 text-[10px] text-foreground-subtle",
65140
- children: t("uiLibrary.devicePicker.shownOf", "{{shown}} of {{total}} shown · {{selected}} selected", {
65542
+ children: selection === "single" ? t("uiLibrary.devicePicker.shownOfSingle", "{{shown}} of {{total}} shown", {
65543
+ shown: matches.length,
65544
+ total: devices.length
65545
+ }) : t("uiLibrary.devicePicker.shownOf", "{{shown}} of {{total}} shown · {{selected}} selected", {
65141
65546
  shown: matches.length,
65142
65547
  total: devices.length,
65143
65548
  selected: value.length
@@ -65159,7 +65564,9 @@ function PickerPanel({ devices, value, onChange, annotate, groupTitle, noun, dis
65159
65564
  groupBy: shownBy,
65160
65565
  disabled,
65161
65566
  locked,
65162
- lockedNote
65567
+ lockedNote,
65568
+ selection,
65569
+ radioName
65163
65570
  }, row.key)), page.remaining > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
65164
65571
  type: "button",
65165
65572
  className: "mt-1 w-full rounded border border-border py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover",
@@ -65189,8 +65596,9 @@ function secondLine(device, groupBy) {
65189
65596
  ].filter((part) => part !== null);
65190
65597
  return parts.length > 0 ? parts.join(" · ") : void 0;
65191
65598
  }
65192
- function PickerRowView({ row, value, onChange, onToggleGroup, annotate, groupTitle, groupBy, disabled, locked, lockedNote }) {
65599
+ function PickerRowView({ row, value, onChange, onToggleGroup, annotate, groupTitle, groupBy, disabled, locked, lockedNote, selection, radioName }) {
65193
65600
  const t = useUiText();
65601
+ const single = selection === "single";
65194
65602
  if (row.kind === "header") {
65195
65603
  const { group, expanded } = row;
65196
65604
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -65208,7 +65616,7 @@ function PickerRowView({ row, value, onChange, onToggleGroup, annotate, groupTit
65208
65616
  className: "truncate",
65209
65617
  children: groupTitle(group)
65210
65618
  }),
65211
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
65619
+ !single && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
65212
65620
  className: "font-normal normal-case",
65213
65621
  children: [
65214
65622
  "(",
@@ -65220,14 +65628,14 @@ function PickerRowView({ row, value, onChange, onToggleGroup, annotate, groupTit
65220
65628
  })
65221
65629
  ]
65222
65630
  }),
65223
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
65631
+ !single && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
65224
65632
  type: "button",
65225
65633
  disabled,
65226
65634
  className: "text-[10px] text-primary hover:underline disabled:opacity-50",
65227
65635
  onClick: () => onChange(selectPickerGroup(value, group)),
65228
65636
  children: t("uiLibrary.devicePicker.all", "All")
65229
65637
  }),
65230
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
65638
+ !single && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
65231
65639
  type: "button",
65232
65640
  disabled,
65233
65641
  className: "text-[10px] text-foreground-subtle hover:underline disabled:opacity-50",
@@ -65244,10 +65652,11 @@ function PickerRowView({ row, value, onChange, onToggleGroup, annotate, groupTit
65244
65652
  className: "flex cursor-pointer items-center gap-2.5 px-3 py-1 text-xs text-foreground hover:bg-surface-hover",
65245
65653
  "data-testid": "device-picker-row",
65246
65654
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
65247
- type: "checkbox",
65655
+ type: single ? "radio" : "checkbox",
65656
+ ...single ? { name: radioName } : {},
65248
65657
  checked: row.selected || isLocked,
65249
65658
  disabled: disabled || isLocked,
65250
- onChange: () => onChange(togglePickerDevice(value, row.device.id)),
65659
+ onChange: () => onChange(single ? [row.device.id] : togglePickerDevice(value, row.device.id)),
65251
65660
  className: "accent-primary",
65252
65661
  "data-device-id": String(row.device.id)
65253
65662
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -68488,6 +68897,8 @@ exports.RotateCcw = RotateCcw;
68488
68897
  exports.RotateCw = RotateCw;
68489
68898
  exports.Route = Route;
68490
68899
  exports.RunReport = RunReport;
68900
+ exports.RunningBadge = RunningBadge;
68901
+ exports.RunningStatusLine = RunningStatusLine;
68491
68902
  exports.SCENE_CAPTURE_VARIANTS = SCENE_CAPTURE_VARIANTS;
68492
68903
  exports.SCENE_CAPTURE_VARIANTS$1 = SCENE_CAPTURE_VARIANTS;
68493
68904
  exports.SECRET_MASK_PLACEHOLDER = SECRET_MASK_PLACEHOLDER;
@@ -68929,6 +69340,8 @@ exports.roiTooLarge = roiTooLarge;
68929
69340
  exports.roiTooLarge$1 = roiTooLarge;
68930
69341
  exports.rootSourceState = rootSourceState;
68931
69342
  exports.routerBasename = routerBasename;
69343
+ exports.runningDurationSince = runningDurationSince;
69344
+ exports.runningStatusParts = runningStatusParts;
68932
69345
  exports.sameLocationSuggestions = sameLocationSuggestions;
68933
69346
  exports.scrubReducer = scrubReducer;
68934
69347
  exports.searchSteps = searchSteps;
@@ -70023,6 +70436,7 @@ exports.useRecordingOnboardSetSettings = useRecordingOnboardSetSettings;
70023
70436
  exports.useRecordingSignalGetStatus = useRecordingSignalGetStatus;
70024
70437
  exports.useRemoteComponent = useRemoteComponent;
70025
70438
  exports.useRoleDisplayDefaults = useRoleDisplayDefaults;
70439
+ exports.useRunningStateGetStatus = useRunningStateGetStatus;
70026
70440
  exports.useSceneMonitorCaptureReference = useSceneMonitorCaptureReference;
70027
70441
  exports.useSceneMonitorCreateScene = useSceneMonitorCreateScene;
70028
70442
  exports.useSceneMonitorDeleteReference = useSceneMonitorDeleteReference;