@camstack/ui-library 1.2.120 → 1.2.122
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/cap-settings/NavigationPanel.d.ts +2 -0
- package/dist/composites/cap-settings/index.d.ts +1 -0
- package/dist/composites/index.d.ts +1 -0
- package/dist/generated/system-hooks.d.ts +24 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/use-navigation.d.ts +26 -0
- package/dist/index.cjs +472 -0
- package/dist/index.js +459 -2
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ export type { MaskShapeCanvasProps, MaskShapeItem } from './MaskShapeCanvas';
|
|
|
4
4
|
export { MaskShapeCanvas } from './MaskShapeCanvas';
|
|
5
5
|
export { MotionZonesSettings } from './MotionZonesSettings';
|
|
6
6
|
export { PrivacyMaskSettings } from './PrivacyMaskSettings';
|
|
7
|
+
export { NavigationPanel } from './NavigationPanel';
|
|
7
8
|
export { PtzPanel } from './PtzPanel';
|
|
8
9
|
export { RecordingBandsEditor } from './RecordingBandsEditor';
|
|
9
10
|
export { RecordingPanel } from './RecordingPanel';
|
|
@@ -21,6 +21,7 @@ export { AutotrackSection } from './cap-settings/AutotrackSection';
|
|
|
21
21
|
export { ConsumablesPanel } from './cap-settings/ConsumablesPanel';
|
|
22
22
|
export type { CapSettingsComponentProps } from './cap-settings/index';
|
|
23
23
|
export type { MaskShapeCanvasProps, MaskShapeItem } from './cap-settings/MaskShapeCanvas';
|
|
24
|
+
export { NavigationPanel } from './cap-settings/NavigationPanel';
|
|
24
25
|
export { PtzPanel } from './cap-settings/PtzPanel';
|
|
25
26
|
export { RecordingPanel } from './cap-settings/RecordingPanel';
|
|
26
27
|
export type { SceneCaptureVariant } from './cap-settings/scene-monitor-copy';
|
|
@@ -935,6 +935,28 @@ export declare const useMqttBrokerGetStatus: typeof trpc.mqttBroker.getStatus.us
|
|
|
935
935
|
export declare const useNativeObjectDetectionSetEnabled: typeof trpc.nativeObjectDetection.setEnabled.useMutation;
|
|
936
936
|
/** Generated alias around `trpc.nativeObjectDetection.getStatus.useQuery`. */
|
|
937
937
|
export declare const useNativeObjectDetectionGetStatus: typeof trpc.nativeObjectDetection.getStatus.useQuery;
|
|
938
|
+
/** Generated alias around `trpc.navigation.move.useMutation`. */
|
|
939
|
+
export declare const useNavigationMove: typeof trpc.navigation.move.useMutation;
|
|
940
|
+
/** Generated alias around `trpc.navigation.stop.useMutation`. */
|
|
941
|
+
export declare const useNavigationStop: typeof trpc.navigation.stop.useMutation;
|
|
942
|
+
/** Generated alias around `trpc.navigation.goToPoint.useMutation`. */
|
|
943
|
+
export declare const useNavigationGoToPoint: typeof trpc.navigation.goToPoint.useMutation;
|
|
944
|
+
/** Generated alias around `trpc.navigation.listActions.useQuery`. */
|
|
945
|
+
export declare const useNavigationListActions: typeof trpc.navigation.listActions.useQuery;
|
|
946
|
+
/** Generated alias around `trpc.navigation.runAction.useMutation`. */
|
|
947
|
+
export declare const useNavigationRunAction: typeof trpc.navigation.runAction.useMutation;
|
|
948
|
+
/** Generated alias around `trpc.navigation.playSound.useMutation`. */
|
|
949
|
+
export declare const useNavigationPlaySound: typeof trpc.navigation.playSound.useMutation;
|
|
950
|
+
/** Generated alias around `trpc.navigation.setLightOn.useMutation`. */
|
|
951
|
+
export declare const useNavigationSetLightOn: typeof trpc.navigation.setLightOn.useMutation;
|
|
952
|
+
/** Generated alias around `trpc.navigation.setLightMode.useMutation`. */
|
|
953
|
+
export declare const useNavigationSetLightMode: typeof trpc.navigation.setLightMode.useMutation;
|
|
954
|
+
/** Generated alias around `trpc.navigation.setLightLevel.useMutation`. */
|
|
955
|
+
export declare const useNavigationSetLightLevel: typeof trpc.navigation.setLightLevel.useMutation;
|
|
956
|
+
/** Generated alias around `trpc.navigation.getFeatures.useQuery`. */
|
|
957
|
+
export declare const useNavigationGetFeatures: typeof trpc.navigation.getFeatures.useQuery;
|
|
958
|
+
/** Generated alias around `trpc.navigation.getStatus.useQuery`. */
|
|
959
|
+
export declare const useNavigationGetStatus: typeof trpc.navigation.getStatus.useQuery;
|
|
938
960
|
/** Generated alias around `trpc.networkAccess.start.useMutation`. */
|
|
939
961
|
export declare const useNetworkAccessStart: typeof trpc.networkAccess.start.useMutation;
|
|
940
962
|
/** Generated alias around `trpc.networkAccess.stop.useMutation`. */
|
|
@@ -945,6 +967,8 @@ export declare const useNetworkAccessGetEndpoint: typeof trpc.networkAccess.getE
|
|
|
945
967
|
export declare const useNetworkAccessGetStatus: typeof trpc.networkAccess.getStatus.useQuery;
|
|
946
968
|
/** Generated alias around `trpc.networkAccess.listEndpoints.useQuery`. */
|
|
947
969
|
export declare const useNetworkAccessListEndpoints: typeof trpc.networkAccess.listEndpoints.useQuery;
|
|
970
|
+
/** Generated alias around `trpc.networkLink.getStatus.useQuery`. */
|
|
971
|
+
export declare const useNetworkLinkGetStatus: typeof trpc.networkLink.getStatus.useQuery;
|
|
948
972
|
/** Generated alias around `trpc.networkQuality.getDeviceStats.useQuery`. */
|
|
949
973
|
export declare const useNetworkQualityGetDeviceStats: typeof trpc.networkQuality.getDeviceStats.useQuery;
|
|
950
974
|
/** Generated alias around `trpc.networkQuality.getAllStats.useQuery`. */
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export { useDebouncedString } from './use-debounced-string';
|
|
|
4
4
|
export type { UseDeviceAutotrack } from './use-device-autotrack';
|
|
5
5
|
export { useDeviceAutotrack } from './use-device-autotrack';
|
|
6
6
|
export type { UseDeviceBatteryTrpc } from './use-device-battery';
|
|
7
|
+
export type { NavigationDirection, UseNavigationResult } from './use-navigation';
|
|
8
|
+
export { NAVIGATION_DRIVE_INTERVAL_MS, useNavigation } from './use-navigation';
|
|
7
9
|
export { useDeviceBattery } from './use-device-battery';
|
|
8
10
|
export type { NetworkLinkStatus } from './use-device-network-link';
|
|
9
11
|
export { useDeviceNetworkLink } from './use-device-network-link';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NavigationActionEntry, NavigationActionId, NavigationFeatures, NavigationLightMode, NavigationStatus } from '@camstack/types';
|
|
2
|
+
import { UseDeviceProxyTrpc } from './use-device-proxy';
|
|
3
|
+
export type NavigationDirection = 'forward' | 'left' | 'right' | 'spin';
|
|
4
|
+
/** The cadence the robot app drives at while a direction is held. */
|
|
5
|
+
export declare const NAVIGATION_DRIVE_INTERVAL_MS = 1000;
|
|
6
|
+
export interface UseNavigationOptions {
|
|
7
|
+
readonly enabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface UseNavigationResult {
|
|
10
|
+
readonly features: NavigationFeatures | null;
|
|
11
|
+
readonly actions: readonly NavigationActionEntry[];
|
|
12
|
+
readonly status: NavigationStatus | null;
|
|
13
|
+
/** Start nudging in a direction at 1 Hz until `stopDrive`. */
|
|
14
|
+
readonly startDrive: (direction: NavigationDirection) => void;
|
|
15
|
+
readonly stopDrive: () => Promise<void>;
|
|
16
|
+
readonly runAction: (actionId: NavigationActionId) => Promise<void>;
|
|
17
|
+
readonly playSound: (soundId: number) => Promise<void>;
|
|
18
|
+
readonly setLightOn: (on: boolean) => Promise<void>;
|
|
19
|
+
readonly setLightMode: (mode: NavigationLightMode, level?: number) => Promise<void>;
|
|
20
|
+
readonly setLightLevel: (level: number) => Promise<void>;
|
|
21
|
+
readonly busy: boolean;
|
|
22
|
+
readonly error: string | null;
|
|
23
|
+
/** True while a direction is held. */
|
|
24
|
+
readonly driving: NavigationDirection | null;
|
|
25
|
+
}
|
|
26
|
+
export declare function useNavigation(trpc: UseDeviceProxyTrpc, deviceId: number, hookOptions?: UseNavigationOptions): UseNavigationResult;
|
package/dist/index.cjs
CHANGED
|
@@ -1890,6 +1890,34 @@ var Flame = createLucideIcon("flame", [["path", {
|
|
|
1890
1890
|
* This source code is licensed under the ISC license.
|
|
1891
1891
|
* See the LICENSE file in the root directory of this source tree.
|
|
1892
1892
|
*/
|
|
1893
|
+
var FlashlightOff = createLucideIcon("flashlight-off", [
|
|
1894
|
+
["path", {
|
|
1895
|
+
d: "M11.652 6H18",
|
|
1896
|
+
key: "voqkpr"
|
|
1897
|
+
}],
|
|
1898
|
+
["path", {
|
|
1899
|
+
d: "M12 13v1",
|
|
1900
|
+
key: "176q98"
|
|
1901
|
+
}],
|
|
1902
|
+
["path", {
|
|
1903
|
+
d: "M16 16v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-8a4 4 0 0 0-.8-2.4l-.6-.8A3 3 0 0 1 6 7V6",
|
|
1904
|
+
key: "dzyf92"
|
|
1905
|
+
}],
|
|
1906
|
+
["path", {
|
|
1907
|
+
d: "m2 2 20 20",
|
|
1908
|
+
key: "1ooewy"
|
|
1909
|
+
}],
|
|
1910
|
+
["path", {
|
|
1911
|
+
d: "M7.649 2H17a1 1 0 0 1 1 1v4a3 3 0 0 1-.6 1.8l-.6.8a4 4 0 0 0-.55 1.007",
|
|
1912
|
+
key: "1hvcfn"
|
|
1913
|
+
}]
|
|
1914
|
+
]);
|
|
1915
|
+
/**
|
|
1916
|
+
* @license lucide-react v0.576.0 - ISC
|
|
1917
|
+
*
|
|
1918
|
+
* This source code is licensed under the ISC license.
|
|
1919
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
1920
|
+
*/
|
|
1893
1921
|
var Flashlight = createLucideIcon("flashlight", [
|
|
1894
1922
|
["path", {
|
|
1895
1923
|
d: "M12 13v1",
|
|
@@ -2081,6 +2109,30 @@ var Hammer = createLucideIcon("hammer", [
|
|
|
2081
2109
|
* This source code is licensed under the ISC license.
|
|
2082
2110
|
* See the LICENSE file in the root directory of this source tree.
|
|
2083
2111
|
*/
|
|
2112
|
+
var Hand = createLucideIcon("hand", [
|
|
2113
|
+
["path", {
|
|
2114
|
+
d: "M18 11V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2",
|
|
2115
|
+
key: "1fvzgz"
|
|
2116
|
+
}],
|
|
2117
|
+
["path", {
|
|
2118
|
+
d: "M14 10V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2v2",
|
|
2119
|
+
key: "1kc0my"
|
|
2120
|
+
}],
|
|
2121
|
+
["path", {
|
|
2122
|
+
d: "M10 10.5V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2v8",
|
|
2123
|
+
key: "10h0bg"
|
|
2124
|
+
}],
|
|
2125
|
+
["path", {
|
|
2126
|
+
d: "M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15",
|
|
2127
|
+
key: "1s1gnw"
|
|
2128
|
+
}]
|
|
2129
|
+
]);
|
|
2130
|
+
/**
|
|
2131
|
+
* @license lucide-react v0.576.0 - ISC
|
|
2132
|
+
*
|
|
2133
|
+
* This source code is licensed under the ISC license.
|
|
2134
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
2135
|
+
*/
|
|
2084
2136
|
var HardDrive = createLucideIcon("hard-drive", [
|
|
2085
2137
|
["path", {
|
|
2086
2138
|
d: "M10 16h.01",
|
|
@@ -4286,6 +4338,19 @@ var Type = createLucideIcon("type", [
|
|
|
4286
4338
|
* This source code is licensed under the ISC license.
|
|
4287
4339
|
* See the LICENSE file in the root directory of this source tree.
|
|
4288
4340
|
*/
|
|
4341
|
+
var Undo2 = createLucideIcon("undo-2", [["path", {
|
|
4342
|
+
d: "M9 14 4 9l5-5",
|
|
4343
|
+
key: "102s5s"
|
|
4344
|
+
}], ["path", {
|
|
4345
|
+
d: "M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11",
|
|
4346
|
+
key: "f3b9sd"
|
|
4347
|
+
}]]);
|
|
4348
|
+
/**
|
|
4349
|
+
* @license lucide-react v0.576.0 - ISC
|
|
4350
|
+
*
|
|
4351
|
+
* This source code is licensed under the ISC license.
|
|
4352
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
4353
|
+
*/
|
|
4289
4354
|
var Unlink2 = createLucideIcon("unlink-2", [["path", {
|
|
4290
4355
|
d: "M15 7h2a5 5 0 0 1 0 10h-2m-6 0H7A5 5 0 0 1 7 7h2",
|
|
4291
4356
|
key: "1re2ne"
|
|
@@ -5922,6 +5987,28 @@ var useMqttBrokerGetStatus = trpc.mqttBroker.getStatus.useQuery;
|
|
|
5922
5987
|
var useNativeObjectDetectionSetEnabled = trpc.nativeObjectDetection.setEnabled.useMutation;
|
|
5923
5988
|
/** Generated alias around `trpc.nativeObjectDetection.getStatus.useQuery`. */
|
|
5924
5989
|
var useNativeObjectDetectionGetStatus = trpc.nativeObjectDetection.getStatus.useQuery;
|
|
5990
|
+
/** Generated alias around `trpc.navigation.move.useMutation`. */
|
|
5991
|
+
var useNavigationMove = trpc.navigation.move.useMutation;
|
|
5992
|
+
/** Generated alias around `trpc.navigation.stop.useMutation`. */
|
|
5993
|
+
var useNavigationStop = trpc.navigation.stop.useMutation;
|
|
5994
|
+
/** Generated alias around `trpc.navigation.goToPoint.useMutation`. */
|
|
5995
|
+
var useNavigationGoToPoint = trpc.navigation.goToPoint.useMutation;
|
|
5996
|
+
/** Generated alias around `trpc.navigation.listActions.useQuery`. */
|
|
5997
|
+
var useNavigationListActions = trpc.navigation.listActions.useQuery;
|
|
5998
|
+
/** Generated alias around `trpc.navigation.runAction.useMutation`. */
|
|
5999
|
+
var useNavigationRunAction = trpc.navigation.runAction.useMutation;
|
|
6000
|
+
/** Generated alias around `trpc.navigation.playSound.useMutation`. */
|
|
6001
|
+
var useNavigationPlaySound = trpc.navigation.playSound.useMutation;
|
|
6002
|
+
/** Generated alias around `trpc.navigation.setLightOn.useMutation`. */
|
|
6003
|
+
var useNavigationSetLightOn = trpc.navigation.setLightOn.useMutation;
|
|
6004
|
+
/** Generated alias around `trpc.navigation.setLightMode.useMutation`. */
|
|
6005
|
+
var useNavigationSetLightMode = trpc.navigation.setLightMode.useMutation;
|
|
6006
|
+
/** Generated alias around `trpc.navigation.setLightLevel.useMutation`. */
|
|
6007
|
+
var useNavigationSetLightLevel = trpc.navigation.setLightLevel.useMutation;
|
|
6008
|
+
/** Generated alias around `trpc.navigation.getFeatures.useQuery`. */
|
|
6009
|
+
var useNavigationGetFeatures = trpc.navigation.getFeatures.useQuery;
|
|
6010
|
+
/** Generated alias around `trpc.navigation.getStatus.useQuery`. */
|
|
6011
|
+
var useNavigationGetStatus = trpc.navigation.getStatus.useQuery;
|
|
5925
6012
|
/** Generated alias around `trpc.networkAccess.start.useMutation`. */
|
|
5926
6013
|
var useNetworkAccessStart = trpc.networkAccess.start.useMutation;
|
|
5927
6014
|
/** Generated alias around `trpc.networkAccess.stop.useMutation`. */
|
|
@@ -5932,6 +6019,8 @@ var useNetworkAccessGetEndpoint = trpc.networkAccess.getEndpoint.useQuery;
|
|
|
5932
6019
|
var useNetworkAccessGetStatus = trpc.networkAccess.getStatus.useQuery;
|
|
5933
6020
|
/** Generated alias around `trpc.networkAccess.listEndpoints.useQuery`. */
|
|
5934
6021
|
var useNetworkAccessListEndpoints = trpc.networkAccess.listEndpoints.useQuery;
|
|
6022
|
+
/** Generated alias around `trpc.networkLink.getStatus.useQuery`. */
|
|
6023
|
+
var useNetworkLinkGetStatus = trpc.networkLink.getStatus.useQuery;
|
|
5935
6024
|
/** Generated alias around `trpc.networkQuality.getDeviceStats.useQuery`. */
|
|
5936
6025
|
var useNetworkQualityGetDeviceStats = trpc.networkQuality.getDeviceStats.useQuery;
|
|
5937
6026
|
/** Generated alias around `trpc.networkQuality.getAllStats.useQuery`. */
|
|
@@ -15987,6 +16076,373 @@ function ConsumablesPanel({ deviceId }) {
|
|
|
15987
16076
|
});
|
|
15988
16077
|
}
|
|
15989
16078
|
//#endregion
|
|
16079
|
+
//#region src/hooks/use-navigation.ts
|
|
16080
|
+
/**
|
|
16081
|
+
* useNavigation — drive a `navigation` robot camera from the UI.
|
|
16082
|
+
*
|
|
16083
|
+
* The cap's `move` is MOMENTARY: fluid driving is the UI sending a nudge at
|
|
16084
|
+
* 1 Hz while a direction is held and ONE `stop` on release, exactly like the
|
|
16085
|
+
* robot app's joystick. This hook owns that cadence (`startDrive` /
|
|
16086
|
+
* `stopDrive`); the provider forwards each nudge to a single drive write.
|
|
16087
|
+
*
|
|
16088
|
+
* Everything else is a plain call plus the data the panel renders from:
|
|
16089
|
+
* `features` (which primitives are on), `actions` (the enabled dictionary)
|
|
16090
|
+
* and the live `status` slice off the device proxy.
|
|
16091
|
+
*/
|
|
16092
|
+
/** The cadence the robot app drives at while a direction is held. */
|
|
16093
|
+
var NAVIGATION_DRIVE_INTERVAL_MS = 1e3;
|
|
16094
|
+
var DIRECTION_VECTORS$1 = {
|
|
16095
|
+
forward: {
|
|
16096
|
+
pan: 0,
|
|
16097
|
+
tilt: 1
|
|
16098
|
+
},
|
|
16099
|
+
left: {
|
|
16100
|
+
pan: -1,
|
|
16101
|
+
tilt: 0
|
|
16102
|
+
},
|
|
16103
|
+
right: {
|
|
16104
|
+
pan: 1,
|
|
16105
|
+
tilt: 0
|
|
16106
|
+
},
|
|
16107
|
+
spin: {
|
|
16108
|
+
pan: 0,
|
|
16109
|
+
tilt: -1
|
|
16110
|
+
}
|
|
16111
|
+
};
|
|
16112
|
+
function isAbsentProvider$1(err) {
|
|
16113
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16114
|
+
return /not available|no provider|NOT_FOUND|PRECONDITION/i.test(message);
|
|
16115
|
+
}
|
|
16116
|
+
function useNavigation(trpc, deviceId, hookOptions) {
|
|
16117
|
+
const enabled = hookOptions?.enabled ?? true;
|
|
16118
|
+
const nav = useDeviceProxy(trpc, enabled ? deviceId : null)?.navigation;
|
|
16119
|
+
const status = useDeviceState(trpc, enabled ? deviceId : null, (s) => s.navigation);
|
|
16120
|
+
const [features, setFeatures] = (0, react$1.useState)(null);
|
|
16121
|
+
const [actions, setActions] = (0, react$1.useState)([]);
|
|
16122
|
+
const [busy, setBusy] = (0, react$1.useState)(false);
|
|
16123
|
+
const [error, setError] = (0, react$1.useState)(null);
|
|
16124
|
+
const [driving, setDriving] = (0, react$1.useState)(null);
|
|
16125
|
+
const driveTimer = (0, react$1.useRef)(null);
|
|
16126
|
+
(0, react$1.useEffect)(() => {
|
|
16127
|
+
if (!enabled || !nav) return;
|
|
16128
|
+
let cancelled = false;
|
|
16129
|
+
(async () => {
|
|
16130
|
+
try {
|
|
16131
|
+
const [nextFeatures, nextActions] = await Promise.all([nav.getFeatures({}), nav.listActions({})]);
|
|
16132
|
+
if (cancelled) return;
|
|
16133
|
+
setFeatures(nextFeatures);
|
|
16134
|
+
setActions(nextActions);
|
|
16135
|
+
} catch (err) {
|
|
16136
|
+
if (cancelled || isAbsentProvider$1(err)) return;
|
|
16137
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
16138
|
+
}
|
|
16139
|
+
})();
|
|
16140
|
+
return () => {
|
|
16141
|
+
cancelled = true;
|
|
16142
|
+
};
|
|
16143
|
+
}, [nav, enabled]);
|
|
16144
|
+
const wrap = (0, react$1.useCallback)(async (fn) => {
|
|
16145
|
+
if (!enabled || !nav) return;
|
|
16146
|
+
setError(null);
|
|
16147
|
+
setBusy(true);
|
|
16148
|
+
try {
|
|
16149
|
+
await fn();
|
|
16150
|
+
} catch (err) {
|
|
16151
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
16152
|
+
} finally {
|
|
16153
|
+
setBusy(false);
|
|
16154
|
+
}
|
|
16155
|
+
}, [enabled, nav]);
|
|
16156
|
+
const clearTimer = (0, react$1.useCallback)(() => {
|
|
16157
|
+
if (driveTimer.current !== null) {
|
|
16158
|
+
clearInterval(driveTimer.current);
|
|
16159
|
+
driveTimer.current = null;
|
|
16160
|
+
}
|
|
16161
|
+
}, []);
|
|
16162
|
+
const stopDrive = (0, react$1.useCallback)(async () => {
|
|
16163
|
+
clearTimer();
|
|
16164
|
+
setDriving(null);
|
|
16165
|
+
if (!nav) return;
|
|
16166
|
+
await wrap(() => nav.stop({}));
|
|
16167
|
+
}, [
|
|
16168
|
+
clearTimer,
|
|
16169
|
+
nav,
|
|
16170
|
+
wrap
|
|
16171
|
+
]);
|
|
16172
|
+
const startDrive = (0, react$1.useCallback)((direction) => {
|
|
16173
|
+
if (!nav) return;
|
|
16174
|
+
clearTimer();
|
|
16175
|
+
setDriving(direction);
|
|
16176
|
+
const vector = DIRECTION_VECTORS$1[direction];
|
|
16177
|
+
const nudge = () => {
|
|
16178
|
+
nav.move({
|
|
16179
|
+
pan: vector.pan,
|
|
16180
|
+
tilt: vector.tilt
|
|
16181
|
+
}).catch((err) => {
|
|
16182
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
16183
|
+
});
|
|
16184
|
+
};
|
|
16185
|
+
nudge();
|
|
16186
|
+
driveTimer.current = setInterval(nudge, NAVIGATION_DRIVE_INTERVAL_MS);
|
|
16187
|
+
}, [clearTimer, nav]);
|
|
16188
|
+
(0, react$1.useEffect)(() => {
|
|
16189
|
+
return () => {
|
|
16190
|
+
if (driveTimer.current !== null) {
|
|
16191
|
+
clearInterval(driveTimer.current);
|
|
16192
|
+
driveTimer.current = null;
|
|
16193
|
+
nav?.stop({}).catch(() => void 0);
|
|
16194
|
+
}
|
|
16195
|
+
};
|
|
16196
|
+
}, [nav]);
|
|
16197
|
+
const runAction = (0, react$1.useCallback)((actionId) => wrap(async () => nav?.runAction({ actionId })), [nav, wrap]);
|
|
16198
|
+
const playSound = (0, react$1.useCallback)((soundId) => wrap(async () => nav?.playSound({ soundId })), [nav, wrap]);
|
|
16199
|
+
const setLightOn = (0, react$1.useCallback)((on) => wrap(async () => nav?.setLightOn({ on })), [nav, wrap]);
|
|
16200
|
+
const setLightMode = (0, react$1.useCallback)((mode, level) => wrap(async () => nav?.setLightMode(level === void 0 ? { mode } : {
|
|
16201
|
+
mode,
|
|
16202
|
+
level
|
|
16203
|
+
})), [nav, wrap]);
|
|
16204
|
+
const setLightLevel = (0, react$1.useCallback)((level) => wrap(async () => nav?.setLightLevel({ level })), [nav, wrap]);
|
|
16205
|
+
return {
|
|
16206
|
+
features,
|
|
16207
|
+
actions,
|
|
16208
|
+
status: status ?? null,
|
|
16209
|
+
startDrive,
|
|
16210
|
+
stopDrive,
|
|
16211
|
+
runAction,
|
|
16212
|
+
playSound,
|
|
16213
|
+
setLightOn,
|
|
16214
|
+
setLightMode,
|
|
16215
|
+
setLightLevel,
|
|
16216
|
+
busy,
|
|
16217
|
+
error,
|
|
16218
|
+
driving
|
|
16219
|
+
};
|
|
16220
|
+
}
|
|
16221
|
+
//#endregion
|
|
16222
|
+
//#region src/composites/cap-settings/NavigationPanel.tsx
|
|
16223
|
+
/** The cap's icon HINTS are lucide names; unknown hints fall back to a spark. */
|
|
16224
|
+
var ICONS = {
|
|
16225
|
+
play: Play,
|
|
16226
|
+
pause: Pause,
|
|
16227
|
+
hand: Hand,
|
|
16228
|
+
home: House,
|
|
16229
|
+
bell: Bell,
|
|
16230
|
+
crosshair: Crosshair,
|
|
16231
|
+
"paw-print": PawPrint,
|
|
16232
|
+
footprints: Footprints,
|
|
16233
|
+
droplets: Droplets,
|
|
16234
|
+
"trash-2": Trash2,
|
|
16235
|
+
flashlight: Flashlight,
|
|
16236
|
+
"flashlight-off": FlashlightOff,
|
|
16237
|
+
cat: Cat,
|
|
16238
|
+
dog: Dog,
|
|
16239
|
+
clock: Clock
|
|
16240
|
+
};
|
|
16241
|
+
function iconFor(hint) {
|
|
16242
|
+
return ICONS[hint] ?? Sparkles;
|
|
16243
|
+
}
|
|
16244
|
+
var DRIVE_BUTTONS = [
|
|
16245
|
+
{
|
|
16246
|
+
direction: "left",
|
|
16247
|
+
label: "Turn left",
|
|
16248
|
+
Icon: RotateCcw
|
|
16249
|
+
},
|
|
16250
|
+
{
|
|
16251
|
+
direction: "forward",
|
|
16252
|
+
label: "Forward",
|
|
16253
|
+
Icon: ArrowUp
|
|
16254
|
+
},
|
|
16255
|
+
{
|
|
16256
|
+
direction: "right",
|
|
16257
|
+
label: "Turn right",
|
|
16258
|
+
Icon: RotateCw
|
|
16259
|
+
},
|
|
16260
|
+
{
|
|
16261
|
+
direction: "spin",
|
|
16262
|
+
label: "Turn around",
|
|
16263
|
+
Icon: Undo2
|
|
16264
|
+
}
|
|
16265
|
+
];
|
|
16266
|
+
var BUTTON = "inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-[10px] font-medium transition-colors bg-surface-elevated/40 text-foreground-subtle hover:bg-surface-hover hover:text-foreground disabled:opacity-50";
|
|
16267
|
+
var BUTTON_ON = "bg-success/15 text-success hover:bg-success/25";
|
|
16268
|
+
function EntryButton({ entry, disabled, onRun }) {
|
|
16269
|
+
const Glyph = iconFor(entry.icon);
|
|
16270
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
16271
|
+
type: "button",
|
|
16272
|
+
className: BUTTON,
|
|
16273
|
+
disabled,
|
|
16274
|
+
onClick: () => onRun(entry),
|
|
16275
|
+
title: entry.label,
|
|
16276
|
+
"aria-label": entry.label,
|
|
16277
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Glyph, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: entry.label })]
|
|
16278
|
+
});
|
|
16279
|
+
}
|
|
16280
|
+
function NavigationPanel({ deviceId }) {
|
|
16281
|
+
const system = useSystem();
|
|
16282
|
+
const ready = Number.isFinite(deviceId);
|
|
16283
|
+
const nav = useNavigation(system.trpcClient, ready ? deviceId : 0, { enabled: ready });
|
|
16284
|
+
if (!ready) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
16285
|
+
className: "flex items-center justify-center h-full text-[11px] text-foreground-subtle italic",
|
|
16286
|
+
children: [
|
|
16287
|
+
"Device #",
|
|
16288
|
+
deviceId,
|
|
16289
|
+
" not loaded."
|
|
16290
|
+
]
|
|
16291
|
+
});
|
|
16292
|
+
const features = nav.features;
|
|
16293
|
+
const actions = nav.actions.filter((entry) => entry.enabled && entry.kind === "action");
|
|
16294
|
+
const sounds = nav.actions.filter((entry) => entry.enabled && entry.kind === "sound");
|
|
16295
|
+
const status = nav.status;
|
|
16296
|
+
const manual = status?.lightMode === "manual";
|
|
16297
|
+
const run = (entry) => {
|
|
16298
|
+
if (entry.kind === "sound") {
|
|
16299
|
+
if (entry.soundId !== void 0) nav.playSound(entry.soundId);
|
|
16300
|
+
return;
|
|
16301
|
+
}
|
|
16302
|
+
nav.runAction(entry.id);
|
|
16303
|
+
};
|
|
16304
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(WidgetPanel, {
|
|
16305
|
+
title: "Navigation",
|
|
16306
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Navigation, { className: "h-3.5 w-3.5 text-foreground-subtle" }),
|
|
16307
|
+
bodyClassName: "p-3 flex flex-col gap-3 overflow-y-auto",
|
|
16308
|
+
children: [
|
|
16309
|
+
status && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
16310
|
+
className: "flex flex-wrap items-center gap-1.5 text-[10px]",
|
|
16311
|
+
children: [
|
|
16312
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
16313
|
+
className: "rounded-full bg-surface-elevated/60 px-2 py-0.5 text-foreground",
|
|
16314
|
+
children: status.mode
|
|
16315
|
+
}),
|
|
16316
|
+
status.following && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
16317
|
+
className: "rounded-full bg-info/15 px-2 py-0.5 text-info",
|
|
16318
|
+
children: "following"
|
|
16319
|
+
}),
|
|
16320
|
+
status.flash && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
16321
|
+
className: "rounded-full bg-warning/15 px-2 py-0.5 text-warning",
|
|
16322
|
+
children: "light on"
|
|
16323
|
+
})
|
|
16324
|
+
]
|
|
16325
|
+
}),
|
|
16326
|
+
features?.move && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
16327
|
+
className: "flex flex-col gap-1.5",
|
|
16328
|
+
children: [
|
|
16329
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
16330
|
+
className: "text-[10.5px] font-semibold text-foreground",
|
|
16331
|
+
children: "Drive (hold)"
|
|
16332
|
+
}),
|
|
16333
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
16334
|
+
className: "grid grid-cols-4 gap-1.5",
|
|
16335
|
+
children: DRIVE_BUTTONS.map(({ direction, label, Icon }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
16336
|
+
type: "button",
|
|
16337
|
+
className: cn(BUTTON, "justify-center select-none", nav.driving === direction && BUTTON_ON),
|
|
16338
|
+
"aria-label": label,
|
|
16339
|
+
title: label,
|
|
16340
|
+
onPointerDown: () => nav.startDrive(direction),
|
|
16341
|
+
onPointerUp: () => void nav.stopDrive(),
|
|
16342
|
+
onPointerLeave: () => {
|
|
16343
|
+
if (nav.driving === direction) nav.stopDrive();
|
|
16344
|
+
},
|
|
16345
|
+
onPointerCancel: () => void nav.stopDrive(),
|
|
16346
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { className: "h-4 w-4" })
|
|
16347
|
+
}, direction))
|
|
16348
|
+
}),
|
|
16349
|
+
features.stop && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
16350
|
+
type: "button",
|
|
16351
|
+
className: cn(BUTTON, "justify-center"),
|
|
16352
|
+
onClick: () => void nav.stopDrive(),
|
|
16353
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hand, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Stop" })]
|
|
16354
|
+
})
|
|
16355
|
+
]
|
|
16356
|
+
}),
|
|
16357
|
+
features?.runAction && actions.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
16358
|
+
className: "flex flex-col gap-1.5",
|
|
16359
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
16360
|
+
className: "text-[10.5px] font-semibold text-foreground",
|
|
16361
|
+
children: "Actions"
|
|
16362
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
16363
|
+
className: "flex flex-wrap gap-1.5",
|
|
16364
|
+
children: actions.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryButton, {
|
|
16365
|
+
entry,
|
|
16366
|
+
disabled: nav.busy,
|
|
16367
|
+
onRun: run
|
|
16368
|
+
}, entry.id))
|
|
16369
|
+
})]
|
|
16370
|
+
}),
|
|
16371
|
+
features?.playSound && sounds.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
16372
|
+
className: "flex flex-col gap-1.5",
|
|
16373
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
16374
|
+
className: "text-[10.5px] font-semibold text-foreground",
|
|
16375
|
+
children: "Sounds"
|
|
16376
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
16377
|
+
className: "flex flex-wrap gap-1.5",
|
|
16378
|
+
children: sounds.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryButton, {
|
|
16379
|
+
entry,
|
|
16380
|
+
disabled: nav.busy,
|
|
16381
|
+
onRun: run
|
|
16382
|
+
}, entry.id))
|
|
16383
|
+
})]
|
|
16384
|
+
}),
|
|
16385
|
+
features?.light && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
16386
|
+
className: "flex flex-col gap-1.5 border-t border-border/40 pt-2",
|
|
16387
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
16388
|
+
className: "flex items-center justify-between",
|
|
16389
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
16390
|
+
className: "text-[10.5px] font-semibold text-foreground",
|
|
16391
|
+
children: "Fill light"
|
|
16392
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
16393
|
+
type: "button",
|
|
16394
|
+
className: cn(BUTTON, status?.flash && BUTTON_ON),
|
|
16395
|
+
"aria-pressed": status?.flash === true,
|
|
16396
|
+
disabled: nav.busy,
|
|
16397
|
+
onClick: () => void nav.setLightOn(!(status?.flash === true)),
|
|
16398
|
+
children: [status?.flash ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Flashlight, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FlashlightOff, { className: "h-3.5 w-3.5" }), status?.flash ? "On" : "Off"]
|
|
16399
|
+
})]
|
|
16400
|
+
}), features.lightMode && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
16401
|
+
className: "flex items-center gap-2",
|
|
16402
|
+
children: [
|
|
16403
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
16404
|
+
"aria-label": "Light mode",
|
|
16405
|
+
className: "rounded-md bg-surface-elevated/40 px-2 py-1 text-[10px] text-foreground",
|
|
16406
|
+
value: status?.lightMode ?? "auto",
|
|
16407
|
+
disabled: nav.busy,
|
|
16408
|
+
onChange: (event) => {
|
|
16409
|
+
const mode = event.target.value === "manual" ? "manual" : "auto";
|
|
16410
|
+
nav.setLightMode(mode, mode === "manual" ? status?.lightLevel : void 0);
|
|
16411
|
+
},
|
|
16412
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
16413
|
+
value: "auto",
|
|
16414
|
+
children: "Auto"
|
|
16415
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
16416
|
+
value: "manual",
|
|
16417
|
+
children: "Manual"
|
|
16418
|
+
})]
|
|
16419
|
+
}),
|
|
16420
|
+
manual && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
16421
|
+
type: "range",
|
|
16422
|
+
"aria-label": "Light level",
|
|
16423
|
+
className: "flex-1",
|
|
16424
|
+
min: _camstack_types.NAVIGATION_LIGHT_LEVEL_MIN,
|
|
16425
|
+
max: _camstack_types.NAVIGATION_LIGHT_LEVEL_MAX,
|
|
16426
|
+
step: 1,
|
|
16427
|
+
value: status?.lightLevel ?? _camstack_types.NAVIGATION_LIGHT_LEVEL_MAX,
|
|
16428
|
+
disabled: nav.busy,
|
|
16429
|
+
onChange: (event) => void nav.setLightLevel(Number(event.target.value))
|
|
16430
|
+
}),
|
|
16431
|
+
manual && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
16432
|
+
className: "text-[10px] text-foreground-subtle w-8 text-right",
|
|
16433
|
+
children: status?.lightLevel ?? _camstack_types.NAVIGATION_LIGHT_LEVEL_MAX
|
|
16434
|
+
})
|
|
16435
|
+
]
|
|
16436
|
+
})]
|
|
16437
|
+
}),
|
|
16438
|
+
nav.error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
16439
|
+
className: "text-[10px] text-danger",
|
|
16440
|
+
children: nav.error
|
|
16441
|
+
})
|
|
16442
|
+
]
|
|
16443
|
+
});
|
|
16444
|
+
}
|
|
16445
|
+
//#endregion
|
|
15990
16446
|
//#region src/lib/cap-error.ts
|
|
15991
16447
|
/**
|
|
15992
16448
|
* Shared capability-error utilities for the admin UI.
|
|
@@ -18812,6 +19268,7 @@ var HOST_WIDGETS = {
|
|
|
18812
19268
|
"host/motion-zones-grid": (0, react$1.lazy)(() => Promise.resolve().then(() => require("./MotionZonesSettings-BP9p0pFB.cjs")).then((m) => ({ default: m.MotionZonesSettings }))),
|
|
18813
19269
|
"host/privacy-mask-grid": (0, react$1.lazy)(() => Promise.resolve().then(() => require("./PrivacyMaskSettings-Oo7gyB4E.cjs")).then((m) => ({ default: m.PrivacyMaskSettings }))),
|
|
18814
19270
|
"host/ptz-panel": PtzPanel,
|
|
19271
|
+
"host/navigation-panel": NavigationPanel,
|
|
18815
19272
|
"host/consumables-panel": ConsumablesPanel,
|
|
18816
19273
|
"host/ptz-autotrack": AutotrackSection,
|
|
18817
19274
|
"host/recording-panel": RecordingPanel
|
|
@@ -49843,6 +50300,8 @@ exports.Mic = Mic;
|
|
|
49843
50300
|
exports.MobileDrawer = MobileDrawer;
|
|
49844
50301
|
exports.ModelPicker = ModelPicker;
|
|
49845
50302
|
exports.MotionZonesSettings = MotionZonesSettings;
|
|
50303
|
+
exports.NAVIGATION_DRIVE_INTERVAL_MS = NAVIGATION_DRIVE_INTERVAL_MS;
|
|
50304
|
+
exports.NavigationPanel = NavigationPanel;
|
|
49846
50305
|
exports.NetworkLinkBadge = NetworkLinkBadge;
|
|
49847
50306
|
exports.NodeMultiSelectField = NodeMultiSelectField;
|
|
49848
50307
|
exports.NodePicker = NodePicker;
|
|
@@ -50562,11 +51021,24 @@ exports.useMqttBrokerStopEmbeddedBroker = useMqttBrokerStopEmbeddedBroker;
|
|
|
50562
51021
|
exports.useMqttBrokerTestConnection = useMqttBrokerTestConnection;
|
|
50563
51022
|
exports.useNativeObjectDetectionGetStatus = useNativeObjectDetectionGetStatus;
|
|
50564
51023
|
exports.useNativeObjectDetectionSetEnabled = useNativeObjectDetectionSetEnabled;
|
|
51024
|
+
exports.useNavigation = useNavigation;
|
|
51025
|
+
exports.useNavigationGetFeatures = useNavigationGetFeatures;
|
|
51026
|
+
exports.useNavigationGetStatus = useNavigationGetStatus;
|
|
51027
|
+
exports.useNavigationGoToPoint = useNavigationGoToPoint;
|
|
51028
|
+
exports.useNavigationListActions = useNavigationListActions;
|
|
51029
|
+
exports.useNavigationMove = useNavigationMove;
|
|
51030
|
+
exports.useNavigationPlaySound = useNavigationPlaySound;
|
|
51031
|
+
exports.useNavigationRunAction = useNavigationRunAction;
|
|
51032
|
+
exports.useNavigationSetLightLevel = useNavigationSetLightLevel;
|
|
51033
|
+
exports.useNavigationSetLightMode = useNavigationSetLightMode;
|
|
51034
|
+
exports.useNavigationSetLightOn = useNavigationSetLightOn;
|
|
51035
|
+
exports.useNavigationStop = useNavigationStop;
|
|
50565
51036
|
exports.useNetworkAccessGetEndpoint = useNetworkAccessGetEndpoint;
|
|
50566
51037
|
exports.useNetworkAccessGetStatus = useNetworkAccessGetStatus;
|
|
50567
51038
|
exports.useNetworkAccessListEndpoints = useNetworkAccessListEndpoints;
|
|
50568
51039
|
exports.useNetworkAccessStart = useNetworkAccessStart;
|
|
50569
51040
|
exports.useNetworkAccessStop = useNetworkAccessStop;
|
|
51041
|
+
exports.useNetworkLinkGetStatus = useNetworkLinkGetStatus;
|
|
50570
51042
|
exports.useNetworkQualityGetAllStats = useNetworkQualityGetAllStats;
|
|
50571
51043
|
exports.useNetworkQualityGetDeviceStats = useNetworkQualityGetDeviceStats;
|
|
50572
51044
|
exports.useNetworkQualityReportClientStats = useNetworkQualityReportClientStats;
|