@camstack/ui-library 0.1.38 → 0.1.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/dist/composites/addon-global-settings-form.d.ts +60 -0
  2. package/dist/composites/addon-page-props.d.ts +12 -0
  3. package/dist/composites/agent-step-editor.d.ts +15 -0
  4. package/dist/composites/app-shell/app-shell.d.ts +19 -0
  5. package/dist/composites/app-shell/index.d.ts +3 -0
  6. package/dist/composites/app-shell/sidebar-item.d.ts +10 -0
  7. package/dist/composites/app-shell/sidebar.d.ts +14 -0
  8. package/dist/composites/audio-classification-list.d.ts +20 -0
  9. package/dist/composites/audio-level-waveform.d.ts +35 -0
  10. package/dist/composites/audio-waveform.d.ts +20 -0
  11. package/dist/composites/battery-badge.d.ts +12 -0
  12. package/dist/composites/breadcrumb.d.ts +25 -0
  13. package/dist/composites/camera-stream-player.d.ts +87 -0
  14. package/dist/composites/code-block.d.ts +6 -0
  15. package/dist/composites/config-form-builder.d.ts +18 -0
  16. package/dist/composites/config-form-field.d.ts +70 -0
  17. package/dist/composites/confirm-action-button.d.ts +41 -0
  18. package/dist/composites/confirm-dialog.d.ts +13 -0
  19. package/dist/composites/data-table/data-table-header.d.ts +10 -0
  20. package/dist/composites/data-table/data-table-pagination.d.ts +9 -0
  21. package/dist/composites/data-table/data-table-row.d.ts +10 -0
  22. package/dist/composites/data-table/data-table.d.ts +2 -0
  23. package/dist/composites/data-table/index.d.ts +2 -0
  24. package/dist/composites/data-table/types.d.ts +34 -0
  25. package/dist/composites/data-table.d.ts +37 -0
  26. package/dist/composites/detection-canvas.d.ts +29 -0
  27. package/dist/composites/detection-colors.d.ts +15 -0
  28. package/dist/composites/detection-overlay.d.ts +9 -0
  29. package/dist/composites/detection-result-tree.d.ts +11 -0
  30. package/dist/composites/dev-shell.d.ts +20 -0
  31. package/dist/composites/device-activity-panel.d.ts +29 -0
  32. package/dist/composites/device-card.d.ts +38 -0
  33. package/dist/composites/device-grid.d.ts +12 -0
  34. package/dist/composites/device-item/actions.d.ts +9 -0
  35. package/dist/composites/device-item/children-accordion.d.ts +11 -0
  36. package/dist/composites/device-item/features.d.ts +17 -0
  37. package/dist/composites/device-item/header.d.ts +14 -0
  38. package/dist/composites/device-item/helpers.d.ts +147 -0
  39. package/dist/composites/device-item/index.d.ts +5 -0
  40. package/dist/composites/device-item/preview.d.ts +23 -0
  41. package/dist/composites/device-item/status-dot.d.ts +5 -0
  42. package/dist/composites/device-list/empty-state.d.ts +6 -0
  43. package/dist/composites/device-list/filter-chips.d.ts +19 -0
  44. package/dist/composites/device-list/group.d.ts +6 -0
  45. package/dist/composites/device-list/index.d.ts +31 -0
  46. package/dist/composites/device-list/pagination.d.ts +18 -0
  47. package/dist/composites/device-list/url-state.d.ts +24 -0
  48. package/dist/composites/discovery-panel.d.ts +26 -0
  49. package/dist/composites/doorbell-recent-panel.d.ts +10 -0
  50. package/dist/composites/empty-state.d.ts +10 -0
  51. package/dist/composites/event-stream.d.ts +48 -0
  52. package/dist/composites/filter-bar.d.ts +28 -0
  53. package/dist/composites/form-field.d.ts +11 -0
  54. package/dist/composites/image-selector.d.ts +25 -0
  55. package/dist/composites/index.d.ts +99 -0
  56. package/dist/composites/inference-config-selector.d.ts +44 -0
  57. package/dist/composites/kebab-menu.d.ts +39 -0
  58. package/dist/composites/key-value-list.d.ts +9 -0
  59. package/dist/composites/log-stream.d.ts +61 -0
  60. package/dist/composites/login-form.d.ts +8 -0
  61. package/dist/composites/mount-addon-page.d.ts +16 -0
  62. package/dist/composites/node-picker.d.ts +15 -0
  63. package/dist/composites/page-header.d.ts +8 -0
  64. package/dist/composites/phase-icon.d.ts +5 -0
  65. package/dist/composites/pipeline-builder.d.ts +43 -0
  66. package/dist/composites/pipeline-runtime-selector.d.ts +16 -0
  67. package/dist/composites/pipeline-step.d.ts +65 -0
  68. package/dist/composites/pipeline-tree-matrix.d.ts +31 -0
  69. package/dist/composites/provider-badge.d.ts +7 -0
  70. package/dist/composites/ptz-overlay.d.ts +20 -0
  71. package/dist/composites/response-log.d.ts +9 -0
  72. package/dist/composites/slide-over-panel.d.ts +11 -0
  73. package/dist/composites/snapshot-button.d.ts +25 -0
  74. package/dist/composites/stat-card.d.ts +10 -0
  75. package/dist/composites/state-values-stream.d.ts +30 -0
  76. package/dist/composites/status-badge.d.ts +10 -0
  77. package/dist/composites/step-timings.d.ts +9 -0
  78. package/dist/composites/step-tree-master.d.ts +28 -0
  79. package/dist/composites/stream-panel.d.ts +143 -0
  80. package/dist/composites/version-badge.d.ts +24 -0
  81. package/dist/composites/widget-slot.d.ts +20 -0
  82. package/dist/contexts/custom-field-renderers.d.ts +26 -0
  83. package/dist/contexts/device-context.d.ts +20 -0
  84. package/dist/contexts/player-overlays.d.ts +56 -0
  85. package/dist/contexts/system-context.d.ts +19 -0
  86. package/dist/contexts/widget-registry.d.ts +68 -0
  87. package/dist/contexts/zone-editing.d.ts +59 -0
  88. package/dist/generated/system-hooks.d.ts +933 -0
  89. package/dist/hooks/index.d.ts +27 -0
  90. package/dist/hooks/use-cluster-nodes.d.ts +17 -0
  91. package/dist/hooks/use-debounced-string.d.ts +1 -0
  92. package/dist/hooks/use-device-battery.d.ts +14 -0
  93. package/dist/hooks/use-device-capability.d.ts +17 -0
  94. package/dist/hooks/use-device-detections.d.ts +50 -0
  95. package/dist/hooks/use-device-features.d.ts +25 -0
  96. package/dist/hooks/use-device-proxy.d.ts +106 -0
  97. package/dist/hooks/use-device-snapshot.d.ts +10 -0
  98. package/dist/hooks/use-device-webrtc.d.ts +108 -0
  99. package/dist/hooks/use-devices.d.ts +13 -0
  100. package/dist/hooks/use-doorbell-events.d.ts +20 -0
  101. package/dist/hooks/use-event-invalidation.d.ts +1 -0
  102. package/dist/hooks/use-event-stream.d.ts +5 -0
  103. package/dist/hooks/use-is-mobile.d.ts +8 -0
  104. package/dist/hooks/use-live-buffer.d.ts +8 -0
  105. package/dist/hooks/use-live-event.d.ts +3 -0
  106. package/dist/hooks/use-ptz.d.ts +54 -0
  107. package/dist/hooks/use-system-query.d.ts +12 -0
  108. package/dist/icons/index.d.ts +2 -0
  109. package/dist/icons/provider-icons.d.ts +3 -0
  110. package/dist/icons/status-icons.d.ts +3 -0
  111. package/dist/index.cjs +24217 -3992
  112. package/dist/index.cjs.map +1 -1
  113. package/dist/index.d.ts +14 -744
  114. package/dist/index.js +23553 -3936
  115. package/dist/index.js.map +1 -1
  116. package/dist/lib/cn.d.ts +2 -0
  117. package/dist/lib/index.d.ts +8 -0
  118. package/dist/lib/mf-runtime-init.d.ts +1 -0
  119. package/dist/lib/phase-config.d.ts +16 -0
  120. package/dist/lib/pipeline-mirror.d.ts +23 -0
  121. package/dist/lib/responsive.d.ts +81 -0
  122. package/dist/lib/shared-context.d.ts +5 -0
  123. package/dist/lib/validate-template.d.ts +2 -0
  124. package/dist/primitives/badge.d.ts +11 -0
  125. package/dist/primitives/bottom-sheet.d.ts +9 -0
  126. package/dist/primitives/button.d.ts +10 -0
  127. package/dist/primitives/card.d.ts +9 -0
  128. package/dist/primitives/checkbox.d.ts +4 -0
  129. package/dist/primitives/collapsible-card.d.ts +15 -0
  130. package/dist/primitives/dialog.d.ts +20 -0
  131. package/dist/primitives/dropdown.d.ts +19 -0
  132. package/dist/primitives/floating-panel.d.ts +22 -0
  133. package/dist/primitives/icon-button.d.ts +13 -0
  134. package/dist/primitives/index.d.ts +21 -0
  135. package/dist/primitives/input.d.ts +11 -0
  136. package/dist/primitives/label.d.ts +4 -0
  137. package/dist/primitives/mobile-drawer.d.ts +10 -0
  138. package/dist/primitives/popover.d.ts +10 -0
  139. package/dist/primitives/scroll-area.d.ts +4 -0
  140. package/dist/primitives/select.d.ts +9 -0
  141. package/dist/primitives/separator.d.ts +9 -0
  142. package/dist/primitives/skeleton.d.ts +4 -0
  143. package/dist/primitives/switch.d.ts +7 -0
  144. package/dist/primitives/tabs.d.ts +17 -0
  145. package/dist/primitives/tooltip.d.ts +6 -0
  146. package/dist/theme/create-theme.d.ts +2 -0
  147. package/dist/theme/defaults.d.ts +4 -0
  148. package/dist/theme/index.cjs +230 -250
  149. package/dist/theme/index.cjs.map +1 -1
  150. package/dist/theme/index.d.ts +6 -128
  151. package/dist/theme/index.js +214 -216
  152. package/dist/theme/index.js.map +1 -1
  153. package/dist/theme/theme-provider.d.ts +10 -0
  154. package/dist/theme/theme-to-css.d.ts +2 -0
  155. package/dist/theme/{index.d.cts → types.d.ts} +5 -27
  156. package/dist/theme/use-theme-mode.d.ts +2 -0
  157. package/dist/trpc-react.d.ts +7 -0
  158. package/package.json +23 -4
  159. package/dist/index.d.cts +0 -744
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Detection class colors — single source of truth.
3
+ *
4
+ * Used by: DetectionCanvas (UI), result-annotator (server-side SVG),
5
+ * admin-ui event viewer, and any other place that visualizes detections.
6
+ */
7
+ /** Fixed colors for known detection classes */
8
+ export declare const CLASS_COLORS: Readonly<Record<string, string>>;
9
+ /** Primary/default color when nothing else matches */
10
+ export declare const DEFAULT_COLOR = "#f59e42";
11
+ /**
12
+ * Get the color for a detection class name.
13
+ * Returns a fixed color for known classes, or a deterministic hash-based color for unknown ones.
14
+ */
15
+ export declare function getClassColor(className: string, customColors?: Readonly<Record<string, string>>): string;
@@ -0,0 +1,9 @@
1
+ import { DeviceDetections } from '../hooks/use-device-detections';
2
+ export interface DetectionOverlayProps {
3
+ readonly detections: DeviceDetections;
4
+ readonly showMotionZones?: boolean;
5
+ readonly showMotionRaw?: boolean;
6
+ readonly showDetections?: boolean;
7
+ readonly showPhaseIndicator?: boolean;
8
+ }
9
+ export declare function DetectionOverlay({ detections: { motion, motionRaw, detection, phase }, showMotionZones, showMotionRaw, showDetections, showPhaseIndicator, }: DetectionOverlayProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,11 @@
1
+ import { ObjectDetection } from '@camstack/types';
2
+ export interface DetectionResultTreeProps {
3
+ readonly detections: readonly ObjectDetection[];
4
+ readonly classColors?: Readonly<Record<string, string>>;
5
+ readonly className?: string;
6
+ /** Set of detection ids that are hidden */
7
+ readonly hiddenKeys?: ReadonlySet<string>;
8
+ /** Callback when a detection's visibility is toggled */
9
+ readonly onToggleVisibility?: (key: string, visible: boolean) => void;
10
+ }
11
+ export declare function DetectionResultTree({ detections, classColors, className, hiddenKeys, onToggleVisibility, }: DetectionResultTreeProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { ReactNode } from 'react';
2
+ import { TRPCClient } from '@trpc/client';
3
+ import { AppRouter } from '@camstack/types';
4
+ import { UseThemeModeReturn } from '../theme/types';
5
+ export interface DevShellProps {
6
+ children: (props: {
7
+ trpc: TRPCClient<AppRouter>;
8
+ theme: UseThemeModeReturn;
9
+ }) => ReactNode;
10
+ serverUrl?: string;
11
+ title?: string;
12
+ }
13
+ interface DevShellContextValue {
14
+ trpc: TRPCClient<AppRouter>;
15
+ token: string;
16
+ logout: () => void;
17
+ }
18
+ export declare function useDevShell(): DevShellContextValue;
19
+ export declare function DevShell({ children, serverUrl, title, }: DevShellProps): import("react/jsx-runtime").JSX.Element;
20
+ export {};
@@ -0,0 +1,29 @@
1
+ export interface DeviceActivityPanelProps {
2
+ readonly deviceId: number;
3
+ /** Initial event categories the user wants tracked. Defaults to "all". */
4
+ readonly defaultEventCategories?: readonly string[];
5
+ /** Initial state-cap whitelist. Empty = show every cap that fires. */
6
+ readonly defaultStateCaps?: readonly string[];
7
+ /** Tab to show first. */
8
+ readonly initialTab?: ActivityTabId;
9
+ /** CSS class for the panel root. */
10
+ readonly className?: string;
11
+ /** Max content height (passed to the active stream). */
12
+ readonly maxHeight?: string;
13
+ }
14
+ declare const TABS: readonly [{
15
+ readonly id: "logs";
16
+ readonly label: "Logs";
17
+ readonly icon: import('react').ForwardRefExoticComponent<Omit<import('lucide-react').LucideProps, "ref"> & import('react').RefAttributes<SVGSVGElement>>;
18
+ }, {
19
+ readonly id: "events";
20
+ readonly label: "Events";
21
+ readonly icon: import('react').ForwardRefExoticComponent<Omit<import('lucide-react').LucideProps, "ref"> & import('react').RefAttributes<SVGSVGElement>>;
22
+ }, {
23
+ readonly id: "state";
24
+ readonly label: "State";
25
+ readonly icon: import('react').ForwardRefExoticComponent<Omit<import('lucide-react').LucideProps, "ref"> & import('react').RefAttributes<SVGSVGElement>>;
26
+ }];
27
+ export type ActivityTabId = (typeof TABS)[number]['id'];
28
+ export declare function DeviceActivityPanel({ deviceId, defaultEventCategories, defaultStateCaps, initialTab, className, maxHeight, }: DeviceActivityPanelProps): import("react/jsx-runtime").JSX.Element;
29
+ export {};
@@ -0,0 +1,38 @@
1
+ import { ReactNode } from 'react';
2
+ export interface DeviceCardBadge {
3
+ /** Badge label text */
4
+ label: string;
5
+ /** Optional icon rendered before the label */
6
+ icon?: ReactNode;
7
+ /** Click handler — makes the badge interactive */
8
+ onClick?: () => void;
9
+ }
10
+ export interface DeviceCardAction {
11
+ /** Icon to render */
12
+ icon: ReactNode;
13
+ /** Tooltip / aria-label */
14
+ label: string;
15
+ /** Click handler */
16
+ onClick: () => void;
17
+ }
18
+ export interface DeviceCardProps {
19
+ /** Primary title (e.g., device name) */
20
+ title: string;
21
+ /** Secondary text (e.g., model, IP) */
22
+ subtitle?: string;
23
+ /** Status: determines the color of the status dot */
24
+ status?: 'online' | 'offline' | 'warning' | 'unknown';
25
+ /** Whether this card is currently selected */
26
+ selected?: boolean;
27
+ /** Click handler for the card body */
28
+ onClick?: () => void;
29
+ /** Clickable badges (e.g., stream profiles) */
30
+ badges?: DeviceCardBadge[];
31
+ /** Action icons shown at the bottom (e.g., PTZ, events) */
32
+ actions?: DeviceCardAction[];
33
+ /** Content rendered at the bottom when status is offline (e.g., Connect button) */
34
+ offlineAction?: ReactNode;
35
+ /** Additional CSS classes */
36
+ className?: string;
37
+ }
38
+ export declare function DeviceCard({ title, subtitle, status, selected, onClick, badges, actions, offlineAction, className, }: DeviceCardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { ReactNode } from 'react';
2
+ export interface DeviceGridProps {
3
+ /** Grid items */
4
+ children: ReactNode;
5
+ /** Minimum card width in pixels (default 220) */
6
+ minCardWidth?: number;
7
+ /** Gap between cards in Tailwind spacing units (default 3) */
8
+ gap?: number;
9
+ /** Additional CSS classes */
10
+ className?: string;
11
+ }
12
+ export declare function DeviceGrid({ children, minCardWidth, gap, className, }: DeviceGridProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { ReactNode } from 'react';
2
+ import { UseDeviceProxyTrpc } from '../../hooks/use-device-proxy';
3
+ import { DeviceItemDevice, VariantDefaults } from './helpers';
4
+ export interface DeviceItemActionsProps {
5
+ readonly trpc: UseDeviceProxyTrpc;
6
+ readonly device: DeviceItemDevice;
7
+ readonly flags: VariantDefaults;
8
+ }
9
+ export declare function DeviceItemActions({ trpc, device, flags }: DeviceItemActionsProps): ReactNode;
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from 'react';
2
+ import { UseDeviceProxyTrpc } from '../../hooks/use-device-proxy';
3
+ import { DeviceItemDevice } from './helpers';
4
+ interface ChildrenAccordionProps {
5
+ readonly trpc: UseDeviceProxyTrpc;
6
+ readonly accessoryChildren: readonly DeviceItemDevice[];
7
+ readonly adoptedChildren: readonly DeviceItemDevice[];
8
+ readonly onNavigate: (id: number) => void;
9
+ }
10
+ export declare function ChildrenAccordion({ trpc, accessoryChildren, adoptedChildren, onNavigate }: ChildrenAccordionProps): ReactNode;
11
+ export {};
@@ -0,0 +1,17 @@
1
+ import { ReactNode } from 'react';
2
+ import { UseDeviceProxyTrpc } from '../../hooks/use-device-proxy';
3
+ import { DeviceItemDevice, VariantDefaults } from './helpers';
4
+ export interface DeviceItemFeaturesProps {
5
+ readonly trpc: UseDeviceProxyTrpc;
6
+ readonly device: DeviceItemDevice;
7
+ readonly flags: VariantDefaults;
8
+ readonly accessoryCount: number;
9
+ readonly adoptedCount: number;
10
+ /**
11
+ * When true, render the feature-icon row + popover (table view's
12
+ * "Features" column). Off in card view — only battery + +N badge
13
+ * to save horizontal space.
14
+ */
15
+ readonly showFeatureRow?: boolean;
16
+ }
17
+ export declare function DeviceItemFeatures({ trpc, device, flags, accessoryCount, adoptedCount, showFeatureRow, }: DeviceItemFeaturesProps): ReactNode;
@@ -0,0 +1,14 @@
1
+ import { ReactNode } from 'react';
2
+ import { DeviceItemDevice, DeviceItemParent, DeviceItemVariant, VariantDefaults } from './helpers';
3
+ export interface DeviceItemHeaderProps {
4
+ readonly device: DeviceItemDevice;
5
+ readonly variant: DeviceItemVariant;
6
+ readonly flags: VariantDefaults;
7
+ readonly parent: DeviceItemParent | null;
8
+ readonly integrationIcon: ReactNode | null;
9
+ readonly hasChildren: boolean;
10
+ readonly expanded: boolean;
11
+ readonly onToggleExpand: () => void;
12
+ readonly onNavigateToParent: (id: number) => void;
13
+ }
14
+ export declare function DeviceItemHeader({ device, variant, flags, parent, integrationIcon, hasChildren, expanded, onToggleExpand, onNavigateToParent, }: DeviceItemHeaderProps): ReactNode;
@@ -0,0 +1,147 @@
1
+ import { ReactNode } from 'react';
2
+ import { LucideIcon } from 'lucide-react';
3
+ import { UseDeviceProxyTrpc } from '../../hooks/use-device-proxy';
4
+ /**
5
+ * Mirror of the canonical `DeviceInfo` wire shape (see
6
+ * `packages/types/src/capabilities/device-manager.cap.ts`). Every
7
+ * `deviceManager.listAll` / `getDevice` / `getChildren` row is
8
+ * already this exact shape — call sites pass the raw row through
9
+ * without remapping. Lives here as a structural type (not an
10
+ * import) so this composite stays decoupled from `@camstack/types`.
11
+ */
12
+ export interface DeviceItemDevice {
13
+ readonly id: number;
14
+ readonly stableId: string;
15
+ readonly addonId: string;
16
+ readonly type: string;
17
+ readonly name: string;
18
+ readonly online: boolean;
19
+ /** Soft-disable flag — `true` dims the row + skips live fetches.
20
+ * Matches `DeviceInfo.disabled` so the wire row passes through. */
21
+ readonly disabled: boolean;
22
+ readonly parentDeviceId: number | null;
23
+ /** Optional `DeviceRole` string. Present ⇒ this is an accessory. */
24
+ readonly role?: string | null;
25
+ /** DeviceFeature strings — gates BatteryBadge etc. */
26
+ readonly features?: readonly string[];
27
+ /** True for ICameraDevice instances — gates snapshot popover. */
28
+ readonly isCamera?: boolean;
29
+ }
30
+ export interface DeviceItemParent {
31
+ readonly id: number;
32
+ readonly name: string;
33
+ /**
34
+ * Type of the parent device. Optional — when provided, callers can
35
+ * distinguish "adopted under a hub/nvr" (renders with extra indent in
36
+ * the table view) from a generic accessory parent.
37
+ */
38
+ readonly type?: string;
39
+ }
40
+ export type DeviceItemKind = 'top-level' | 'adopted' | 'accessory';
41
+ export declare function deriveDeviceKind(device: Pick<DeviceItemDevice, 'parentDeviceId' | 'role'>): DeviceItemKind;
42
+ export type DeviceItemVariant = 'minimal' | 'compact' | 'expanded';
43
+ export type DeviceItemView = 'card' | 'table';
44
+ export interface DeviceItemProps {
45
+ readonly trpc: UseDeviceProxyTrpc;
46
+ readonly device: DeviceItemDevice;
47
+ readonly variant?: DeviceItemVariant;
48
+ /**
49
+ * Render mode. `'card'` (default) = flex row + optional accordion
50
+ * below. `'table'` = `<tr>` with one `<td>` per logical column.
51
+ * Phase 2's `<DeviceList>` wrapper drives this prop; Phase 1
52
+ * scaffolds both branches with no current consumer using table.
53
+ */
54
+ readonly view?: DeviceItemView;
55
+ /**
56
+ * When true, the row is rendered as an accessory of a parent (Phase 2
57
+ * nested-only mode). Adds a subtle background tint + indent on the
58
+ * first cell. Has no effect on `view='card'`. Caller provides `true`
59
+ * only for the accessory passes inside <DeviceList>.
60
+ */
61
+ readonly isAccessoryRow?: boolean;
62
+ /**
63
+ * Indent level for the `<td>` first cell in `view='table'`. Controls
64
+ * `pl-N` on the name cell so adopted-under-hub rows can be visually
65
+ * nested below their parent without forcing the accessory tint.
66
+ *
67
+ * 0 → `pl-2` (top-level, no parent)
68
+ * 1 → `pl-6` (adopted under a hub/nvr — visual hierarchy hint)
69
+ * 2 → `pl-8` (accessory under any parent — strongest indent)
70
+ *
71
+ * When omitted, the orchestrator derives `2` from `isAccessoryRow` and
72
+ * otherwise defaults to `0`. Caller may override (e.g. <DeviceList>
73
+ * promoting "adopted-under-hub" rows from 0 → 1).
74
+ */
75
+ readonly indentLevel?: 0 | 1 | 2;
76
+ /**
77
+ * Controlled expand state for the children-accordion chevron. When
78
+ * BOTH `expanded` and `onToggleExpand` are passed, DeviceItem becomes
79
+ * fully controlled; otherwise it falls back to internal state. Used
80
+ * by `<TableRowGroup>` to lift expand state to the parent so the
81
+ * accessory `<tr>` rows can render based on the same flag the chevron
82
+ * flips.
83
+ */
84
+ readonly expanded?: boolean;
85
+ readonly onToggleExpand?: () => void;
86
+ readonly integrationIcon?: ReactNode;
87
+ readonly parent?: DeviceItemParent | null;
88
+ readonly showIntegrationIcon?: boolean;
89
+ readonly showParentBadge?: boolean;
90
+ readonly showSnapshot?: boolean;
91
+ readonly showBattery?: boolean;
92
+ readonly showStableId?: boolean;
93
+ readonly showId?: boolean;
94
+ readonly showSwitchToggle?: boolean;
95
+ readonly showChildrenAccordion?: boolean;
96
+ readonly children?: readonly DeviceItemDevice[];
97
+ readonly onNavigate?: (deviceId: number) => void;
98
+ readonly className?: string;
99
+ }
100
+ export interface VariantDefaults {
101
+ readonly showIntegrationIcon: boolean;
102
+ readonly showParentBadge: boolean;
103
+ readonly showSnapshot: boolean;
104
+ readonly showBattery: boolean;
105
+ readonly showStableId: boolean;
106
+ readonly showId: boolean;
107
+ readonly showSwitchToggle: boolean;
108
+ readonly showChildrenAccordion: boolean;
109
+ }
110
+ export declare function resolveFlags(props: DeviceItemProps): VariantDefaults;
111
+ export declare const ROLE_ICONS: Readonly<Record<string, LucideIcon>>;
112
+ export declare const TYPE_ICONS: Readonly<Record<string, LucideIcon>>;
113
+ export declare function deviceLeadIcon(device: DeviceItemDevice): LucideIcon;
114
+ /**
115
+ * Icon for each `DeviceFeature` advertised on a device row. Used by
116
+ * the features popover (`<DeviceItemFeatures>`) to render compact
117
+ * feature chips. Keys mirror `DeviceFeature` enum string values from
118
+ * `@camstack/types/device/device-type.ts`.
119
+ */
120
+ export declare const FEATURE_ICON_MAP: Readonly<Record<string, LucideIcon>>;
121
+ export declare const FEATURE_LABEL_MAP: Readonly<Record<string, string>>;
122
+ /**
123
+ * Maps a wire-level `DeviceFeature` string to the cap name registered
124
+ * in `deviceManager.getBindings` entries. A feature with NO entry here
125
+ * is a pure informational marker (no cap to interrogate) — render but
126
+ * without a native/enhanced label.
127
+ *
128
+ * Source of truth: live `getBindings` capNames observed against a
129
+ * Reolink camera (snapshot, reboot, ptz, ptz-autotrack, intercom,
130
+ * motion-trigger). Cap-name strings cross-checked against the
131
+ * `name:` fields in `packages/types/src/capabilities/*.cap.ts`. When
132
+ * a new feature ↔ cap pairing goes live, add the row here so the
133
+ * popover picks it up.
134
+ *
135
+ * Pure markers (no cap to bind, intentionally absent):
136
+ * - `battery-operated` — exposed as a plain `device.features` flag;
137
+ * the runtime-state slice lives under the `battery` cap which has
138
+ * its own dedicated reactive surface (`useDeviceBattery`).
139
+ * - `doorbell-button` — UI marker only; the actual press events
140
+ * flow through the `doorbell` cap which is already exercised by
141
+ * `useDoorbellEvents`. Distinct from the marker.
142
+ */
143
+ export declare const FEATURE_TO_CAP_NAME: Readonly<Record<string, string>>;
144
+ export declare function maySupportSwitch(device: DeviceItemDevice): boolean;
145
+ export declare function isAccessoryChild(device: DeviceItemDevice): boolean;
146
+ export declare function hasMotionTriggerFeature(device: DeviceItemDevice): boolean;
147
+ export declare function shortStableId(stableId: string): string;
@@ -0,0 +1,5 @@
1
+ import { ReactNode } from 'react';
2
+ import { DeviceItemProps } from './helpers';
3
+ export type { DeviceItemDevice, DeviceItemParent, DeviceItemKind, DeviceItemVariant, DeviceItemView, DeviceItemProps, } from './helpers';
4
+ export { deriveDeviceKind } from './helpers';
5
+ export declare function DeviceItem(props: DeviceItemProps): ReactNode;
@@ -0,0 +1,23 @@
1
+ import { ReactNode } from 'react';
2
+ import { UseDeviceProxyTrpc } from '../../hooks/use-device-proxy';
3
+ import { DeviceItemDevice } from './helpers';
4
+ export interface DeviceItemPreviewProps {
5
+ readonly trpc: UseDeviceProxyTrpc;
6
+ readonly device: DeviceItemDevice;
7
+ readonly status: 'online' | 'offline' | 'disabled';
8
+ /**
9
+ * Render gate for the snapshot eye icon (typically
10
+ * `flags.showSnapshot && isCamera` from the orchestrator). Even when
11
+ * `false`, the component still renders the status-pills row when
12
+ * `showStatusPills` is on.
13
+ */
14
+ readonly enabled: boolean;
15
+ /**
16
+ * When true, render the battery / charging / sleeping pills next to
17
+ * the snapshot eye. Driven by table view (where the Preview cell is
18
+ * the natural home for status indicators); off in card view to keep
19
+ * the row narrow.
20
+ */
21
+ readonly showStatusPills?: boolean;
22
+ }
23
+ export declare function DeviceItemPreview({ trpc, device, status, enabled, showStatusPills, }: DeviceItemPreviewProps): ReactNode;
@@ -0,0 +1,5 @@
1
+ import { ReactNode } from 'react';
2
+ export interface StatusDotProps {
3
+ readonly status: 'online' | 'offline' | 'disabled';
4
+ }
5
+ export declare function StatusDot({ status }: StatusDotProps): ReactNode;
@@ -0,0 +1,6 @@
1
+ import { ReactNode } from 'react';
2
+ export interface EmptyStateProps {
3
+ readonly variant: 'nofilter' | 'filtered';
4
+ readonly onClearFilters?: () => void;
5
+ }
6
+ export declare function DeviceListEmptyState({ variant, onClearFilters }: EmptyStateProps): ReactNode;
@@ -0,0 +1,19 @@
1
+ import { ReactNode } from 'react';
2
+ import { DeviceListView } from './url-state';
3
+ export interface FilterChipsProps {
4
+ readonly view: DeviceListView;
5
+ readonly onViewChange: (view: DeviceListView) => void;
6
+ readonly types?: readonly string[];
7
+ readonly currentType: string | null;
8
+ readonly onTypeChange: (type: string | null) => void;
9
+ readonly addons?: readonly {
10
+ readonly id: string;
11
+ readonly name: string;
12
+ readonly icon?: ReactNode;
13
+ }[];
14
+ readonly currentAddon: string | null;
15
+ readonly onAddonChange: (addon: string | null) => void;
16
+ /** When true, the addon group is hidden (used by Integrations expand-row inner DeviceList). */
17
+ readonly hideAddons?: boolean;
18
+ }
19
+ export declare function FilterChips({ view, onViewChange, types, currentType, onTypeChange, addons, currentAddon, onAddonChange, hideAddons, }: FilterChipsProps): ReactNode;
@@ -0,0 +1,6 @@
1
+ import { DeviceItemDevice } from '../device-item/helpers';
2
+ export interface GroupedDevices {
3
+ readonly topLevel: readonly DeviceItemDevice[];
4
+ readonly accessoriesByParent: ReadonlyMap<number, readonly DeviceItemDevice[]>;
5
+ }
6
+ export declare function groupTopLevelAndAccessories(devices: readonly DeviceItemDevice[]): GroupedDevices;
@@ -0,0 +1,31 @@
1
+ import { ReactNode } from 'react';
2
+ import { UseDeviceProxyTrpc } from '../../hooks/use-device-proxy';
3
+ import { DeviceItemDevice, DeviceItemParent } from '../device-item/helpers';
4
+ import { DeviceListView } from './url-state';
5
+ export interface DeviceListAddonOption {
6
+ readonly id: string;
7
+ readonly name: string;
8
+ readonly icon?: ReactNode;
9
+ }
10
+ export interface DeviceListProps {
11
+ readonly devices: readonly DeviceItemDevice[];
12
+ readonly trpc: UseDeviceProxyTrpc;
13
+ readonly defaultView?: DeviceListView;
14
+ readonly filters?: {
15
+ readonly types?: readonly string[];
16
+ readonly addons?: readonly DeviceListAddonOption[];
17
+ };
18
+ /** Pre-applied addon filter — hides the addon-chip group. */
19
+ readonly forceAddon?: string;
20
+ readonly resolveIntegrationIcon?: (addonId: string) => ReactNode | null;
21
+ readonly resolveParent?: (parentId: number) => DeviceItemParent | null;
22
+ readonly onNavigate?: (deviceId: number) => void;
23
+ readonly pageSize?: {
24
+ readonly cards: number;
25
+ readonly table: number;
26
+ };
27
+ readonly urlScope?: 'root' | 'nested';
28
+ /** LocalStorage key prefix. Default 'devices' for root scope, 'integrations:nested' for nested. */
29
+ readonly lsKey?: string;
30
+ }
31
+ export declare function DeviceList(props: DeviceListProps): ReactNode;
@@ -0,0 +1,18 @@
1
+ import { ReactNode } from 'react';
2
+ export interface PaginationProps {
3
+ readonly currentPage: number;
4
+ readonly totalItems: number;
5
+ readonly pageSize: number;
6
+ readonly onPageChange: (page: number) => void;
7
+ /** Singular noun for the showing-info label. Default `'devices'`. */
8
+ readonly itemNoun?: string;
9
+ }
10
+ export type PageButton = {
11
+ readonly kind: 'page';
12
+ readonly n: number;
13
+ } | {
14
+ readonly kind: 'ellipsis';
15
+ readonly side: 'left' | 'right';
16
+ };
17
+ export declare function computePageButtons(currentPage: number, totalPages: number): readonly PageButton[];
18
+ export declare function Pagination({ currentPage, totalItems, pageSize, onPageChange, itemNoun, }: PaginationProps): ReactNode;
@@ -0,0 +1,24 @@
1
+ export type DeviceListView = 'cards' | 'table';
2
+ export interface DeviceListUrlState {
3
+ readonly view: DeviceListView;
4
+ readonly page: number;
5
+ readonly addon: string | null;
6
+ readonly type: string | null;
7
+ readonly q: string;
8
+ }
9
+ export interface UseDeviceListUrlStateOptions {
10
+ readonly scope: 'root' | 'nested';
11
+ readonly defaultView: DeviceListView;
12
+ /** LocalStorage key prefix, e.g. `'devices'` → `camstack:devices:lastFilters`. */
13
+ readonly lsKey: string;
14
+ }
15
+ export interface UseDeviceListUrlStateResult {
16
+ readonly state: DeviceListUrlState;
17
+ readonly setView: (view: DeviceListView) => void;
18
+ readonly setPage: (page: number) => void;
19
+ readonly setAddon: (addon: string | null) => void;
20
+ readonly setType: (type: string | null) => void;
21
+ readonly setQ: (q: string) => void;
22
+ readonly clearFilters: () => void;
23
+ }
24
+ export declare function useDeviceListUrlState(options: UseDeviceListUrlStateOptions): UseDeviceListUrlStateResult;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Shared discovery panel — renders the `device-discovery` cap surface
3
+ * for any parent device that registers it (Reolink Hub, future ONVIF
4
+ * gateway, NVR-style integrations). Keeps the integration's UI
5
+ * surface zero-effort: as long as the cap is mounted, the panel
6
+ * renders the channel list with status badges, refresh, adopt, and
7
+ * release controls.
8
+ *
9
+ * Mirrors the Scrypted device-discovery affordance pattern: a single
10
+ * generic UI used by every plugin that exposes children behind a
11
+ * gateway. Keeps the operator UX consistent across integrations.
12
+ */
13
+ interface DiscoveryPanelProps {
14
+ readonly deviceId: number;
15
+ readonly className?: string;
16
+ /**
17
+ * Optional navigation callback fired when the operator clicks the
18
+ * "Open" link on an adopted child row. ui-library deliberately
19
+ * stays free of `react-router-dom` so it works in agent UIs +
20
+ * embedded admin shells alike — host wires the actual navigation.
21
+ * When omitted, the link is hidden.
22
+ */
23
+ readonly onOpenChild?: (childDeviceId: number) => void;
24
+ }
25
+ export declare function DiscoveryPanel({ deviceId, className, onOpenChild }: DiscoveryPanelProps): React.ReactElement;
26
+ export {};
@@ -0,0 +1,10 @@
1
+ import { DoorbellPressEvent } from '../hooks/use-doorbell-events';
2
+ export interface DoorbellRecentPanelProps {
3
+ readonly history: readonly DoorbellPressEvent[];
4
+ /** Max rows to show (defaults to 5). */
5
+ readonly limit?: number;
6
+ /** Visual hint that the latest press is fresh (< 30s) — pulses the icon. */
7
+ readonly latestIsFresh?: boolean;
8
+ readonly className?: string;
9
+ }
10
+ export declare function DoorbellRecentPanel({ history, limit, latestIsFresh, className, }: DoorbellRecentPanelProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,10 @@
1
+ import { ReactNode } from 'react';
2
+ import { LucideIcon } from 'lucide-react';
3
+ export interface EmptyStateProps {
4
+ icon?: LucideIcon;
5
+ title: string;
6
+ description?: string;
7
+ action?: ReactNode;
8
+ className?: string;
9
+ }
10
+ export declare function EmptyState({ icon: Icon, title, description, action, className, }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,48 @@
1
+ import { LiveBuffer } from '../hooks/use-live-buffer';
2
+ interface EventEntry {
3
+ readonly id: string;
4
+ readonly timestamp: string;
5
+ readonly source: {
6
+ readonly type: string;
7
+ readonly id: string | number;
8
+ readonly nodeId?: string;
9
+ readonly addonId?: string;
10
+ readonly deviceId?: number;
11
+ };
12
+ readonly category: string;
13
+ readonly data: Record<string, unknown>;
14
+ }
15
+ export interface EventStreamProps {
16
+ readonly agentId?: string;
17
+ readonly addonId?: string;
18
+ readonly deviceId?: number;
19
+ /** Initial whitelist — the user can mutate through the multiselect popover.
20
+ * Defaults to ALL EventCategory values when both this and `categories`
21
+ * are omitted. */
22
+ readonly defaultCategories?: readonly string[];
23
+ /** Legacy alias for `defaultCategories`. Kept for back-compat. */
24
+ readonly categories?: readonly string[];
25
+ /** Category glob/pattern passed to the backend subscription (e.g. 'addon.*'). */
26
+ readonly category?: string;
27
+ readonly maxHeight?: string;
28
+ readonly limit?: number;
29
+ /** Show the multiselect filter button in the toolbar (default true). */
30
+ readonly showCategoryFilter?: boolean;
31
+ readonly showFilters?: boolean;
32
+ /**
33
+ * Optional controlled live buffer. When provided, the stream reads
34
+ * + appends to this external store rather than its own `useState`,
35
+ * so the visible list survives an unmount/remount of the component
36
+ * (used by `DeviceActivityPanel` to keep tab content alive across
37
+ * tab switches without keeping subscriptions open in inactive tabs).
38
+ */
39
+ readonly liveBuffer?: LiveBuffer<EventEntry>;
40
+ readonly onClose?: () => void;
41
+ readonly className?: string;
42
+ }
43
+ export declare function EventStream({ agentId, addonId, deviceId, defaultCategories, categories: legacyCategories, category: propsCategory, maxHeight, limit, showCategoryFilter, showFilters: _showFilters, liveBuffer: externalBuffer, onClose, className, }: EventStreamProps): import("react/jsx-runtime").JSX.Element;
44
+ export interface FloatingEventStreamProps extends EventStreamProps {
45
+ readonly position?: 'bottom' | 'overlay';
46
+ }
47
+ export declare function FloatingEventStream({ position, className, ...props }: FloatingEventStreamProps): import("react/jsx-runtime").JSX.Element;
48
+ export {};
@@ -0,0 +1,28 @@
1
+ type FilterDef = {
2
+ type: 'search';
3
+ key: string;
4
+ placeholder?: string;
5
+ } | {
6
+ type: 'select';
7
+ key: string;
8
+ label: string;
9
+ options: {
10
+ value: string;
11
+ label: string;
12
+ }[];
13
+ } | {
14
+ type: 'badge-toggle';
15
+ key: string;
16
+ options: {
17
+ value: string;
18
+ label: string;
19
+ }[];
20
+ };
21
+ export type { FilterDef };
22
+ export interface FilterBarProps {
23
+ filters: FilterDef[];
24
+ values: Record<string, unknown>;
25
+ onChange: (values: Record<string, unknown>) => void;
26
+ className?: string;
27
+ }
28
+ export declare function FilterBar({ filters, values, onChange, className }: FilterBarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from 'react';
2
+ export interface FormFieldProps {
3
+ label: string;
4
+ description?: string;
5
+ error?: string;
6
+ required?: boolean;
7
+ children: ReactNode;
8
+ orientation?: 'vertical' | 'horizontal';
9
+ className?: string;
10
+ }
11
+ export declare function FormField({ label, description, error, required, children, orientation, className, }: FormFieldProps): import("react/jsx-runtime").JSX.Element;