@viamrobotics/test-widgets 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/dist/client-map.d.ts +30 -30
- package/dist/client-map.js +32 -29
- package/dist/components/index.d.ts +22 -0
- package/dist/components/index.js +22 -0
- package/dist/components/is-moving.svelte +1 -4
- package/dist/components/mutation-section.svelte +1 -1
- package/dist/components/navigation-map/components/obstacle.svelte +2 -1
- package/dist/components/three/capsule-geometry.d.ts +10 -0
- package/dist/components/three/capsule-geometry.js +19 -0
- package/dist/components/three/index.d.ts +1 -0
- package/dist/components/three/index.js +1 -0
- package/dist/components/widgets/arm/arm.svelte +8 -5
- package/dist/components/widgets/arm/get-joint-positions-widget.svelte +36 -0
- package/dist/components/widgets/arm/get-joint-positions-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/arm/is-moving-widget.svelte +20 -0
- package/dist/components/widgets/arm/is-moving-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/arm/move-to-joint-positions-widget.svelte +9 -5
- package/dist/components/widgets/arm/move-to-position.svelte +31 -3
- package/dist/components/widgets/audio-input/get-properties-widget.svelte +43 -0
- package/dist/components/widgets/audio-input/get-properties-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/audio-output/get-properties-widget.svelte +43 -0
- package/dist/components/widgets/audio-output/get-properties-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/base/is-moving-widget.svelte +20 -0
- package/dist/components/widgets/base/is-moving-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/base/quick-move.svelte +12 -5
- package/dist/components/widgets/camera/live-or-polling-video.svelte +8 -1
- package/dist/components/widgets/do-command/do-command.svelte +21 -7
- package/dist/components/widgets/do-command/do-command.svelte.d.ts +8 -1
- package/dist/components/widgets/encoder/encoder-position-type.d.ts +8 -0
- package/dist/components/widgets/encoder/encoder-position-type.js +20 -0
- package/dist/components/widgets/encoder/encoder.svelte +3 -20
- package/dist/components/widgets/encoder/get-position-widget.svelte +54 -0
- package/dist/components/widgets/encoder/get-position-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/gantry/get-position-widget.svelte +43 -0
- package/dist/components/widgets/gantry/get-position-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/gantry/is-moving-widget.svelte +20 -0
- package/dist/components/widgets/gantry/is-moving-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/gripper/gripper.svelte +1 -1
- package/dist/components/widgets/gripper/is-holding-something.svelte +1 -4
- package/dist/components/widgets/gripper/is-moving-widget.svelte +20 -0
- package/dist/components/widgets/gripper/is-moving-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/motion/component-name-select.svelte +29 -0
- package/dist/components/widgets/motion/component-name-select.svelte.d.ts +9 -0
- package/dist/components/widgets/motion/frame-system-config.d.ts +28 -0
- package/dist/components/widgets/motion/frame-system-config.js +30 -0
- package/dist/components/widgets/motion/motion.svelte +27 -0
- package/dist/components/widgets/motion/motion.svelte.d.ts +7 -0
- package/dist/components/widgets/motion/move-widget.svelte +84 -0
- package/dist/components/widgets/motion/move-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/motion/move.svelte +127 -0
- package/dist/components/widgets/motion/move.svelte.d.ts +14 -0
- package/dist/components/widgets/motion/parse-move-args.d.ts +24 -0
- package/dist/components/widgets/motion/parse-move-args.js +23 -0
- package/dist/components/widgets/motion/parse-pasted-pose.d.ts +10 -0
- package/dist/components/widgets/motion/parse-pasted-pose.js +30 -0
- package/dist/components/widgets/motion/pose-in-frame-input.svelte +168 -0
- package/dist/components/widgets/motion/pose-in-frame-input.svelte.d.ts +10 -0
- package/dist/components/widgets/motor/is-moving-widget.svelte +20 -0
- package/dist/components/widgets/motor/is-moving-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/motor/motor.svelte +2 -8
- package/dist/components/widgets/movement-sensor/get-accuracy-widget.svelte +38 -0
- package/dist/components/widgets/movement-sensor/get-accuracy-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/movement-sensor/get-compass-heading-widget.svelte +38 -0
- package/dist/components/widgets/movement-sensor/get-compass-heading-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/movement-sensor/get-orientation-widget.svelte +38 -0
- package/dist/components/widgets/movement-sensor/get-orientation-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/movement-sensor/get-position-widget.svelte +38 -0
- package/dist/components/widgets/movement-sensor/get-position-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/navigation/obstacles/meshes.svelte +1 -2
- package/dist/components/widgets/power-sensor/get-current-widget.svelte +38 -0
- package/dist/components/widgets/power-sensor/get-current-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/power-sensor/get-power-widget.svelte +38 -0
- package/dist/components/widgets/power-sensor/get-power-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/power-sensor/get-voltage-widget.svelte +38 -0
- package/dist/components/widgets/power-sensor/get-voltage-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/servo/is-moving-widget.svelte +20 -0
- package/dist/components/widgets/servo/is-moving-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/slam/get-position-widget.svelte +38 -0
- package/dist/components/widgets/slam/get-position-widget.svelte.d.ts +7 -0
- package/dist/components/widgets/vision-service/vision-service.svelte +9 -10
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/is-known-resource.d.ts +3 -0
- package/dist/is-known-resource.js +5 -0
- package/dist/pip/context.svelte.d.ts +2 -0
- package/dist/pip/context.svelte.js +48 -20
- package/dist/registry.d.ts +28 -0
- package/dist/registry.js +176 -0
- package/dist/resource-triplet.d.ts +37 -0
- package/dist/resource-triplet.js +37 -0
- package/dist/resource-widget-types.d.ts +21 -0
- package/dist/resource-widget-types.js +1 -0
- package/dist/resource.d.ts +0 -9
- package/dist/resource.js +0 -72
- package/dist/show-resource-widget.d.ts +3 -0
- package/dist/show-resource-widget.js +10 -0
- package/package.json +23 -6
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { MovementSensorClient } from '@viamrobotics/sdk'
|
|
3
|
+
import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk'
|
|
4
|
+
|
|
5
|
+
import ApiSection from '../../api-section.svelte'
|
|
6
|
+
import Query from '../../query.svelte'
|
|
7
|
+
|
|
8
|
+
import CompassHeading from './compass-heading.svelte'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
partID: string
|
|
12
|
+
resourceName: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { partID, resourceName }: Props = $props()
|
|
16
|
+
|
|
17
|
+
const client = createResourceClient(
|
|
18
|
+
MovementSensorClient,
|
|
19
|
+
() => partID,
|
|
20
|
+
() => resourceName
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const query = createResourceQuery(client, 'getCompassHeading', { refetchInterval: 500 })
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<ApiSection
|
|
27
|
+
title="GetCompassHeading"
|
|
28
|
+
class="grow"
|
|
29
|
+
>
|
|
30
|
+
<Query
|
|
31
|
+
{query}
|
|
32
|
+
contentCx="h-6"
|
|
33
|
+
>
|
|
34
|
+
{#if query.data !== undefined}
|
|
35
|
+
<CompassHeading data={query.data} />
|
|
36
|
+
{/if}
|
|
37
|
+
</Query>
|
|
38
|
+
</ApiSection>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { MovementSensorClient } from '@viamrobotics/sdk'
|
|
3
|
+
import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk'
|
|
4
|
+
|
|
5
|
+
import ApiSection from '../../api-section.svelte'
|
|
6
|
+
import Query from '../../query.svelte'
|
|
7
|
+
|
|
8
|
+
import Orientation from './orientation.svelte'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
partID: string
|
|
12
|
+
resourceName: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { partID, resourceName }: Props = $props()
|
|
16
|
+
|
|
17
|
+
const client = createResourceClient(
|
|
18
|
+
MovementSensorClient,
|
|
19
|
+
() => partID,
|
|
20
|
+
() => resourceName
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const query = createResourceQuery(client, 'getOrientation', { refetchInterval: 500 })
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<ApiSection
|
|
27
|
+
title="GetOrientation"
|
|
28
|
+
class="grow"
|
|
29
|
+
>
|
|
30
|
+
<Query
|
|
31
|
+
{query}
|
|
32
|
+
contentCx="h-6"
|
|
33
|
+
>
|
|
34
|
+
{#if query.data !== undefined}
|
|
35
|
+
<Orientation data={query.data} />
|
|
36
|
+
{/if}
|
|
37
|
+
</Query>
|
|
38
|
+
</ApiSection>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { MovementSensorClient } from '@viamrobotics/sdk'
|
|
3
|
+
import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk'
|
|
4
|
+
|
|
5
|
+
import ApiSection from '../../api-section.svelte'
|
|
6
|
+
import Query from '../../query.svelte'
|
|
7
|
+
|
|
8
|
+
import Position from './position.svelte'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
partID: string
|
|
12
|
+
resourceName: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { partID, resourceName }: Props = $props()
|
|
16
|
+
|
|
17
|
+
const client = createResourceClient(
|
|
18
|
+
MovementSensorClient,
|
|
19
|
+
() => partID,
|
|
20
|
+
() => resourceName
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const query = createResourceQuery(client, 'getPosition', { refetchInterval: 500 })
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<ApiSection
|
|
27
|
+
title="GetPosition"
|
|
28
|
+
class="grow"
|
|
29
|
+
>
|
|
30
|
+
<Query
|
|
31
|
+
{query}
|
|
32
|
+
contentCx="h-6"
|
|
33
|
+
>
|
|
34
|
+
{#if query.data !== undefined}
|
|
35
|
+
<Position data={query.data} />
|
|
36
|
+
{/if}
|
|
37
|
+
</Query>
|
|
38
|
+
</ApiSection>
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
import type { GeoGeometry } from '@viamrobotics/sdk'
|
|
3
3
|
|
|
4
4
|
import { T } from '@threlte/core'
|
|
5
|
-
import { CapsuleGeometry } from '@viamrobotics/motion-tools/lib'
|
|
6
5
|
import { type BufferGeometry, MathUtils } from 'three'
|
|
7
6
|
|
|
8
|
-
import { AxesHelper } from '../../../three'
|
|
7
|
+
import { AxesHelper, CapsuleGeometry } from '../../../three'
|
|
9
8
|
|
|
10
9
|
import { getColor } from './color'
|
|
11
10
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { PowerSensorClient } from '@viamrobotics/sdk'
|
|
3
|
+
import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk'
|
|
4
|
+
|
|
5
|
+
import ApiSection from '../../api-section.svelte'
|
|
6
|
+
import Query from '../../query.svelte'
|
|
7
|
+
|
|
8
|
+
import CurrentReading from './current-reading.svelte'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
partID: string
|
|
12
|
+
resourceName: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { partID, resourceName }: Props = $props()
|
|
16
|
+
|
|
17
|
+
const client = createResourceClient(
|
|
18
|
+
PowerSensorClient,
|
|
19
|
+
() => partID,
|
|
20
|
+
() => resourceName
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const query = createResourceQuery(client, 'getCurrent', { refetchInterval: 500 })
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<ApiSection
|
|
27
|
+
title="GetCurrent"
|
|
28
|
+
class="grow"
|
|
29
|
+
>
|
|
30
|
+
<Query
|
|
31
|
+
{query}
|
|
32
|
+
contentCx="h-6"
|
|
33
|
+
>
|
|
34
|
+
{#if query.data !== undefined}
|
|
35
|
+
<CurrentReading data={query.data} />
|
|
36
|
+
{/if}
|
|
37
|
+
</Query>
|
|
38
|
+
</ApiSection>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { PowerSensorClient } from '@viamrobotics/sdk'
|
|
3
|
+
import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk'
|
|
4
|
+
|
|
5
|
+
import ApiSection from '../../api-section.svelte'
|
|
6
|
+
import Query from '../../query.svelte'
|
|
7
|
+
|
|
8
|
+
import PowerReading from './power-reading.svelte'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
partID: string
|
|
12
|
+
resourceName: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { partID, resourceName }: Props = $props()
|
|
16
|
+
|
|
17
|
+
const client = createResourceClient(
|
|
18
|
+
PowerSensorClient,
|
|
19
|
+
() => partID,
|
|
20
|
+
() => resourceName
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const query = createResourceQuery(client, 'getPower', { refetchInterval: 500 })
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<ApiSection
|
|
27
|
+
title="GetPower"
|
|
28
|
+
class="grow"
|
|
29
|
+
>
|
|
30
|
+
<Query
|
|
31
|
+
{query}
|
|
32
|
+
contentCx="h-6"
|
|
33
|
+
>
|
|
34
|
+
{#if query.data !== undefined}
|
|
35
|
+
<PowerReading data={query.data} />
|
|
36
|
+
{/if}
|
|
37
|
+
</Query>
|
|
38
|
+
</ApiSection>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { PowerSensorClient } from '@viamrobotics/sdk'
|
|
3
|
+
import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk'
|
|
4
|
+
|
|
5
|
+
import ApiSection from '../../api-section.svelte'
|
|
6
|
+
import Query from '../../query.svelte'
|
|
7
|
+
|
|
8
|
+
import VoltageReading from './voltage-reading.svelte'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
partID: string
|
|
12
|
+
resourceName: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { partID, resourceName }: Props = $props()
|
|
16
|
+
|
|
17
|
+
const client = createResourceClient(
|
|
18
|
+
PowerSensorClient,
|
|
19
|
+
() => partID,
|
|
20
|
+
() => resourceName
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const query = createResourceQuery(client, 'getVoltage', { refetchInterval: 500 })
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<ApiSection
|
|
27
|
+
title="GetVoltage"
|
|
28
|
+
class="grow"
|
|
29
|
+
>
|
|
30
|
+
<Query
|
|
31
|
+
{query}
|
|
32
|
+
contentCx="h-6"
|
|
33
|
+
>
|
|
34
|
+
{#if query.data !== undefined}
|
|
35
|
+
<VoltageReading data={query.data} />
|
|
36
|
+
{/if}
|
|
37
|
+
</Query>
|
|
38
|
+
</ApiSection>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ServoClient } from '@viamrobotics/sdk'
|
|
3
|
+
|
|
4
|
+
import IsMoving from '../../is-moving.svelte'
|
|
5
|
+
import { ResourceTriplets } from '../../../resource-triplet'
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
partID: string
|
|
9
|
+
resourceName: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const { partID, resourceName }: Props = $props()
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<IsMoving
|
|
16
|
+
client={ServoClient}
|
|
17
|
+
api={ResourceTriplets.Servo}
|
|
18
|
+
{partID}
|
|
19
|
+
{resourceName}
|
|
20
|
+
/>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { SlamClient } from '@viamrobotics/sdk'
|
|
3
|
+
import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk'
|
|
4
|
+
|
|
5
|
+
import ApiSection from '../../api-section.svelte'
|
|
6
|
+
import Query from '../../query.svelte'
|
|
7
|
+
|
|
8
|
+
import Position from './position.svelte'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
partID: string
|
|
12
|
+
resourceName: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { partID, resourceName }: Props = $props()
|
|
16
|
+
|
|
17
|
+
const client = createResourceClient(
|
|
18
|
+
SlamClient,
|
|
19
|
+
() => partID,
|
|
20
|
+
() => resourceName
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const query = createResourceQuery(client, 'getPosition', { refetchInterval: 1000 })
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<ApiSection
|
|
27
|
+
title="GetPosition"
|
|
28
|
+
class="grow"
|
|
29
|
+
>
|
|
30
|
+
<Query
|
|
31
|
+
{query}
|
|
32
|
+
contentCx="h-6"
|
|
33
|
+
>
|
|
34
|
+
{#if query.data !== undefined}
|
|
35
|
+
<Position position={query.data} />
|
|
36
|
+
{/if}
|
|
37
|
+
</Query>
|
|
38
|
+
</ApiSection>
|
|
@@ -147,16 +147,15 @@
|
|
|
147
147
|
</Select>
|
|
148
148
|
</Label>
|
|
149
149
|
</div>
|
|
150
|
-
<
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
</Label>
|
|
150
|
+
<div class="w-fit">
|
|
151
|
+
<Label position="top">
|
|
152
|
+
Is remote?
|
|
153
|
+
<Switch
|
|
154
|
+
slot="input"
|
|
155
|
+
bind:on={isRemote}
|
|
156
|
+
/>
|
|
157
|
+
</Label>
|
|
158
|
+
</div>
|
|
160
159
|
</div>
|
|
161
160
|
|
|
162
161
|
<h6 class="text-subtle-1 font-semibold">Detections/Classifications</h6>
|
package/dist/index.d.ts
CHANGED
|
@@ -3,5 +3,10 @@ export { apiDocsHref } from './api-docs-href';
|
|
|
3
3
|
export { clientForResource } from './client-map';
|
|
4
4
|
export * from './components';
|
|
5
5
|
export { getResourceAPI } from './get-resource-api';
|
|
6
|
+
export { isKnownResource,
|
|
7
|
+
/** @deprecated use `isKnownResource` instead. Will be deleted in the next release */
|
|
8
|
+
isKnownResource as hasWidget, } from './is-known-resource';
|
|
6
9
|
export { providePip, usePip } from './pip/context.svelte';
|
|
7
|
-
export {
|
|
10
|
+
export { ResourceTriplets } from './resource-triplet';
|
|
11
|
+
export type { ResourceAPIWidget, ResourceWidget, ResourceWidgetProps, } from './resource-widget-types';
|
|
12
|
+
export { showResourceWidget } from './show-resource-widget';
|
package/dist/index.js
CHANGED
|
@@ -3,5 +3,10 @@ export { apiDocsHref } from './api-docs-href';
|
|
|
3
3
|
export { clientForResource } from './client-map';
|
|
4
4
|
export * from './components';
|
|
5
5
|
export { getResourceAPI } from './get-resource-api';
|
|
6
|
+
export { isKnownResource,
|
|
7
|
+
// TODO: Delete `hasWidget`
|
|
8
|
+
/** @deprecated use `isKnownResource` instead. Will be deleted in the next release */
|
|
9
|
+
isKnownResource as hasWidget, } from './is-known-resource';
|
|
6
10
|
export { providePip, usePip } from './pip/context.svelte';
|
|
7
|
-
export {
|
|
11
|
+
export { ResourceTriplets } from './resource-triplet';
|
|
12
|
+
export { showResourceWidget } from './show-resource-widget';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { getResourceAPI } from "./get-resource-api.js";
|
|
2
|
+
import { ResourceTriplets } from "./resource-triplet.js";
|
|
3
|
+
const knownResources = new Set(Object.values(ResourceTriplets));
|
|
4
|
+
/** Whether a resource's API is a recognized Viam resource triplet. */
|
|
5
|
+
export const isKnownResource = (resource) => knownResources.has(getResourceAPI(resource));
|
|
@@ -2,6 +2,8 @@ interface PipContext {
|
|
|
2
2
|
/** Called by PictureInPictureButton to start or stop PiP. */
|
|
3
3
|
toggle(resourceName: string): Promise<void>;
|
|
4
4
|
setRate(rate: 'live' | number | false): void;
|
|
5
|
+
/** Register the media stream from the main camera view when its card is open. */
|
|
6
|
+
setStream(resourceName: string, stream: MediaStream | null): void;
|
|
5
7
|
error: Error | undefined;
|
|
6
8
|
/** Whether the PictureInPicture is active */
|
|
7
9
|
readyState: 'inactive' | 'loading' | 'active';
|
|
@@ -14,12 +14,21 @@ export function providePip(partID) {
|
|
|
14
14
|
const canvasCtx = canvas.getContext('2d');
|
|
15
15
|
const canvasStream = canvas.captureStream();
|
|
16
16
|
const img = document.createElement('img');
|
|
17
|
+
const externalStreams = new Map();
|
|
18
|
+
let externalStreamVersion = $state(0);
|
|
17
19
|
let error = $state();
|
|
18
20
|
let readyState = $state('inactive');
|
|
19
21
|
let rate = $state('live');
|
|
20
22
|
let activeName = $state();
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
+
const externalStream = $derived.by(() => {
|
|
24
|
+
void externalStreamVersion;
|
|
25
|
+
return activeName ? externalStreams.get(activeName) : undefined;
|
|
26
|
+
});
|
|
27
|
+
const needsOwnedStream = $derived(activeName !== undefined && !externalStream);
|
|
28
|
+
const cameraClient = $derived(needsOwnedStream && activeName
|
|
29
|
+
? createResourceClient(CameraClient, partID, () => activeName ?? '')
|
|
30
|
+
: undefined);
|
|
31
|
+
const streamClient = $derived(needsOwnedStream && activeName ? createStreamClient(partID, () => activeName ?? '') : undefined);
|
|
23
32
|
const imageQuery = $derived(cameraClient?.current
|
|
24
33
|
? createResourceQuery(cameraClient, 'getImages', () => ({
|
|
25
34
|
enabled: rate !== 'live',
|
|
@@ -27,22 +36,39 @@ export function providePip(partID) {
|
|
|
27
36
|
refetchIntervalInBackground: activeName === cameraClient?.current?.name,
|
|
28
37
|
}))
|
|
29
38
|
: undefined);
|
|
30
|
-
const
|
|
39
|
+
const ownedMediaStream = $derived(needsOwnedStream ? ((rate === 'live' ? streamClient?.mediaStream : canvasStream) ?? null) : null);
|
|
40
|
+
const playbackStream = $derived(externalStream ?? ownedMediaStream);
|
|
41
|
+
const setStream = (resourceName, stream) => {
|
|
42
|
+
if (stream) {
|
|
43
|
+
externalStreams.set(resourceName, stream);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
externalStreams.delete(resourceName);
|
|
47
|
+
}
|
|
48
|
+
externalStreamVersion++;
|
|
49
|
+
};
|
|
31
50
|
$effect(() => {
|
|
32
51
|
document.body.append(video);
|
|
52
|
+
const handleLeave = () => {
|
|
53
|
+
readyState = 'inactive';
|
|
54
|
+
activeName = undefined;
|
|
55
|
+
error = undefined;
|
|
56
|
+
};
|
|
57
|
+
video.addEventListener('leavepictureinpicture', handleLeave);
|
|
33
58
|
return () => {
|
|
59
|
+
video.removeEventListener('leavepictureinpicture', handleLeave);
|
|
34
60
|
video.remove();
|
|
35
61
|
};
|
|
36
62
|
});
|
|
37
63
|
$effect(() => {
|
|
38
|
-
video.srcObject =
|
|
64
|
+
video.srcObject = playbackStream;
|
|
39
65
|
return () => {
|
|
40
66
|
video.srcObject = null;
|
|
41
67
|
};
|
|
42
68
|
});
|
|
43
69
|
$effect(() => {
|
|
44
70
|
const currentRate = rate;
|
|
45
|
-
if (currentRate === 'live')
|
|
71
|
+
if (!needsOwnedStream || currentRate === 'live')
|
|
46
72
|
return;
|
|
47
73
|
const image = imageQuery?.data?.images[0];
|
|
48
74
|
if (!image)
|
|
@@ -64,12 +90,11 @@ export function providePip(partID) {
|
|
|
64
90
|
img.removeEventListener('load', drawImage);
|
|
65
91
|
};
|
|
66
92
|
});
|
|
67
|
-
const toggle = async () => {
|
|
68
|
-
if (activeName ===
|
|
69
|
-
readyState === 'active' &&
|
|
70
|
-
document.pictureInPictureElement === video) {
|
|
93
|
+
const toggle = async (resourceName) => {
|
|
94
|
+
if (activeName === resourceName && document.pictureInPictureElement === video) {
|
|
71
95
|
try {
|
|
72
96
|
await document.exitPictureInPicture();
|
|
97
|
+
activeName = undefined;
|
|
73
98
|
readyState = 'inactive';
|
|
74
99
|
error = undefined;
|
|
75
100
|
}
|
|
@@ -78,28 +103,31 @@ export function providePip(partID) {
|
|
|
78
103
|
}
|
|
79
104
|
return;
|
|
80
105
|
}
|
|
106
|
+
activeName = resourceName;
|
|
81
107
|
readyState = 'loading';
|
|
82
|
-
// Wait for the new stream's metadata to load before requesting PiP,
|
|
83
|
-
// otherwise the browser throws InvalidStateError.
|
|
84
|
-
if (video.readyState < 1 /* HAVE_METADATA */) {
|
|
85
|
-
await new Promise((resolve) => {
|
|
86
|
-
video.addEventListener('loadedmetadata', () => resolve(), { once: true });
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
108
|
try {
|
|
109
|
+
const stream = ownedMediaStream;
|
|
110
|
+
video.srcObject = stream;
|
|
111
|
+
// Wait for the stream's metadata to load before requesting PiP,
|
|
112
|
+
// otherwise the browser throws InvalidStateError.
|
|
113
|
+
if (video.readyState < 1 /* HAVE_METADATA */) {
|
|
114
|
+
await new Promise((resolve) => {
|
|
115
|
+
video.addEventListener('loadedmetadata', () => resolve(), { once: true });
|
|
116
|
+
});
|
|
117
|
+
}
|
|
90
118
|
await video.requestPictureInPicture();
|
|
91
119
|
readyState = 'active';
|
|
92
120
|
error = undefined;
|
|
93
121
|
}
|
|
94
122
|
catch (nextError) {
|
|
123
|
+
readyState = 'inactive';
|
|
124
|
+
activeName = undefined;
|
|
95
125
|
error = nextError;
|
|
96
126
|
}
|
|
97
127
|
};
|
|
98
128
|
const context = {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
await toggle();
|
|
102
|
-
},
|
|
129
|
+
toggle,
|
|
130
|
+
setStream,
|
|
103
131
|
setRate(newRate) {
|
|
104
132
|
rate = newRate;
|
|
105
133
|
},
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ResourceName } from '@viamrobotics/sdk';
|
|
2
|
+
import type { ResourceAPIWidget, ResourceWidget } from './resource-widget-types.ts';
|
|
3
|
+
import { type ResourceTriplet } from './resource-triplet.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Returns a resource's individual API widgets. Each entry carries a stable `id`, a
|
|
6
|
+
* display `label`, and the `widgets` to render with `{ partID, resourceName }`.
|
|
7
|
+
*
|
|
8
|
+
* Returns `[]` for a resource with a card but no standalone API widgets, and for
|
|
9
|
+
* unrecognized resources.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* apiWidgetsForResource(gripperResourceName)
|
|
13
|
+
* // [{ id: 'open-grab', label: 'Open / Grab', widgets: [GripperOpenWidget, GripperGrabWidget] }, ...]
|
|
14
|
+
*/
|
|
15
|
+
export declare const apiWidgetsForResource: (resource: ResourceName) => ResourceAPIWidget[];
|
|
16
|
+
/**
|
|
17
|
+
* Returns every resource triplet that has a test card, mapped to its API widgets.
|
|
18
|
+
* Use this to enumerate the full catalog, e.g. a menu spanning every resource type;
|
|
19
|
+
* for a single resource, prefer `apiWidgetsForResource`.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* availableAPIWidgets()[ResourceTriplets.Gripper]
|
|
23
|
+
* // [{ id: 'open-grab', label: 'Open / Grab', widgets: [GripperOpenWidget, GripperGrabWidget] }, ...]
|
|
24
|
+
*/
|
|
25
|
+
export declare const availableAPIWidgets: () => Partial<Record<ResourceTriplet, ResourceAPIWidget[]>>;
|
|
26
|
+
/** Returns the full composite test card for a resource, or `undefined` if none exists. */
|
|
27
|
+
export declare const widgetForResource: (resource: ResourceName) => ResourceWidget | undefined;
|
|
28
|
+
export type { ResourceAPIWidget, ResourceWidget, ResourceWidgetProps, } from './resource-widget-types.ts';
|