@camstack/ui-library 0.1.57 → 0.2.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.
- package/dist/composites/addon-global-settings-form.d.ts +1 -1
- package/dist/composites/agent-step-editor.d.ts +1 -1
- package/dist/composites/app-shell/app-shell.d.ts +1 -1
- package/dist/composites/app-shell/sidebar-item.d.ts +1 -1
- package/dist/composites/app-shell/sidebar.d.ts +1 -1
- package/dist/composites/audio-classification-list.d.ts +1 -1
- package/dist/composites/audio-level-waveform.d.ts +1 -1
- package/dist/composites/audio-waveform.d.ts +1 -1
- package/dist/composites/battery-badge.d.ts +4 -1
- package/dist/composites/breadcrumb.d.ts +2 -1
- package/dist/composites/camera-stream-player.d.ts +94 -2
- package/dist/composites/cap-settings/AutotrackSection.d.ts +1 -1
- package/dist/composites/cap-settings/ConsumablesPanel.d.ts +2 -0
- package/dist/composites/cap-settings/CoverageTrack.d.ts +12 -0
- package/dist/composites/cap-settings/EventBucketStrip.d.ts +25 -0
- package/dist/composites/cap-settings/EventHeatmap.d.ts +10 -0
- package/dist/composites/cap-settings/MaskShapeCanvas.d.ts +1 -1
- package/dist/composites/cap-settings/MotionZonesSettings.d.ts +1 -1
- package/dist/composites/cap-settings/PrivacyMaskSettings.d.ts +1 -1
- package/dist/composites/cap-settings/PtzPanel.d.ts +1 -1
- package/dist/composites/cap-settings/RecordingPanel.d.ts +2 -0
- package/dist/composites/cap-settings/RecordingRulesEditor.d.ts +7 -0
- package/dist/composites/cap-settings/RecordingSettings.d.ts +8 -0
- package/dist/composites/cap-settings/RecordingTimeline.d.ts +5 -0
- package/dist/composites/cap-settings/ScheduleBandsEditor.d.ts +7 -0
- package/dist/composites/cap-settings/TimelineControls.d.ts +21 -0
- package/dist/composites/cap-settings/event-thumb.d.ts +11 -0
- package/dist/composites/cap-settings/index.d.ts +4 -0
- package/dist/composites/cap-settings/recording-config-form.d.ts +34 -0
- package/dist/composites/cap-settings/recording-spans.d.ts +22 -0
- package/dist/composites/cap-settings/recording-timeline-model.d.ts +84 -0
- package/dist/composites/code-block.d.ts +1 -1
- package/dist/composites/config-form-builder.d.ts +1 -1
- package/dist/composites/config-form-field.d.ts +3 -3
- package/dist/composites/confirm-action-button.d.ts +1 -1
- package/dist/composites/confirm-dialog.d.ts +1 -1
- package/dist/composites/data-table/data-table-header.d.ts +1 -1
- package/dist/composites/data-table/data-table-pagination.d.ts +1 -1
- package/dist/composites/data-table/data-table-row.d.ts +1 -1
- package/dist/composites/data-table/data-table.d.ts +1 -1
- package/dist/composites/data-table.d.ts +1 -1
- package/dist/composites/detection-canvas.d.ts +1 -1
- package/dist/composites/detection-overlay.d.ts +1 -1
- package/dist/composites/detection-result-tree.d.ts +1 -1
- package/dist/composites/dev-shell.d.ts +1 -1
- package/dist/composites/device-activity-panel.d.ts +5 -1
- package/dist/composites/device-card.d.ts +1 -1
- package/dist/composites/device-controls/alarm-hero-card.d.ts +24 -0
- package/dist/composites/device-controls/atoms.d.ts +81 -0
- package/dist/composites/device-controls/brightness-panel.d.ts +3 -0
- package/dist/composites/device-controls/button-control.d.ts +18 -0
- package/dist/composites/device-controls/climate-panel.d.ts +16 -0
- package/dist/composites/device-controls/container-primary-hero.d.ts +24 -0
- package/dist/composites/device-controls/container-primary.d.ts +46 -0
- package/dist/composites/device-controls/control-panel.d.ts +10 -0
- package/dist/composites/device-controls/control-registry.d.ts +74 -0
- package/dist/composites/device-controls/cover-hero-card.d.ts +27 -0
- package/dist/composites/device-controls/cover-inline.d.ts +27 -0
- package/dist/composites/device-controls/cover-panel.d.ts +3 -0
- package/dist/composites/device-controls/dummy-hero-card.d.ts +6 -0
- package/dist/composites/device-controls/fan-hero-card.d.ts +21 -0
- package/dist/composites/device-controls/fan-panel.d.ts +3 -0
- package/dist/composites/device-controls/humidifier-control.d.ts +37 -0
- package/dist/composites/device-controls/image-control.d.ts +24 -0
- package/dist/composites/device-controls/index.d.ts +33 -0
- package/dist/composites/device-controls/lawn-mower-control.d.ts +24 -0
- package/dist/composites/device-controls/light-hero-card.d.ts +16 -0
- package/dist/composites/device-controls/lock-hero-card.d.ts +15 -0
- package/dist/composites/device-controls/lock-panel.d.ts +3 -0
- package/dist/composites/device-controls/media-player-hero-card.d.ts +17 -0
- package/dist/composites/device-controls/media-player-panel.d.ts +9 -0
- package/dist/composites/device-controls/offline-badge.d.ts +11 -0
- package/dist/composites/device-controls/panel-controls.d.ts +17 -0
- package/dist/composites/device-controls/popover-row-action.d.ts +9 -0
- package/dist/composites/device-controls/primary-child.d.ts +18 -0
- package/dist/composites/device-controls/radial-gauge.d.ts +20 -0
- package/dist/composites/device-controls/sensor-hero-card.d.ts +10 -0
- package/dist/composites/device-controls/sensor-inline-control.d.ts +11 -0
- package/dist/composites/device-controls/sensor-value-atom.d.ts +106 -0
- package/dist/composites/device-controls/switch-hero-card.d.ts +13 -0
- package/dist/composites/device-controls/switch-panel.d.ts +3 -0
- package/dist/composites/device-controls/tap-toggle.d.ts +17 -0
- package/dist/composites/device-controls/thermostat-hero-card.d.ts +17 -0
- package/dist/composites/device-controls/types.d.ts +17 -0
- package/dist/composites/device-controls/update-control.d.ts +11 -0
- package/dist/composites/device-controls/vacuum-control.d.ts +36 -0
- package/dist/composites/device-controls/valve-control.d.ts +46 -0
- package/dist/composites/device-controls/water-heater-control.d.ts +41 -0
- package/dist/composites/device-controls/weather-control.d.ts +41 -0
- package/dist/composites/device-export-panel.d.ts +1 -1
- package/dist/composites/device-grid.d.ts +1 -1
- package/dist/composites/device-item/actions.d.ts +12 -1
- package/dist/composites/device-item/child-layout.d.ts +32 -0
- package/dist/composites/device-item/child-section-accordion.d.ts +9 -0
- package/dist/composites/device-item/children-accordion.d.ts +1 -1
- package/dist/composites/device-item/container-children-context.d.ts +15 -0
- package/dist/composites/device-item/device-delete-action.d.ts +8 -0
- package/dist/composites/device-item/header.d.ts +8 -1
- package/dist/composites/device-item/helpers.d.ts +108 -2
- package/dist/composites/device-item/index.d.ts +4 -0
- package/dist/composites/device-item/preview.d.ts +3 -3
- package/dist/composites/device-item/reboot-quick-action.d.ts +9 -0
- package/dist/composites/device-item/status-dot.d.ts +4 -1
- package/dist/composites/device-list/batch-actions-bar.d.ts +15 -0
- package/dist/composites/device-list/batch-toolbar.d.ts +15 -0
- package/dist/composites/device-list/cards-layout.d.ts +18 -0
- package/dist/composites/device-list/columns.d.ts +68 -0
- package/dist/composites/device-list/device-mode.d.ts +115 -0
- package/dist/composites/device-list/filter-chips.d.ts +15 -6
- package/dist/composites/device-list/fuzzy-match.d.ts +27 -0
- package/dist/composites/device-list/generic-mode.d.ts +81 -0
- package/dist/composites/device-list/group.d.ts +19 -0
- package/dist/composites/device-list/hardware-cell.d.ts +7 -0
- package/dist/composites/device-list/hardware.d.ts +26 -0
- package/dist/composites/device-list/icon-action.d.ts +17 -0
- package/dist/composites/device-list/index.d.ts +23 -39
- package/dist/composites/device-list/multi-select.d.ts +22 -0
- package/dist/composites/device-list/sort.d.ts +18 -0
- package/dist/composites/device-list/sortable-header.d.ts +10 -0
- package/dist/composites/device-list/table-layout.d.ts +25 -0
- package/dist/composites/device-list/type-filter.d.ts +19 -0
- package/dist/composites/device-list/url-state.d.ts +7 -2
- package/dist/composites/device-meta.d.ts +38 -0
- package/dist/composites/discovery-panel.d.ts +4 -4
- package/dist/composites/doorbell-recent-panel.d.ts +1 -1
- package/dist/composites/empty-state.d.ts +1 -1
- package/dist/composites/error-box.d.ts +1 -1
- package/dist/composites/event-stream.d.ts +2 -2
- package/dist/composites/filter-bar.d.ts +1 -1
- package/dist/composites/form-field.d.ts +1 -1
- package/dist/composites/hls-quality.d.ts +35 -0
- package/dist/composites/hls-video.d.ts +26 -0
- package/dist/composites/hover-zoom-image.d.ts +18 -0
- package/dist/composites/image-selector.d.ts +1 -1
- package/dist/composites/index.d.ts +15 -4
- package/dist/composites/inference-config-selector.d.ts +1 -1
- package/dist/composites/kebab-menu.d.ts +1 -1
- package/dist/composites/key-value-list.d.ts +1 -1
- package/dist/composites/log-stream-scroll.d.ts +32 -0
- package/dist/composites/log-stream.d.ts +9 -2
- package/dist/composites/login-form.d.ts +1 -1
- package/dist/composites/node-picker.d.ts +1 -1
- package/dist/composites/page-header.d.ts +1 -1
- package/dist/composites/phase-icon.d.ts +1 -1
- package/dist/composites/pipeline-builder.d.ts +1 -1
- package/dist/composites/pipeline-runtime-selector.d.ts +1 -1
- package/dist/composites/pipeline-step.d.ts +3 -3
- package/dist/composites/pipeline-tree-matrix.d.ts +1 -1
- package/dist/composites/provider-badge.d.ts +1 -1
- package/dist/composites/ptz-overlay.d.ts +1 -1
- package/dist/composites/qr-code.d.ts +1 -1
- package/dist/composites/response-log.d.ts +1 -1
- package/dist/composites/scope-picker.d.ts +1 -1
- package/dist/composites/slide-over-panel.d.ts +1 -1
- package/dist/composites/snapshot-button.d.ts +1 -1
- package/dist/composites/stat-card.d.ts +1 -1
- package/dist/composites/state-values-stream.d.ts +1 -1
- package/dist/composites/status-badge.d.ts +1 -1
- package/dist/composites/step-timings.d.ts +1 -1
- package/dist/composites/step-tree-master.d.ts +1 -1
- package/dist/composites/stream-panel.d.ts +45 -10
- package/dist/composites/timezone-selector.d.ts +18 -0
- package/dist/composites/version-badge.d.ts +2 -2
- package/dist/composites/widget-panel.d.ts +28 -0
- package/dist/contexts/custom-field-renderers.d.ts +1 -1
- package/dist/contexts/device-context.d.ts +1 -1
- package/dist/contexts/player-overlays.d.ts +1 -1
- package/dist/contexts/system-context.d.ts +1 -1
- package/dist/contexts/vod-playback.d.ts +17 -0
- package/dist/contexts/widget-registry.d.ts +1 -1
- package/dist/contexts/zone-editing.d.ts +1 -1
- package/dist/generated/system-hooks.d.ts +386 -56
- package/dist/hooks/index.d.ts +8 -2
- package/dist/hooks/use-device-cap-slice.d.ts +19 -0
- package/dist/hooks/use-device-capability.d.ts +12 -0
- package/dist/hooks/use-device-list-page-size.d.ts +14 -0
- package/dist/hooks/use-device-webrtc.d.ts +36 -4
- package/dist/hooks/use-optimistic-slice.d.ts +11 -0
- package/dist/index.cjs +54834 -11195
- package/dist/index.d.ts +1 -0
- package/dist/index.js +54483 -11136
- package/dist/lib/format-control-datetime.d.ts +18 -0
- package/dist/lib/format-last-seen.d.ts +12 -0
- package/dist/lib/format-numeric.d.ts +9 -0
- package/dist/lib/index.d.ts +3 -0
- package/dist/primitives/bottom-sheet.d.ts +1 -1
- package/dist/primitives/collapsible-card.d.ts +1 -1
- package/dist/primitives/dialog.d.ts +19 -6
- package/dist/primitives/dropdown.d.ts +3 -3
- package/dist/primitives/floating-panel.d.ts +1 -1
- package/dist/primitives/mobile-drawer.d.ts +1 -1
- package/dist/primitives/popover.d.ts +3 -3
- package/dist/primitives/tabs.d.ts +4 -4
- package/dist/primitives/tooltip.d.ts +11 -5
- package/dist/theme/index.cjs +0 -3
- package/dist/theme/index.js +0 -2
- package/dist/theme/theme-provider.d.ts +1 -1
- package/package.json +13 -5
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/theme/index.cjs.map +0 -1
- package/dist/theme/index.js.map +0 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DeviceControlProps } from './control-registry';
|
|
3
|
+
/**
|
|
4
|
+
* MediaPlayerHeroCard — now-playing hero for MediaPlayer devices.
|
|
5
|
+
*
|
|
6
|
+
* Renders (Spec §3):
|
|
7
|
+
* - Now-playing block: cover glyph + title + artist/album.
|
|
8
|
+
* - Seek GripTrack with a native range overlay (gated on DeviceFeature
|
|
9
|
+
* MediaPlayerSeek + a known duration).
|
|
10
|
+
* - Transport row: SkipBack / Play-Pause / SkipForward (lucide icons). Skip
|
|
11
|
+
* buttons are gated on MediaPlayerPrevious / MediaPlayerNext.
|
|
12
|
+
* - Volume GripTrack with a native range overlay + mute toggle (gated on a
|
|
13
|
+
* non-null volume surface + DeviceFeature.MediaPlayerVolume).
|
|
14
|
+
*
|
|
15
|
+
* Cap-gated on `media-player` — returns null when the device lacks the cap.
|
|
16
|
+
*/
|
|
17
|
+
export declare function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic, }: DeviceControlProps): ReactNode;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ControlPanelProps } from './types.js';
|
|
3
|
+
import { MediaPlayerState } from '@camstack/types';
|
|
4
|
+
/**
|
|
5
|
+
* Exhaustive colour map — one entry per MediaPlayerState.
|
|
6
|
+
* Build fails if a state is added and not reflected here.
|
|
7
|
+
*/
|
|
8
|
+
export declare const STATE_COLOR: Record<MediaPlayerState, string>;
|
|
9
|
+
export declare function MediaPlayerPanel({ trpc, deviceId, features: _features, layout, optimistic, }: ControlPanelProps): ReactNode;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
export interface OfflineBadgeProps {
|
|
3
|
+
/**
|
|
4
|
+
* Ms epoch of the last online→offline transition (device-status
|
|
5
|
+
* `lastChangedAt`). `null`/`undefined`/non-positive → no "last seen"
|
|
6
|
+
* suffix is shown.
|
|
7
|
+
*/
|
|
8
|
+
readonly lastChangedAt?: number | null;
|
|
9
|
+
readonly className?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function OfflineBadge({ lastChangedAt, className }: OfflineBadgeProps): ReactElement;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DeviceControlProps } from './control-registry';
|
|
3
|
+
export { ThermostatHeroCard } from './thermostat-hero-card';
|
|
4
|
+
export { LockHeroCard } from './lock-hero-card';
|
|
5
|
+
export { LightHeroCard } from './light-hero-card';
|
|
6
|
+
export { FanHeroCard } from './fan-hero-card';
|
|
7
|
+
export { SwitchHeroCard } from './switch-hero-card';
|
|
8
|
+
export { MediaPlayerHeroCard } from './media-player-hero-card';
|
|
9
|
+
export { AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl } from './alarm-hero-card';
|
|
10
|
+
export declare function SwitchInlineControl({ trpc, deviceId, features, optimistic, }: DeviceControlProps): ReactNode;
|
|
11
|
+
export declare function LockInlineControl({ trpc, deviceId, features, optimistic, }: DeviceControlProps): ReactNode;
|
|
12
|
+
export declare function LightInlineControl({ trpc, deviceId, features, optimistic, }: DeviceControlProps): ReactNode;
|
|
13
|
+
export declare function FanInlineControl({ trpc, deviceId, features, optimistic, }: DeviceControlProps): ReactNode;
|
|
14
|
+
export declare function ThermostatInlineControl({ trpc, deviceId, features, optimistic, }: DeviceControlProps): ReactNode;
|
|
15
|
+
export declare function MediaPlayerInlineControl({ trpc, deviceId, features, optimistic, }: DeviceControlProps): ReactNode;
|
|
16
|
+
export declare function ControlInlineControl({ trpc, deviceId, features, optimistic, }: DeviceControlProps): ReactNode;
|
|
17
|
+
export declare function ControlHeroCard({ trpc, deviceId, features, optimistic, }: DeviceControlProps): ReactNode;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { LucideIcon } from 'lucide-react';
|
|
3
|
+
interface PopoverRowActionProps {
|
|
4
|
+
readonly icon: LucideIcon;
|
|
5
|
+
readonly title: string;
|
|
6
|
+
readonly children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export declare function PopoverRowAction({ icon: Icon, title, children, }: PopoverRowActionProps): ReactNode;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure resolver: given a container's entity-children and an optional picker
|
|
3
|
+
* override (stored as an entityId string, re-sync-stable), returns the child
|
|
4
|
+
* that should be rendered as the container's PRIMARY child.
|
|
5
|
+
*
|
|
6
|
+
* Design note: ChildRef.type is kept as `string` (not `DeviceType`) to decouple
|
|
7
|
+
* this pure resolver from the types enum. The resolver is tolerant of unknown
|
|
8
|
+
* type names — they sort after all known PRIORITY entries. This avoids creating
|
|
9
|
+
* a hard import dependency between the resolver and the enum, and handles future
|
|
10
|
+
* entity types gracefully.
|
|
11
|
+
*/
|
|
12
|
+
export declare const PRIORITY: readonly string[];
|
|
13
|
+
export interface ChildRef {
|
|
14
|
+
readonly id: number;
|
|
15
|
+
readonly entityId: string;
|
|
16
|
+
readonly type: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function resolvePrimaryChild(children: readonly ChildRef[], overrideEntityId: string | undefined): ChildRef | null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface RadialGaugeProps {
|
|
3
|
+
/** Fill fraction 0..1 (brightness or speed level). */
|
|
4
|
+
readonly fraction: number;
|
|
5
|
+
/** Hex/CSS colour for the fill arc + knob border. */
|
|
6
|
+
readonly color: string;
|
|
7
|
+
/** Centered content (icon + value readout). */
|
|
8
|
+
readonly children: ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* When provided, the ArcKnob becomes draggable: dragging it reports the new
|
|
11
|
+
* arc fraction (0..1) to the parent, which owns the value and re-renders the
|
|
12
|
+
* gauge at the new `fraction`. When omitted the knob is display-only.
|
|
13
|
+
*/
|
|
14
|
+
readonly onDragFraction?: (fraction: number) => void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Circular gauge with an ArcKnob at `fraction` and centered children.
|
|
18
|
+
* The knob wrapper carries `data-testid="arc-knob"` for test assertions.
|
|
19
|
+
*/
|
|
20
|
+
export declare function RadialGauge({ fraction, color, children, onDragFraction, }: RadialGaugeProps): ReactNode;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DeviceControlProps } from './control-registry';
|
|
3
|
+
/**
|
|
4
|
+
* SensorHeroCard — full hero card for the device-detail area.
|
|
5
|
+
*
|
|
6
|
+
* Fetches the device row (name, role, sourceInfo) via React Query
|
|
7
|
+
* (`deviceManager.getDevice`), then delegates rendering to the inner
|
|
8
|
+
* component that reads the live state slice via the proxy.
|
|
9
|
+
*/
|
|
10
|
+
export declare function SensorHeroCard({ trpc, deviceId }: DeviceControlProps): ReactNode;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DeviceControlProps } from './control-registry';
|
|
3
|
+
/**
|
|
4
|
+
* Registry InlineControl for Sensor and Presence device types.
|
|
5
|
+
*
|
|
6
|
+
* Fetches the device row once (React Query cache — no waterfall for
|
|
7
|
+
* repeated renders), maps to DeviceItemDevice, and delegates rendering
|
|
8
|
+
* to the existing SensorValueAtom so both the row special-case path and
|
|
9
|
+
* the registry path stay in sync.
|
|
10
|
+
*/
|
|
11
|
+
export declare function SensorInlineControl({ trpc, deviceId }: DeviceControlProps): ReactNode;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DeviceProxy, SliceHandle } from '@camstack/types';
|
|
3
|
+
import { UseDeviceProxyTrpc } from '../../hooks/use-device-proxy';
|
|
4
|
+
import { ControlDateTimeFormat } from '../../lib/format-control-datetime';
|
|
5
|
+
import { DeviceItemDevice } from '../device-item/helpers';
|
|
6
|
+
interface NumericDescriptor {
|
|
7
|
+
readonly kind: 'numeric';
|
|
8
|
+
/** Field in the slice that holds the numeric value. */
|
|
9
|
+
readonly field: string;
|
|
10
|
+
/** Canonical display unit for TYPED roles (temperature → '°C', humidity → '%',
|
|
11
|
+
* ambient-light → 'lx', pressure → 'hPa'). When present the UI renders this
|
|
12
|
+
* directly WITHOUT consulting the slice or sourceInfo.
|
|
13
|
+
* For the generic `numeric-sensor` role this is `undefined` — the unit is
|
|
14
|
+
* read live from the slice (`slice.unit`). */
|
|
15
|
+
readonly canonicalUnit?: string;
|
|
16
|
+
/** Accessor into DeviceProxy['state'] — returns a typed slice handle. */
|
|
17
|
+
readonly getSliceHandle: (state: DeviceProxy['state']) => SliceHandle<unknown>;
|
|
18
|
+
}
|
|
19
|
+
interface BinaryDescriptor {
|
|
20
|
+
readonly kind: 'binary';
|
|
21
|
+
/** Field in the slice that holds the boolean trigger. */
|
|
22
|
+
readonly field: string;
|
|
23
|
+
/** Label shown when the boolean field is truthy. */
|
|
24
|
+
readonly onLabel: string;
|
|
25
|
+
/** Label shown when the boolean field is falsy. */
|
|
26
|
+
readonly offLabel: string;
|
|
27
|
+
readonly getSliceHandle: (state: DeviceProxy['state']) => SliceHandle<unknown>;
|
|
28
|
+
}
|
|
29
|
+
interface PresenceDescriptor {
|
|
30
|
+
readonly kind: 'presence';
|
|
31
|
+
readonly getSliceHandle: (state: DeviceProxy['state']) => SliceHandle<unknown>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* String-valued sensor whose slice holds `{ value: string, lastFetchedAt }`.
|
|
35
|
+
* Used for HA free-text sensors (IP address, SSID, firmware version, …) that
|
|
36
|
+
* have no numeric device_class and whose state is a plain string.
|
|
37
|
+
*/
|
|
38
|
+
interface StringDescriptor {
|
|
39
|
+
readonly kind: 'string';
|
|
40
|
+
readonly getSliceHandle: (state: DeviceProxy['state']) => SliceHandle<unknown>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Date / timestamp sensor whose slice holds `{ value: string, format? }`
|
|
44
|
+
* carrying a raw ISO string (e.g. '2025-12-02T09:36:12+00:00'). Rendered
|
|
45
|
+
* locale-formatted via `formatControlDateTime`. The slice's own `format` (seeded
|
|
46
|
+
* by the HA provider from the entity's `device_class` — `timestamp` → 'datetime',
|
|
47
|
+
* `date` → 'date', time-only → 'time') selects the shape; `descriptor.format` is
|
|
48
|
+
* the fallback for slices adopted before the field was threaded ('datetime').
|
|
49
|
+
*/
|
|
50
|
+
interface DateTimeDescriptor {
|
|
51
|
+
readonly kind: 'datetime';
|
|
52
|
+
readonly format: ControlDateTimeFormat;
|
|
53
|
+
readonly getSliceHandle: (state: DeviceProxy['state']) => SliceHandle<unknown>;
|
|
54
|
+
}
|
|
55
|
+
export type SensorDescriptor = NumericDescriptor | BinaryDescriptor | PresenceDescriptor | StringDescriptor | DateTimeDescriptor;
|
|
56
|
+
/**
|
|
57
|
+
* Binary fallback for the `battery-sensor` role.
|
|
58
|
+
*
|
|
59
|
+
* HA assigns role `battery-sensor` to BOTH numeric battery entities
|
|
60
|
+
* (`sensor.*` device_class=battery → cap `numeric-sensor`) AND binary battery
|
|
61
|
+
* entities (`binary_sensor.*` device_class=battery → cap `binary`, e.g. a
|
|
62
|
+
* HomeMatic `LOW_BAT` flag). When the numeric slice is absent the binary slice
|
|
63
|
+
* is rendered instead, with battery-specific polarity: `on:true` means LOW
|
|
64
|
+
* (bad → warning style + "Low"), `on:false` means Normal (neutral).
|
|
65
|
+
*/
|
|
66
|
+
export declare const BINARY_BATTERY_DESCRIPTOR: BinaryDescriptor;
|
|
67
|
+
/** True for the role that can resolve to either a numeric or a binary slice. */
|
|
68
|
+
export declare function isBatterySensorRole(role: string | null | undefined): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* A numeric slice counts as "present" only when it carries a real numeric value
|
|
71
|
+
* at the descriptor field — a cold-start slice (`{ value: 0, lastFetchedAt: 0 }`)
|
|
72
|
+
* or a binary slice (no numeric field) does NOT, so the binary fallback wins.
|
|
73
|
+
*/
|
|
74
|
+
export declare function hasBatteryNumericValue(slice: unknown, field: string): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Keyed by DeviceRole string value. Every entry maps a role to the
|
|
77
|
+
* exact proxy state accessor + rendering instructions. The accessor
|
|
78
|
+
* avoids dynamic string indexing — each one is a concrete property
|
|
79
|
+
* access on the typed `DeviceProxy['state']` shape.
|
|
80
|
+
*
|
|
81
|
+
* Canonical unit rules:
|
|
82
|
+
* - Typed roles (temperature/humidity/ambient-light/pressure/power/energy)
|
|
83
|
+
* carry a `canonicalUnit` constant. The slice is normalised to one unit
|
|
84
|
+
* so no per-device lookup is needed.
|
|
85
|
+
* - Generic `numeric-sensor` has no `canonicalUnit`. The unit is read live
|
|
86
|
+
* from the slice (`slice.unit`) as populated by the provider from the
|
|
87
|
+
* upstream source on every state push.
|
|
88
|
+
*/
|
|
89
|
+
export declare const ROLE_DESCRIPTOR: Record<string, SensorDescriptor>;
|
|
90
|
+
export interface StringSliceValue {
|
|
91
|
+
readonly value: string;
|
|
92
|
+
}
|
|
93
|
+
export declare function isStringSliceValue(v: unknown): v is StringSliceValue;
|
|
94
|
+
/**
|
|
95
|
+
* The enum-sensor slice carries an optional `format` ('date' | 'time' |
|
|
96
|
+
* 'datetime') for `DateTimeSensor`-role sensors. Read it off the live slice so
|
|
97
|
+
* each sensor renders its true shape; returns `undefined` when absent (older
|
|
98
|
+
* adoptions) so the caller falls back to the descriptor default.
|
|
99
|
+
*/
|
|
100
|
+
export declare function readSliceDateTimeFormat(slice: unknown): ControlDateTimeFormat | undefined;
|
|
101
|
+
export interface SensorValueAtomProps {
|
|
102
|
+
readonly trpc: UseDeviceProxyTrpc;
|
|
103
|
+
readonly device: DeviceItemDevice;
|
|
104
|
+
}
|
|
105
|
+
export declare function SensorValueAtom({ trpc, device }: SensorValueAtomProps): ReactNode;
|
|
106
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DeviceControlProps } from './control-registry';
|
|
3
|
+
/**
|
|
4
|
+
* SwitchHeroCard — large tap-toggle hero for Switch / Siren devices.
|
|
5
|
+
*
|
|
6
|
+
* Renders (Spec §3):
|
|
7
|
+
* - A power glyph tinted by on/off state (success when on, muted when off).
|
|
8
|
+
* - A large TAP TOGGLE for on/off — a single tap flips state. This is NOT a
|
|
9
|
+
* SlideToggle; slide-to-confirm is reserved for safety-gated locks ONLY.
|
|
10
|
+
*
|
|
11
|
+
* Cap-gated on `switch` — returns null when the device has no switch cap.
|
|
12
|
+
*/
|
|
13
|
+
export declare function SwitchHeroCard({ trpc, deviceId, optimistic }: DeviceControlProps): ReactNode;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* TapToggle — plain tap-to-toggle on/off control.
|
|
4
|
+
*
|
|
5
|
+
* Spec §3: everyday on/off (switch, light, fan) uses a plain TAP TOGGLE.
|
|
6
|
+
* slide-to-confirm is reserved for safety-gated actions (lock) ONLY. This
|
|
7
|
+
* component must NEVER be built on `SlideToggle` — a single tap flips state.
|
|
8
|
+
*
|
|
9
|
+
* Presentational: the caller owns the cap mutation + optimistic update via
|
|
10
|
+
* `onToggle`. Mirrors the `SwitchPanel` button treatment at hero scale.
|
|
11
|
+
*/
|
|
12
|
+
export interface TapToggleProps {
|
|
13
|
+
readonly on: boolean;
|
|
14
|
+
readonly busy: boolean;
|
|
15
|
+
readonly onToggle: () => void;
|
|
16
|
+
}
|
|
17
|
+
export declare function TapToggle({ on, busy, onToggle }: TapToggleProps): ReactNode;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DeviceControlProps } from './control-registry';
|
|
3
|
+
/**
|
|
4
|
+
* ThermostatHeroCard — circular gauge hero for thermostat / HVAC devices.
|
|
5
|
+
*
|
|
6
|
+
* Renders:
|
|
7
|
+
* - SVG ring gauge: track + fill arc representing the setpoint fraction
|
|
8
|
+
* - Centered current temperature (large, prominent)
|
|
9
|
+
* - ArcKnob(s) at the setpoint fraction(s) riding the ring
|
|
10
|
+
* - Single knob for heat / cool / auto / dry modes
|
|
11
|
+
* - Two knobs (low + high) with a band fill for heat_cool mode
|
|
12
|
+
* - Stepper (single) or "Low / High" display (range) for the setpoint
|
|
13
|
+
* - Mode select
|
|
14
|
+
*
|
|
15
|
+
* Cap-gated: returns null when the device has no climateControl cap.
|
|
16
|
+
*/
|
|
17
|
+
export declare function ThermostatHeroCard({ trpc, deviceId, features: _features, optimistic, }: DeviceControlProps): ReactNode;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { UseDeviceProxyTrpc } from '../../hooks/use-device-proxy';
|
|
2
|
+
/** Shared props for every control panel. `layout` selects the compact (row
|
|
3
|
+
* popover) vs full (detail tab) presentation. `features` gates sub-controls
|
|
4
|
+
* (e.g. cover position/tilt, fan speed/preset). */
|
|
5
|
+
export interface ControlPanelProps {
|
|
6
|
+
readonly trpc: UseDeviceProxyTrpc;
|
|
7
|
+
readonly deviceId: number;
|
|
8
|
+
readonly features: readonly string[] | undefined;
|
|
9
|
+
readonly layout: 'compact' | 'full';
|
|
10
|
+
/** Enable optimistic UI mode (default: true). Set to false to disable. */
|
|
11
|
+
readonly optimistic?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** Cap names whose presence (bound on a device) means it has a control surface.
|
|
14
|
+
* Single source of truth shared by the row registry and the detail Controls tab
|
|
15
|
+
* so the two never drift. */
|
|
16
|
+
export declare const CONTROL_CAP_NAMES: readonly ["cover", "lock-control", "switch", "brightness", "fan-control", "climate-control", "media-player", "control"];
|
|
17
|
+
export type ControlCapName = (typeof CONTROL_CAP_NAMES)[number];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DeviceControlProps } from './control-registry';
|
|
3
|
+
/**
|
|
4
|
+
* UpdateInlineControl — compact firmware state for a device-list row.
|
|
5
|
+
*/
|
|
6
|
+
export declare function UpdateInlineControl({ trpc, deviceId }: DeviceControlProps): ReactNode;
|
|
7
|
+
/**
|
|
8
|
+
* UpdateHeroCard — version transition + Install action for the device-detail
|
|
9
|
+
* hero area.
|
|
10
|
+
*/
|
|
11
|
+
export declare function UpdateHeroCard({ trpc, deviceId }: DeviceControlProps): ReactNode;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { VacuumState, TankStatus } from '@camstack/types';
|
|
3
|
+
import { DeviceControlProps } from './control-registry';
|
|
4
|
+
export interface VacuumStateMeta {
|
|
5
|
+
readonly label: string;
|
|
6
|
+
/** Tailwind text-colour token for the state label. */
|
|
7
|
+
readonly tone: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Pure helper — maps a VacuumState (or undefined when no slice yet) to a
|
|
11
|
+
* human label + colour tone. Exhaustive switch: a new enum member fails
|
|
12
|
+
* the build.
|
|
13
|
+
*/
|
|
14
|
+
export declare function vacuumStateMeta(state: VacuumState | undefined): VacuumStateMeta;
|
|
15
|
+
/** The four intrinsic tanks a vacuum cap can expose. */
|
|
16
|
+
export type TankKind = 'cleanWater' | 'dirtyWater' | 'detergent' | 'dustBin';
|
|
17
|
+
export type TankAlert = 'ok' | 'warning';
|
|
18
|
+
/**
|
|
19
|
+
* Pure helper — classifies a tank as `ok` or `warning`.
|
|
20
|
+
*
|
|
21
|
+
* Clean-water + detergent are "supply" tanks: low is bad. Dirty-water +
|
|
22
|
+
* dust-bin are "waste" tanks: full is bad. Prefers the numeric `level`
|
|
23
|
+
* (thresholds 15 / 85), falling back to the discrete `status` flag. Both
|
|
24
|
+
* unknown → `ok`. Exhaustive over TankKind.
|
|
25
|
+
*/
|
|
26
|
+
export declare function tankAlert(kind: TankKind, tank: TankStatus): TankAlert;
|
|
27
|
+
/**
|
|
28
|
+
* VacuumInlineControl — compact, state-aware vacuum controls for a
|
|
29
|
+
* device-list row. Start / Pause / Return-to-base + battery badge.
|
|
30
|
+
*/
|
|
31
|
+
export declare function VacuumInlineControl({ trpc, deviceId }: DeviceControlProps): ReactNode;
|
|
32
|
+
/**
|
|
33
|
+
* VacuumHeroCard — full control surface for the device-detail hero area.
|
|
34
|
+
* State label + action buttons + fan-speed selector + battery readout.
|
|
35
|
+
*/
|
|
36
|
+
export declare function VacuumHeroCard({ trpc, deviceId }: DeviceControlProps): ReactNode;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ValveState } from '@camstack/types';
|
|
3
|
+
import { DeviceControlProps } from './control-registry';
|
|
4
|
+
export interface ValveStateMeta {
|
|
5
|
+
readonly label: string;
|
|
6
|
+
/** Tailwind text-colour token for the state label. */
|
|
7
|
+
readonly tone: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Pure helper — maps a ValveState (or undefined when no slice yet) to a
|
|
11
|
+
* human label + colour tone. Exhaustive switch: a new enum member fails
|
|
12
|
+
* the build.
|
|
13
|
+
*/
|
|
14
|
+
export declare function valveStateMeta(state: ValveState | undefined): ValveStateMeta;
|
|
15
|
+
/**
|
|
16
|
+
* ValveInlineControl — compact, state-aware valve controls for a
|
|
17
|
+
* device-list row. Open ▲ Stop ■ Close ▼ + optional position % badge.
|
|
18
|
+
* Mirrors `CoverInlineControl` exactly. Must NOT blow out the row width.
|
|
19
|
+
*/
|
|
20
|
+
export declare function ValveInlineControl({ trpc, deviceId, optimistic }: DeviceControlProps): ReactNode;
|
|
21
|
+
/** Per-state visual tint tokens for the framed valve graphic. */
|
|
22
|
+
export interface ValveGraphicTint {
|
|
23
|
+
/** Tailwind class for the flow-glow wash over the pipe. */
|
|
24
|
+
readonly glow: string;
|
|
25
|
+
/** Tailwind text token driving the valve body via currentColor. */
|
|
26
|
+
readonly accent: string;
|
|
27
|
+
/** Whether to render the animated flow dashes (open / opening). */
|
|
28
|
+
readonly flowing: boolean;
|
|
29
|
+
/** Whether to render the transient-motion activity pulse. */
|
|
30
|
+
readonly active: boolean;
|
|
31
|
+
}
|
|
32
|
+
export declare function valveGraphicTint(state: ValveState | undefined): ValveGraphicTint;
|
|
33
|
+
/**
|
|
34
|
+
* ValveHeroCard — full control surface for the device-detail hero area.
|
|
35
|
+
*
|
|
36
|
+
* Bespoke pipe + gate-valve graphic (drag surface when positionable) +
|
|
37
|
+
* a large position % (or capitalized state when position is null) +
|
|
38
|
+
* Open / Stop / Close hero buttons + a position slider gated on
|
|
39
|
+
* `ValvePositionable` (additive to drag), and a read-only range when a
|
|
40
|
+
* position is reported but not settable.
|
|
41
|
+
*
|
|
42
|
+
* Position support is detected via `ValveStatus.position !== null`; the
|
|
43
|
+
* interactive setPosition surface is gated on `DeviceFeature.ValvePositionable`.
|
|
44
|
+
* Only hides when the device truly has no valve cap.
|
|
45
|
+
*/
|
|
46
|
+
export declare function ValveHeroCard({ trpc, deviceId, features, optimistic, }: DeviceControlProps): ReactNode;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DeviceControlProps } from './control-registry';
|
|
3
|
+
/** Heating phase derived from the slice — drives the tank tint + element glow. */
|
|
4
|
+
export type WaterHeaterPhase = 'heating' | 'idle' | 'off';
|
|
5
|
+
export interface WaterHeaterTint {
|
|
6
|
+
/** Tailwind class for the wash behind the tank. */
|
|
7
|
+
readonly glow: string;
|
|
8
|
+
/** Tailwind text token driving the tank via currentColor. */
|
|
9
|
+
readonly accent: string;
|
|
10
|
+
/** Whether to render the heating-element glow. */
|
|
11
|
+
readonly heating: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Pure helper — maps a phase to a tint. Exhaustive over WaterHeaterPhase
|
|
15
|
+
* (a new member fails the build).
|
|
16
|
+
*
|
|
17
|
+
* heating → warning (element glow)
|
|
18
|
+
* idle → primary (warm but settled)
|
|
19
|
+
* off → muted
|
|
20
|
+
*/
|
|
21
|
+
export declare function waterHeaterTint(phase: WaterHeaterPhase): WaterHeaterTint;
|
|
22
|
+
/**
|
|
23
|
+
* Heuristic heating phase: off when the operation mode is 'off' (or null);
|
|
24
|
+
* heating when current < target (actively warming); otherwise idle.
|
|
25
|
+
*/
|
|
26
|
+
export declare function waterHeaterPhase(operationMode: string | null, currentTemp: number | null, targetTemp: number | null): WaterHeaterPhase;
|
|
27
|
+
/**
|
|
28
|
+
* WaterHeaterInlineControl — compact current→target readout + mode hint
|
|
29
|
+
* for a device-list row. Must NOT blow out the row width.
|
|
30
|
+
*/
|
|
31
|
+
export declare function WaterHeaterInlineControl({ trpc, deviceId, optimistic, }: DeviceControlProps): ReactNode;
|
|
32
|
+
/**
|
|
33
|
+
* WaterHeaterHeroCard — full control surface for the device-detail hero.
|
|
34
|
+
*
|
|
35
|
+
* Bespoke tank graphic + a large current-temp readout + a target-temp
|
|
36
|
+
* stepper (clamped to min/maxTemp) + an operation-mode `<select>` + an
|
|
37
|
+
* "Away" toggle (only when `away !== null`) + the current-temp readout.
|
|
38
|
+
* Gated on `available`. Only hides when the device truly has no
|
|
39
|
+
* water-heater cap.
|
|
40
|
+
*/
|
|
41
|
+
export declare function WaterHeaterHeroCard({ trpc, deviceId, optimistic }: DeviceControlProps): ReactNode;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DeviceControlProps } from './control-registry';
|
|
3
|
+
/** Which sky glyph a condition maps to. Drives both the inline icon and
|
|
4
|
+
* the hero scene's graphic branch. */
|
|
5
|
+
export type WeatherGlyph = 'sun' | 'clear-night' | 'partly-cloudy' | 'cloudy' | 'rain' | 'snow' | 'lightning' | 'fog' | 'wind' | 'hail';
|
|
6
|
+
export interface WeatherConditionMeta {
|
|
7
|
+
/** Human-readable label for the condition. */
|
|
8
|
+
readonly label: string;
|
|
9
|
+
/** Which glyph to render. */
|
|
10
|
+
readonly glyph: WeatherGlyph;
|
|
11
|
+
}
|
|
12
|
+
export interface WeatherTint {
|
|
13
|
+
/** Tailwind class for the wash behind the scene. */
|
|
14
|
+
readonly glow: string;
|
|
15
|
+
/** Tailwind text token driving the scene glyph via currentColor. */
|
|
16
|
+
readonly accent: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Pure helper — maps a verbatim HA condition string to a label + glyph.
|
|
20
|
+
* Covers the known HA `weather.*` condition set; an unknown / null
|
|
21
|
+
* condition falls back to a neutral cloud.
|
|
22
|
+
*/
|
|
23
|
+
export declare function weatherConditionMeta(condition: string | null): WeatherConditionMeta;
|
|
24
|
+
/**
|
|
25
|
+
* Pure helper — maps a verbatim HA condition string to a tint. Exhaustive
|
|
26
|
+
* over the known condition set with a neutral default.
|
|
27
|
+
*/
|
|
28
|
+
export declare function weatherTint(condition: string | null): WeatherTint;
|
|
29
|
+
/**
|
|
30
|
+
* WeatherInlineControl — compact condition icon + temperature readout
|
|
31
|
+
* for a device-list row. Read-only; must NOT blow out the row width.
|
|
32
|
+
*/
|
|
33
|
+
export declare function WeatherInlineControl({ trpc, deviceId }: DeviceControlProps): ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* WeatherHeroCard — read-only weather panel for the device-detail hero.
|
|
36
|
+
*
|
|
37
|
+
* Bespoke state-tinted sky scene + a large temperature readout +
|
|
38
|
+
* humidity / wind-speed (with a bearing arrow) / pressure readouts.
|
|
39
|
+
* Pure — no controls (the cap is read-only).
|
|
40
|
+
*/
|
|
41
|
+
export declare function WeatherHeroCard({ trpc, deviceId }: DeviceControlProps): ReactNode;
|
|
@@ -20,4 +20,4 @@ export interface DeviceExportPanelProps {
|
|
|
20
20
|
* Generic device-export panel. Addon-agnostic — only the `device-export`
|
|
21
21
|
* cap drives it.
|
|
22
22
|
*/
|
|
23
|
-
export declare function DeviceExportPanel({ addonId, trpc, onOpenDevice }: DeviceExportPanelProps): ReactElement;
|
|
23
|
+
export declare function DeviceExportPanel({ addonId, trpc, onOpenDevice, }: DeviceExportPanelProps): ReactElement;
|
|
@@ -9,4 +9,4 @@ export interface DeviceGridProps {
|
|
|
9
9
|
/** Additional CSS classes */
|
|
10
10
|
className?: string;
|
|
11
11
|
}
|
|
12
|
-
export declare function DeviceGrid({ children, minCardWidth, gap, className
|
|
12
|
+
export declare function DeviceGrid({ children, minCardWidth, gap, className }: DeviceGridProps): import("react").JSX.Element;
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { UseDeviceProxyTrpc } from '../../hooks/use-device-proxy';
|
|
3
|
+
import { ControlPlacement } from '../device-controls/control-registry';
|
|
3
4
|
import { DeviceItemDevice, VariantDefaults } from './helpers';
|
|
4
5
|
export interface DeviceItemActionsProps {
|
|
5
6
|
readonly trpc: UseDeviceProxyTrpc;
|
|
6
7
|
readonly device: DeviceItemDevice;
|
|
7
8
|
readonly flags: VariantDefaults;
|
|
9
|
+
/**
|
|
10
|
+
* Where the control sits and whether the column carries the fixed `w-[140px]`
|
|
11
|
+
* box. `'right'` (default) → flush right in the fixed column, for card /
|
|
12
|
+
* minimal views. `'center'` → centered in the fixed column. `'table'` → the
|
|
13
|
+
* column sizes to its content (no fixed width) so a wide control lays out in
|
|
14
|
+
* sequence with the trailing trash + status dot without overflowing/colliding
|
|
15
|
+
* — used by the main devices table. FILL controls stretch to the fixed column
|
|
16
|
+
* width under `'right'`/`'center'`; under `'table'` they take natural width.
|
|
17
|
+
*/
|
|
18
|
+
readonly controlPlacement?: ControlPlacement;
|
|
8
19
|
}
|
|
9
|
-
export declare function DeviceItemActions({ trpc, device,
|
|
20
|
+
export declare function DeviceItemActions({ trpc, device, controlPlacement, }: DeviceItemActionsProps): ReactNode;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ChildLayout } from '@camstack/types';
|
|
2
|
+
import { DeviceItemDevice } from './helpers';
|
|
3
|
+
export interface ChildLayoutSection {
|
|
4
|
+
readonly title: string;
|
|
5
|
+
readonly children: readonly DeviceItemDevice[];
|
|
6
|
+
/** Whether the section renders open by default. `false` when any matched
|
|
7
|
+
* layout entry for this section declared `collapsed: true`. */
|
|
8
|
+
readonly defaultOpen: boolean;
|
|
9
|
+
/** When `true`, the section's children render visually de-emphasized
|
|
10
|
+
* (muted). Set only on the synthetic "Disabled" section. */
|
|
11
|
+
readonly muted?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface GroupedChildren {
|
|
14
|
+
/** Sections ordered by first appearance in `childLayout`. */
|
|
15
|
+
readonly sections: readonly ChildLayoutSection[];
|
|
16
|
+
/** Children not referenced by any layout entry — render plainly, as today. */
|
|
17
|
+
readonly ungrouped: readonly DeviceItemDevice[];
|
|
18
|
+
/** Trailing synthetic section gathering every child whose CamStack-side
|
|
19
|
+
* `disabled` flag is set. Kept SEPARATE from `sections`/`ungrouped` so
|
|
20
|
+
* consumers render it LAST (after provider sections + ungrouped) and
|
|
21
|
+
* muted. Undefined when no child is disabled. Generic — driven purely by
|
|
22
|
+
* `child.disabled`, no provider/HA-specific input. */
|
|
23
|
+
readonly disabledSection?: ChildLayoutSection;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Partition a parent's children into provider-declared accordion sections +
|
|
27
|
+
* the remaining (ungrouped) children. A child matches an entry when
|
|
28
|
+
* `child.stableId === ${parentStableId}-${entry.childKey}`. Within a section,
|
|
29
|
+
* children sort by `order ?? Number.MAX_SAFE_INTEGER` then by name. Sections
|
|
30
|
+
* appear in first-seen order across `childLayout`. Pure — no I/O.
|
|
31
|
+
*/
|
|
32
|
+
export declare function groupChildrenByLayout(parentStableId: string, children: readonly DeviceItemDevice[], childLayout: ChildLayout | undefined): GroupedChildren;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
interface ChildSectionAccordionProps {
|
|
3
|
+
readonly title: string;
|
|
4
|
+
readonly count: number;
|
|
5
|
+
readonly children: ReactNode;
|
|
6
|
+
readonly defaultOpen?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function ChildSectionAccordion({ title, count, children, defaultOpen, }: ChildSectionAccordionProps): ReactNode;
|
|
9
|
+
export {};
|
|
@@ -7,5 +7,5 @@ interface ChildrenAccordionProps {
|
|
|
7
7
|
readonly adoptedChildren: readonly DeviceItemDevice[];
|
|
8
8
|
readonly onNavigate: (id: number) => void;
|
|
9
9
|
}
|
|
10
|
-
export declare function ChildrenAccordion({ trpc, accessoryChildren, adoptedChildren, onNavigate }: ChildrenAccordionProps): ReactNode;
|
|
10
|
+
export declare function ChildrenAccordion({ trpc, accessoryChildren, adoptedChildren, onNavigate, }: ChildrenAccordionProps): ReactNode;
|
|
11
11
|
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DeviceItemDevice } from './helpers';
|
|
3
|
+
export interface ContainerChildrenProviderProps {
|
|
4
|
+
/** `parentDeviceId → that parent's children`. Built once by the list. */
|
|
5
|
+
readonly value: ReadonlyMap<number, readonly DeviceItemDevice[]>;
|
|
6
|
+
readonly children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export declare function ContainerChildrenProvider({ value, children, }: ContainerChildrenProviderProps): ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* The children of `deviceId` as published by the nearest
|
|
11
|
+
* `ContainerChildrenProvider`. Returns a stable empty array when there is no
|
|
12
|
+
* provider or the device has no children — so a non-container row, or a row
|
|
13
|
+
* rendered outside a list, degrades exactly like the old optional prop.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useContainerChildren(deviceId: number): readonly DeviceItemDevice[];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DeviceItemDevice } from './helpers';
|
|
3
|
+
export interface DeviceDeleteActionProps {
|
|
4
|
+
readonly device: DeviceItemDevice;
|
|
5
|
+
/** Called only after the operator confirms the destructive delete. */
|
|
6
|
+
readonly onDelete: (device: DeviceItemDevice) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function DeviceDeleteAction({ device, onDelete }: DeviceDeleteActionProps): ReactNode;
|
|
@@ -10,5 +10,12 @@ export interface DeviceItemHeaderProps {
|
|
|
10
10
|
readonly expanded: boolean;
|
|
11
11
|
readonly onToggleExpand: () => void;
|
|
12
12
|
readonly onNavigateToParent: (id: number) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Vertical-card layout. When true, the name is rendered as the card's
|
|
15
|
+
* primary anchor: bigger font, heavier weight, line-clamp-2 instead of
|
|
16
|
+
* single-line truncation, and the inline integrationIcon flips above
|
|
17
|
+
* the name as a small lead-line so the name's full width is name-only.
|
|
18
|
+
*/
|
|
19
|
+
readonly stacked?: boolean;
|
|
13
20
|
}
|
|
14
|
-
export declare function DeviceItemHeader({ device, variant, flags, parent, integrationIcon, hasChildren, expanded, onToggleExpand, onNavigateToParent, }: DeviceItemHeaderProps): ReactNode;
|
|
21
|
+
export declare function DeviceItemHeader({ device, variant, flags, parent, integrationIcon, hasChildren, expanded, onToggleExpand, onNavigateToParent, stacked, }: DeviceItemHeaderProps): ReactNode;
|