@camstack/ui-library 0.1.57 → 0.1.58
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/battery-badge.d.ts +3 -0
- package/dist/composites/camera-stream-player.d.ts +62 -2
- 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/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/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 +5 -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/device-activity-panel.d.ts +5 -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-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/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 +3 -3
- 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/index.d.ts +12 -1
- package/dist/composites/log-stream-scroll.d.ts +32 -0
- package/dist/composites/log-stream.d.ts +8 -1
- package/dist/composites/stream-panel.d.ts +45 -10
- package/dist/composites/timezone-selector.d.ts +18 -0
- package/dist/composites/widget-panel.d.ts +28 -0
- package/dist/contexts/vod-playback.d.ts +17 -0
- package/dist/generated/system-hooks.d.ts +330 -56
- package/dist/hooks/index.d.ts +6 -0
- 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 +52175 -10927
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +51796 -10813
- package/dist/index.js.map +1 -1
- 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/dialog.d.ts +13 -0
- package/dist/primitives/tooltip.d.ts +9 -3
- package/package.json +3 -1
|
@@ -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;
|
|
@@ -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 {};
|
|
@@ -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;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { LucideIcon } from 'lucide-react';
|
|
3
|
+
import { SourceInfo, ChildLayout } from '@camstack/types';
|
|
3
4
|
import { UseDeviceProxyTrpc } from '../../hooks/use-device-proxy';
|
|
4
5
|
/**
|
|
5
6
|
* Mirror of the canonical `DeviceInfo` wire shape (see
|
|
@@ -26,6 +27,40 @@ export interface DeviceItemDevice {
|
|
|
26
27
|
readonly features?: readonly string[];
|
|
27
28
|
/** True for ICameraDevice instances — gates snapshot popover. */
|
|
28
29
|
readonly isCamera?: boolean;
|
|
30
|
+
/** Upstream-system identity (dispatch key + system tag + optional uniqueId).
|
|
31
|
+
* Flows from `DeviceInfo.sourceInfo` via structural cast / parse;
|
|
32
|
+
* optional so rows from providers that pre-date SourceInfo still work.
|
|
33
|
+
* Does NOT carry rendering hints (unit, precision) — those live in the
|
|
34
|
+
* cap STATUS SLICE for generic numeric-sensor, or are canonical constants
|
|
35
|
+
* in ROLE_DESCRIPTOR for typed sensor roles. */
|
|
36
|
+
readonly sourceInfo?: SourceInfo;
|
|
37
|
+
/** Soft-link to another device id. For a CONTAINER device this is the
|
|
38
|
+
* LEGACY picker-chosen primary child (numeric id); the row/hero resolve the
|
|
39
|
+
* primary child via `resolveContainerPrimary(children, linkDeviceId)`.
|
|
40
|
+
* Nullable: an explicit null means "no override → priority default".
|
|
41
|
+
* Mirrors `DeviceInfo.linkDeviceId` so the wire row passes through. */
|
|
42
|
+
readonly linkDeviceId?: number | null;
|
|
43
|
+
/** Durable primary-child override for a CONTAINER device, keyed on the
|
|
44
|
+
* chosen child's re-sync/rename-stable `entityId`. Preferred over the
|
|
45
|
+
* numeric `linkDeviceId` in `resolveContainerPrimary` (survives a re-sync
|
|
46
|
+
* that reallocates the child's numeric id). Mirrors
|
|
47
|
+
* `DeviceInfo.primaryChildEntityId`. */
|
|
48
|
+
readonly primaryChildEntityId?: string | null;
|
|
49
|
+
/** Container-level layout hint: assigns specific accessory children to named
|
|
50
|
+
* accordion sections (with optional intra-section order). Each entry's
|
|
51
|
+
* `childKey` is the child's re-sync-stable accessory `stableIdSuffix`; a child
|
|
52
|
+
* matches when `child.stableId === ${this.stableId}-${childKey}`. Mirrors
|
|
53
|
+
* `DeviceInfo.childLayout` so the wire row passes through. Absent ⇒ no layout
|
|
54
|
+
* declared (all children render in the plain list). Consumed by
|
|
55
|
+
* `groupChildrenByLayout` for the device-detail list + the table row
|
|
56
|
+
* expansion. */
|
|
57
|
+
readonly childLayout?: ChildLayout;
|
|
58
|
+
/** Hardware + identity blob (manufacturer / model / firmware / sn / uid /
|
|
59
|
+
* mac / …). Driver-populated; keys are free-form and values arbitrary, so
|
|
60
|
+
* consumers MUST treat them defensively (string-coerce for display, skip
|
|
61
|
+
* non-string/empty). Mirrors `DeviceInfo.metadata` so the wire row passes
|
|
62
|
+
* through unchanged. Absent/null ⇒ no identity info advertised. */
|
|
63
|
+
readonly metadata?: Readonly<Record<string, unknown>> | null;
|
|
29
64
|
}
|
|
30
65
|
export interface DeviceItemParent {
|
|
31
66
|
readonly id: number;
|
|
@@ -105,6 +140,47 @@ export interface DeviceItemProps {
|
|
|
105
140
|
* so every existing call site renders unchanged.
|
|
106
141
|
*/
|
|
107
142
|
readonly renderRowAction?: (device: DeviceItemDevice) => ReactNode;
|
|
143
|
+
/**
|
|
144
|
+
* Built-in confirmed delete (TABLE feature). When provided, the merged
|
|
145
|
+
* previewActions cell renders a red trash button that opens the shared
|
|
146
|
+
* centered confirm dialog and calls `onDelete(device)` only on confirm.
|
|
147
|
+
* Cap/feature-agnostic — delete is generic. Context gating is "consumer
|
|
148
|
+
* passes the handler or not": omitted ⇒ no trash, zero layout change.
|
|
149
|
+
* No effect on `view='card'` (card delete is a deliberate follow-up).
|
|
150
|
+
*/
|
|
151
|
+
readonly onDelete?: (device: DeviceItemDevice) => void;
|
|
152
|
+
/**
|
|
153
|
+
* When provided, renders a leading checkbox for row selection.
|
|
154
|
+
* Only passed to top-level rows (accessory sub-rows omit it).
|
|
155
|
+
* Omitted ⇒ no checkbox, zero layout change for existing callers.
|
|
156
|
+
*/
|
|
157
|
+
readonly selection?: {
|
|
158
|
+
readonly selected: boolean;
|
|
159
|
+
readonly onToggle: () => void;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* When `true` (and `selection` is provided), a click anywhere on the
|
|
163
|
+
* row's primary body toggles selection instead of navigating — the
|
|
164
|
+
* batch-mode interaction (spec §6). The row also gains an accessible
|
|
165
|
+
* pressed affordance (`role="button"` + `aria-pressed`). When omitted
|
|
166
|
+
* or `false`, the row navigates on click as usual; the leading
|
|
167
|
+
* checkbox remains the only selection surface. The checkbox always
|
|
168
|
+
* toggles regardless of this flag (and never bubbles to navigate).
|
|
169
|
+
*/
|
|
170
|
+
readonly rowClickSelects?: boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Table-view column gates (context-configured). Default `true` so every
|
|
173
|
+
* existing call site renders all cells. When `false`, the corresponding
|
|
174
|
+
* `<td>` is omitted entirely (the matching `<th>` is gated in the parent
|
|
175
|
+
* `TableLayout`, so header + cells stay in lock-step). No effect on
|
|
176
|
+
* `view='card'`.
|
|
177
|
+
*/
|
|
178
|
+
readonly showTypeCell?: boolean;
|
|
179
|
+
/** Render the Hardware (manufacturer/model) `<td>` (context-gated). Default
|
|
180
|
+
* `true` so existing call sites render it; the parent `TableLayout` gates the
|
|
181
|
+
* matching `<th>` so header + cell stay in lock-step. No effect on `'card'`. */
|
|
182
|
+
readonly showManufacturerCell?: boolean;
|
|
183
|
+
readonly showFeaturesCell?: boolean;
|
|
108
184
|
}
|
|
109
185
|
export interface VariantDefaults {
|
|
110
186
|
readonly showIntegrationIcon: boolean;
|
|
@@ -117,8 +193,6 @@ export interface VariantDefaults {
|
|
|
117
193
|
readonly showChildrenAccordion: boolean;
|
|
118
194
|
}
|
|
119
195
|
export declare function resolveFlags(props: DeviceItemProps): VariantDefaults;
|
|
120
|
-
export declare const ROLE_ICONS: Readonly<Record<string, LucideIcon>>;
|
|
121
|
-
export declare const TYPE_ICONS: Readonly<Record<string, LucideIcon>>;
|
|
122
196
|
export declare function deviceLeadIcon(device: DeviceItemDevice): LucideIcon;
|
|
123
197
|
/**
|
|
124
198
|
* Icon for each `DeviceFeature` advertised on a device row. Used by
|
|
@@ -153,4 +227,36 @@ export declare const FEATURE_TO_CAP_NAME: Readonly<Record<string, string>>;
|
|
|
153
227
|
export declare function maySupportSwitch(device: DeviceItemDevice): boolean;
|
|
154
228
|
export declare function isAccessoryChild(device: DeviceItemDevice): boolean;
|
|
155
229
|
export declare function hasMotionTriggerFeature(device: DeviceItemDevice): boolean;
|
|
230
|
+
/**
|
|
231
|
+
* Effective online state for a device row's status dot.
|
|
232
|
+
*
|
|
233
|
+
* A CONTAINER device renders AS its PRIMARY child (same row control via
|
|
234
|
+
* `ContainerPrimaryInline`, same hero via `ContainerPrimaryHero`). Its
|
|
235
|
+
* reachability dot should therefore follow that primary child's `online`,
|
|
236
|
+
* NOT "any child online" — so the dot and the control gate agree (the
|
|
237
|
+
* control is bound to the same primary child via `resolveContainerPrimary`).
|
|
238
|
+
*
|
|
239
|
+
* Resolution reuses the SAME `resolveContainerPrimary(children, linkDeviceId)`
|
|
240
|
+
* helper the row control uses, then reads the resolved child row's `online`.
|
|
241
|
+
* Degrades gracefully: a non-container, a container with no children, or a
|
|
242
|
+
* container with no resolvable primary child falls back to `device.online`
|
|
243
|
+
* (never crashes, never forces offline).
|
|
244
|
+
*/
|
|
245
|
+
export declare function effectiveOnline(device: DeviceItemDevice, containerChildren: readonly DeviceItemDevice[] | undefined): boolean;
|
|
246
|
+
/**
|
|
247
|
+
* The type a CONTAINER should DISPLAY as (and be FILTERED by): its primary
|
|
248
|
+
* child's type, since a container renders as that child (a vacuum container
|
|
249
|
+
* should read + filter as `vacuum`, not the structural `container`). Mirrors
|
|
250
|
+
* {@link effectiveOnline} — same primary-child resolution. Non-containers, and
|
|
251
|
+
* containers with no resolvable primary child, fall back to `device.type`.
|
|
252
|
+
*/
|
|
253
|
+
export declare function effectiveType(device: DeviceItemDevice, containerChildren: readonly DeviceItemDevice[] | undefined): string;
|
|
254
|
+
/**
|
|
255
|
+
* The device whose lead ICON a row should display: a Container shows its
|
|
256
|
+
* primary CHILD's icon (the child's type + role drive the glyph, e.g. a vacuum
|
|
257
|
+
* rather than the generic container box). Mirrors {@link effectiveType}, but
|
|
258
|
+
* returns the resolved device so {@link deviceLeadIcon} also picks up the
|
|
259
|
+
* child's role. Falls back to the device itself for non-containers / no primary.
|
|
260
|
+
*/
|
|
261
|
+
export declare function effectiveIconDevice(device: DeviceItemDevice, containerChildren: readonly DeviceItemDevice[] | undefined): DeviceItemDevice;
|
|
156
262
|
export declare function shortStableId(stableId: string): string;
|
|
@@ -2,4 +2,8 @@ import { ReactNode } from 'react';
|
|
|
2
2
|
import { DeviceItemProps } from './helpers';
|
|
3
3
|
export type { DeviceItemDevice, DeviceItemParent, DeviceItemKind, DeviceItemVariant, DeviceItemView, DeviceItemProps, } from './helpers';
|
|
4
4
|
export { deriveDeviceKind } from './helpers';
|
|
5
|
+
export { ChildSectionAccordion } from './child-section-accordion';
|
|
6
|
+
export { ContainerChildrenProvider, useContainerChildren } from './container-children-context';
|
|
7
|
+
export { groupChildrenByLayout } from './child-layout';
|
|
8
|
+
export type { GroupedChildren, ChildLayoutSection } from './child-layout';
|
|
5
9
|
export declare function DeviceItem(props: DeviceItemProps): ReactNode;
|
|
@@ -6,7 +6,7 @@ export interface DeviceItemPreviewProps {
|
|
|
6
6
|
readonly device: DeviceItemDevice;
|
|
7
7
|
readonly status: 'online' | 'offline' | 'disabled';
|
|
8
8
|
/**
|
|
9
|
-
* Render gate for the snapshot
|
|
9
|
+
* Render gate for the snapshot thumbnail (typically
|
|
10
10
|
* `flags.showSnapshot && isCamera` from the orchestrator). Even when
|
|
11
11
|
* `false`, the component still renders the status-pills row when
|
|
12
12
|
* `showStatusPills` is on.
|
|
@@ -14,8 +14,8 @@ export interface DeviceItemPreviewProps {
|
|
|
14
14
|
readonly enabled: boolean;
|
|
15
15
|
/**
|
|
16
16
|
* When true, render the battery / charging / sleeping pills next to
|
|
17
|
-
* the snapshot
|
|
18
|
-
* the natural home for status indicators); off in card view to keep
|
|
17
|
+
* the snapshot thumbnail. Driven by table view (where the Preview cell
|
|
18
|
+
* is the natural home for status indicators); off in card view to keep
|
|
19
19
|
* the row narrow.
|
|
20
20
|
*/
|
|
21
21
|
readonly showStatusPills?: boolean;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { UseDeviceProxyTrpc } from '../../hooks/use-device-proxy';
|
|
3
|
+
export interface RebootQuickActionProps {
|
|
4
|
+
readonly trpc: UseDeviceProxyTrpc;
|
|
5
|
+
readonly deviceId: number;
|
|
6
|
+
/** Device display name — woven into the confirm-modal body. */
|
|
7
|
+
readonly deviceName: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function RebootQuickAction({ trpc, deviceId, deviceName }: RebootQuickActionProps): ReactNode;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
export interface StatusDotProps {
|
|
3
3
|
readonly status: 'online' | 'offline' | 'disabled';
|
|
4
|
+
/** Ms epoch of the last online→offline transition. Only used to enrich
|
|
5
|
+
* the tooltip when `status === 'offline'`. */
|
|
6
|
+
readonly lastChangedAt?: number | null;
|
|
4
7
|
}
|
|
5
|
-
export declare function StatusDot({ status }: StatusDotProps): ReactNode;
|
|
8
|
+
export declare function StatusDot({ status, lastChangedAt }: StatusDotProps): ReactNode;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface DeviceBatchActionsBarProps {
|
|
3
|
+
readonly selectedIds: ReadonlySet<number>;
|
|
4
|
+
readonly onClear: () => void;
|
|
5
|
+
readonly remove: (input: {
|
|
6
|
+
deviceId: number;
|
|
7
|
+
}) => void;
|
|
8
|
+
readonly disable: (input: {
|
|
9
|
+
deviceId: number;
|
|
10
|
+
}) => void;
|
|
11
|
+
readonly enable: (input: {
|
|
12
|
+
deviceId: number;
|
|
13
|
+
}) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare function DeviceBatchActionsBar(props: DeviceBatchActionsBarProps): ReactNode;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface DeviceBatchToolbarProps {
|
|
3
|
+
readonly selectedIds: ReadonlySet<number>;
|
|
4
|
+
readonly onClear: () => void;
|
|
5
|
+
readonly remove: (input: {
|
|
6
|
+
deviceId: number;
|
|
7
|
+
}) => void;
|
|
8
|
+
readonly disable: (input: {
|
|
9
|
+
deviceId: number;
|
|
10
|
+
}) => void;
|
|
11
|
+
readonly enable: (input: {
|
|
12
|
+
deviceId: number;
|
|
13
|
+
}) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare function DeviceBatchToolbar({ selectedIds, onClear, remove, disable, enable, }: DeviceBatchToolbarProps): ReactNode;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { UseDeviceProxyTrpc } from '../../hooks/use-device-proxy';
|
|
3
|
+
import { DeviceItemDevice, DeviceItemParent } from '../device-item/helpers';
|
|
4
|
+
export interface CardsLayoutProps {
|
|
5
|
+
readonly rows: readonly DeviceItemDevice[];
|
|
6
|
+
readonly accessoriesByParent: ReadonlyMap<number, readonly DeviceItemDevice[]>;
|
|
7
|
+
readonly trpc: UseDeviceProxyTrpc;
|
|
8
|
+
readonly resolveIntegrationIcon: ((addonId: string) => ReactNode | null) | null;
|
|
9
|
+
readonly resolveParent: ((parentId: number) => DeviceItemParent | null) | null;
|
|
10
|
+
readonly onNavigate: ((deviceId: number) => void) | null;
|
|
11
|
+
readonly renderRowAction: ((device: DeviceItemDevice) => ReactNode) | null;
|
|
12
|
+
readonly selectable: boolean;
|
|
13
|
+
/** Batch mode active — a row click toggles selection instead of navigating. */
|
|
14
|
+
readonly rowClickSelects: boolean;
|
|
15
|
+
readonly activeSelected: ReadonlySet<number>;
|
|
16
|
+
readonly onToggleSelection: (id: number) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare function CardsLayout({ rows, accessoriesByParent, trpc, resolveIntegrationIcon, resolveParent, onNavigate, renderRowAction, selectable, rowClickSelects, activeSelected, onToggleSelection, }: CardsLayoutProps): ReactNode;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Device-mode column model: a fixed catalog, a per-context subset matrix,
|
|
3
|
+
* a responsive priority, and a priority-derived breakpoint mapping. Each
|
|
4
|
+
* consumer declares its `TableContext`; the table renders only the columns
|
|
5
|
+
* that context enables, in catalog order, hiding the optional ones as the
|
|
6
|
+
* viewport narrows.
|
|
7
|
+
*
|
|
8
|
+
* The catalog is intentionally device-mode only. Generic-mode (integration
|
|
9
|
+
* rows) keeps its own `DeviceListColumn[]` defs — reconciled in a later phase.
|
|
10
|
+
*
|
|
11
|
+
* ── Responsive convention (single source of truth) ────────────────────────
|
|
12
|
+
* LOWER priority number = MORE important = hidden at a NARROWER width (kept
|
|
13
|
+
* longest). So as the viewport shrinks the HIGHEST-priority-number column
|
|
14
|
+
* drops first.
|
|
15
|
+
*
|
|
16
|
+
* name (0) — never hidden; sticky left, always visible
|
|
17
|
+
* previewActions (1) — never hidden; carries the live control + status dot
|
|
18
|
+
* icon (2) — integration badge; rendered INSIDE the name cell,
|
|
19
|
+
* not a standalone column, so it has no breakpoint
|
|
20
|
+
* features (3) — optional; hidden below `md` (kept longer)
|
|
21
|
+
* type (4) — optional; hidden below `lg`
|
|
22
|
+
* manufacturer (5) — optional; hidden below `xl` (drops FIRST,
|
|
23
|
+
* wide-screen-only hardware/identity column)
|
|
24
|
+
*
|
|
25
|
+
* `COLUMN_BREAKPOINT_CLASS` derives ONE Tailwind visibility class per id and
|
|
26
|
+
* is the single source used by BOTH the `<th>` and the `<td>`, so a hidden
|
|
27
|
+
* column folds header + cell in lock-step. The drop order is therefore:
|
|
28
|
+
* `manufacturer` first (below `xl`), then `type` (below `lg`), then
|
|
29
|
+
* `features` (below `md`) — matching the priority numbers above.
|
|
30
|
+
*/
|
|
31
|
+
/** Fixed device-mode column catalog, in render order. `name` is always first.
|
|
32
|
+
* `manufacturer` sits after `type` — a wide-screen-only hardware/identity
|
|
33
|
+
* column (manufacturer · model, full metadata in a tooltip). */
|
|
34
|
+
export declare const DEVICE_COLUMNS: readonly ["name", "icon", "type", "manufacturer", "features", "previewActions"];
|
|
35
|
+
export type DeviceColumnId = (typeof DEVICE_COLUMNS)[number];
|
|
36
|
+
/**
|
|
37
|
+
* The places a device table is rendered; each declares its column subset.
|
|
38
|
+
*
|
|
39
|
+
* Device-detail CHILDREN are deliberately NOT a table context: they render as
|
|
40
|
+
* a stack of `<DeviceItem variant="minimal">` cards (see `ChildrenList`), not
|
|
41
|
+
* through this table, so no `device-children` context exists.
|
|
42
|
+
*/
|
|
43
|
+
export type TableContext = 'devices' | 'integration-detail';
|
|
44
|
+
export declare function columnsForContext(ctx: TableContext): readonly DeviceColumnId[];
|
|
45
|
+
/**
|
|
46
|
+
* Lower number = higher priority (kept longest as width shrinks). `name` = 0
|
|
47
|
+
* (sticky, never dropped); `previewActions` = 1 (always visible). The optional
|
|
48
|
+
* columns drop in REVERSE priority order as width shrinks — highest number
|
|
49
|
+
* (`type`) hides first, then `features`. `icon` is a name-cell badge, not a
|
|
50
|
+
* standalone column. See `COLUMN_BREAKPOINT_CLASS` for the derived classes.
|
|
51
|
+
*/
|
|
52
|
+
export declare const COLUMN_PRIORITY: Record<DeviceColumnId, number>;
|
|
53
|
+
/**
|
|
54
|
+
* Priority-derived Tailwind visibility class per column. Used by BOTH the
|
|
55
|
+
* `<th>` and the `<td>` (single source → header + cell stay in lock-step).
|
|
56
|
+
*
|
|
57
|
+
* - `name` / `previewActions`: empty string — never hidden (always visible).
|
|
58
|
+
* - `icon`: empty string — rendered inside the name cell, no standalone cell.
|
|
59
|
+
* - `features`: `hidden md:table-cell` — visible from `md` up (kept longer).
|
|
60
|
+
* - `type`: `hidden lg:table-cell` — visible only from `lg` up.
|
|
61
|
+
* - `manufacturer`: `hidden xl:table-cell` — visible only from `xl` up (drops
|
|
62
|
+
* first).
|
|
63
|
+
*
|
|
64
|
+
* Drop order as the viewport narrows therefore follows the priority numbers:
|
|
65
|
+
* `manufacturer` (5) disappears below `xl`, then `type` (4) below `lg`, then
|
|
66
|
+
* `features` (3) below `md`.
|
|
67
|
+
*/
|
|
68
|
+
export declare const COLUMN_BREAKPOINT_CLASS: Record<DeviceColumnId, string>;
|