@viamrobotics/motion-tools 1.1.3 → 1.1.5

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/color.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { Color } from 'three';
2
2
  import twColors from 'tailwindcss/colors';
3
- import { isNumber } from 'lodash-es';
4
3
  import { ResourceName } from '@viamrobotics/sdk';
5
4
  // Step 3: linear sRGB → sRGB
6
5
  const linearToSrgb = (x) => {
@@ -104,7 +103,7 @@ export const isRGB = (color) => {
104
103
  !('b' in color)) {
105
104
  return false;
106
105
  }
107
- return isNumber(color.r) && isNumber(color.g) && isNumber(color.b);
106
+ return typeof color.r === 'number' && typeof color.g === 'number' && typeof color.b === 'number';
108
107
  };
109
108
  export const parseRGB = (color, defaultColor = { r: 0, g: 0, b: 0 }) => {
110
109
  if (!isRGB(color))
@@ -112,8 +111,9 @@ export const parseRGB = (color, defaultColor = { r: 0, g: 0, b: 0 }) => {
112
111
  return new Color().setRGB(color.r > 1 ? color.r / 255 : color.r, color.g > 1 ? color.g / 255 : color.g, color.b > 1 ? color.b / 255 : color.b);
113
112
  };
114
113
  export const parseOpacity = (opacity, defaultOpacity = 1) => {
115
- if (!isNumber(opacity))
114
+ if (typeof opacity !== 'number') {
116
115
  return defaultOpacity;
116
+ }
117
117
  return opacity > 1 ? opacity / 100 : opacity;
118
118
  };
119
119
  const isColor = (color) => {
@@ -22,6 +22,10 @@
22
22
  import { provideEnvironment } from '../hooks/useEnvironment.svelte'
23
23
  import type { CameraPose } from '../hooks/useControls.svelte'
24
24
  import { provideWorld } from '../ecs'
25
+ import {
26
+ provideDrawConnectionConfig,
27
+ type DrawConnectionConfig,
28
+ } from '../hooks/useDrawConnectionConfig.svelte'
25
29
 
26
30
  interface LocalConfigProps {
27
31
  getLocalPartConfig: () => Struct
@@ -36,6 +40,7 @@
36
40
  children?: Snippet
37
41
  dashboard?: Snippet
38
42
  localConfigProps?: LocalConfigProps
43
+ drawConnectionConfig?: DrawConnectionConfig
39
44
 
40
45
  /**
41
46
  * Allows setting the initial camera pose
@@ -48,6 +53,7 @@
48
53
  enableKeybindings = true,
49
54
  localConfigProps,
50
55
  cameraPose,
56
+ drawConnectionConfig,
51
57
  children: appChildren,
52
58
  dashboard,
53
59
  }: Props = $props()
@@ -63,7 +69,7 @@
63
69
  })
64
70
 
65
71
  createPartIDContext(() => partID)
66
-
72
+ provideDrawConnectionConfig(() => drawConnectionConfig)
67
73
  provideWeblabs()
68
74
  provideToast()
69
75
 
@@ -1,6 +1,7 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { Struct } from '@viamrobotics/sdk';
3
3
  import type { CameraPose } from '../hooks/useControls.svelte';
4
+ import { type DrawConnectionConfig } from '../hooks/useDrawConnectionConfig.svelte';
4
5
  interface LocalConfigProps {
5
6
  getLocalPartConfig: () => Struct;
6
7
  setLocalPartConfig: (config: Struct) => void;
@@ -13,6 +14,7 @@ interface Props {
13
14
  children?: Snippet;
14
15
  dashboard?: Snippet;
15
16
  localConfigProps?: LocalConfigProps;
17
+ drawConnectionConfig?: DrawConnectionConfig;
16
18
  /**
17
19
  * Allows setting the initial camera pose
18
20
  */
@@ -13,7 +13,6 @@
13
13
  provideTransformControls,
14
14
  type CameraPose,
15
15
  } from '../hooks/useControls.svelte'
16
- import { provideMotionClient } from '../hooks/useMotionClient.svelte'
17
16
  import { provideLogs } from '../hooks/useLogs.svelte'
18
17
  import { provideOrigin } from './xr/useOrigin.svelte'
19
18
  import { provideWorldStates } from '../hooks/useWorldState.svelte'
@@ -45,7 +44,6 @@
45
44
  provideGeometries(() => partID.current)
46
45
  provide3DModels(() => partID.current)
47
46
  providePointclouds(() => partID.current)
48
- provideMotionClient(() => partID.current)
49
47
  provideArmClient(() => partID.current)
50
48
  provideWorldStates()
51
49
  provideFramelessComponents()
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { Select, Switch, Input } from '@viamrobotics/prime-core'
3
3
  import RefreshRate from '../RefreshRate.svelte'
4
- import { useMotionClient } from '../../hooks/useMotionClient.svelte'
5
4
  import Drawer from './Drawer.svelte'
6
5
  import { useSettings } from '../../hooks/useSettings.svelte'
7
6
  import { useResourceNames } from '@viamrobotics/svelte-sdk'
@@ -19,10 +18,8 @@
19
18
  const cameras = useResourceNames(() => partID.current, 'camera')
20
19
  const settings = useSettings()
21
20
  const { disabledCameras } = useMachineSettings()
22
- const motionClient = useMotionClient()
23
21
  const geometries = useGeometries()
24
22
  const pointclouds = usePointClouds()
25
-
26
23
  const { refetchPoses } = useRefetchPoses()
27
24
 
28
25
  // Invalidate the renderer for any settings change
@@ -76,22 +73,6 @@
76
73
  {/each}
77
74
  </div>
78
75
 
79
- <label class="flex flex-col gap-1">
80
- Motion client
81
- <Select
82
- onchange={(event: InputEvent) => {
83
- if (event.target instanceof HTMLSelectElement) {
84
- motionClient.set(event.target.value)
85
- }
86
- }}
87
- value={motionClient.current}
88
- >
89
- {#each motionClient.names as name (name)}
90
- <option>{name}</option>
91
- {/each}
92
- </Select>
93
- </label>
94
-
95
76
  <h3 class="pt-2 text-sm"><strong>Pointclouds</strong></h3>
96
77
  <div class="flex flex-col gap-2.5">
97
78
  <label class="flex items-center justify-between gap-2">
@@ -69,41 +69,39 @@
69
69
  })
70
70
  </script>
71
71
 
72
- {#if resizable.isLoaded}
73
- <div
74
- bind:this={container}
75
- class="bg-extralight border-medium absolute top-0 left-0 z-1000 m-2 resize overflow-y-auto border text-xs"
76
- style:min-width="{MIN_DIMENSIONS.width}px"
77
- style:min-height="{MIN_DIMENSIONS.height}px"
78
- style:width={resizable.current ? `${resizable.current.width}px` : undefined}
79
- style:height={resizable.current ? `${resizable.current.height}px` : undefined}
80
- use:draggable={{
81
- bounds: 'body',
82
- handle: dragElement,
83
- defaultPosition: dragPosition.current,
84
- onDragEnd(data) {
85
- dragPosition.current = { x: data.offsetX, y: data.offsetY }
86
- },
87
- }}
88
- {...rest}
89
- >
90
- <Tree
91
- {rootNode}
92
- {nodeMap}
93
- bind:dragElement
94
- onSelectionChange={(event) => {
95
- const value = event.selectedValue[0]
72
+ <div
73
+ bind:this={container}
74
+ class="bg-extralight border-medium absolute top-0 left-0 z-1000 m-2 resize overflow-y-auto border text-xs"
75
+ style:min-width="{MIN_DIMENSIONS.width}px"
76
+ style:min-height="{MIN_DIMENSIONS.height}px"
77
+ style:width={resizable.current ? `${resizable.current.width}px` : undefined}
78
+ style:height={resizable.current ? `${resizable.current.height}px` : undefined}
79
+ use:draggable={{
80
+ bounds: 'body',
81
+ handle: dragElement,
82
+ defaultPosition: dragPosition.current,
83
+ onDragEnd(data) {
84
+ dragPosition.current = { x: Math.max(data.offsetX, 0), y: Math.max(data.offsetY, 0) }
85
+ },
86
+ }}
87
+ {...rest}
88
+ >
89
+ <Tree
90
+ {rootNode}
91
+ {nodeMap}
92
+ bind:dragElement
93
+ onSelectionChange={(event) => {
94
+ const value = event.selectedValue[0]
96
95
 
97
- selectedEntity.set(value ? (Number(value) as Entity) : undefined)
98
- }}
99
- />
96
+ selectedEntity.set(value ? (Number(value) as Entity) : undefined)
97
+ }}
98
+ />
100
99
 
101
- {#if environment.current.isStandalone && partID.current && partConfig.hasEditPermissions}
102
- <AddFrames />
103
- {/if}
100
+ {#if environment.current.isStandalone && partID.current && partConfig.hasEditPermissions}
101
+ <AddFrames />
102
+ {/if}
104
103
 
105
- <Logs />
106
- <Settings />
107
- <Widgets />
108
- </div>
109
- {/if}
104
+ <Logs />
105
+ <Settings />
106
+ <Widgets />
107
+ </div>
@@ -1,14 +1,15 @@
1
1
  <script lang="ts">
2
2
  import { Icon, type IconName, Tooltip } from '@viamrobotics/prime-core'
3
3
  import { Ruler } from 'lucide-svelte'
4
+ import type { ClassValue, MouseEventHandler } from 'svelte/elements'
4
5
 
5
6
  interface Props {
6
7
  icon: IconName | 'ruler'
7
8
  active?: boolean
8
9
  description: string
9
10
  hotkey?: string
10
- class?: string
11
- onclick?: () => void
11
+ class?: ClassValue | null | undefined
12
+ onclick?: MouseEventHandler<HTMLButtonElement> | null | undefined
12
13
  }
13
14
 
14
15
  let {
@@ -1,11 +1,12 @@
1
1
  import { type IconName } from '@viamrobotics/prime-core';
2
+ import type { ClassValue, MouseEventHandler } from 'svelte/elements';
2
3
  interface Props {
3
4
  icon: IconName | 'ruler';
4
5
  active?: boolean;
5
6
  description: string;
6
7
  hotkey?: string;
7
- class?: string;
8
- onclick?: () => void;
8
+ class?: ClassValue | null | undefined;
9
+ onclick?: MouseEventHandler<HTMLButtonElement> | null | undefined;
9
10
  }
10
11
  declare const Button: import("svelte").Component<Props, {}, "">;
11
12
  type Button = ReturnType<typeof Button>;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Variables that are string-replaced by vite.
3
+ *
4
+ * These should not be imported into `$lib`,
5
+ * due to them not being replaced when shipped to NPM.
6
+ */
7
+ export declare const backendIP: any;
8
+ export declare const websocketPort: any;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Variables that are string-replaced by vite.
3
+ *
4
+ * These should not be imported into `$lib`,
5
+ * due to them not being replaced when shipped to NPM.
6
+ */
7
+ export const backendIP = BACKEND_IP;
8
+ export const websocketPort = WS_PORT;
@@ -12,6 +12,7 @@ import {} from 'koota';
12
12
  import { parsePlyInput } from '../ply';
13
13
  import { useLogs } from './useLogs.svelte';
14
14
  import { createBox, createCapsule, createSphere } from '../geometry';
15
+ import { useDrawConnectionConfig } from './useDrawConnectionConfig.svelte';
15
16
  const colorUtil = new Color();
16
17
  const bufferTypes = {
17
18
  DRAW_POINTS: 0,
@@ -70,6 +71,9 @@ export const provideDrawAPI = () => {
70
71
  const logs = useLogs();
71
72
  const cameraControls = useCameraControls();
72
73
  const { invalidate } = useThrelte();
74
+ const drawConnectionConfig = useDrawConnectionConfig();
75
+ const backendIP = $derived(drawConnectionConfig.current?.backendIP);
76
+ const websocketPort = $derived(drawConnectionConfig.current?.websocketPort);
73
77
  let pointsIndex = 0;
74
78
  let geometryIndex = 0;
75
79
  let poseIndex = 0;
@@ -82,7 +86,7 @@ export const provideDrawAPI = () => {
82
86
  const loader = new GLTFLoader();
83
87
  const entities = new Map();
84
88
  const sendResponse = (response) => {
85
- ws.send(JSON.stringify(response));
89
+ ws?.send(JSON.stringify(response));
86
90
  };
87
91
  const drawFrames = async (data) => {
88
92
  for (const rawFrame of data) {
@@ -300,15 +304,20 @@ export const provideDrawAPI = () => {
300
304
  };
301
305
  const scheduleReconnect = () => {
302
306
  setTimeout(() => {
303
- reconnectDelay = Math.min(reconnectDelay * 2, maxReconnectDelay);
304
- logs.add(`Reconnecting to drawing server in ${reconnectDelay / 1000} seconds...`, 'warn');
305
- connect();
307
+ if (backendIP && websocketPort) {
308
+ reconnectDelay = Math.min(reconnectDelay * 2, maxReconnectDelay);
309
+ logs.add(`Reconnecting to drawing server in ${reconnectDelay / 1000} seconds...`, 'warn');
310
+ connect(backendIP, websocketPort);
311
+ }
312
+ else {
313
+ logs.add('No provided backend IP or websocket port', 'error');
314
+ }
306
315
  }, reconnectDelay);
307
316
  };
308
317
  const onOpen = () => {
309
318
  connectionStatus = 'open';
310
319
  reconnectDelay = 1000;
311
- logs.add(`Connected to drawing server at ${BACKEND_IP}:${WS_PORT}`);
320
+ logs.add(`Connected to drawing server at ${backendIP}:${websocketPort}`);
312
321
  };
313
322
  const onClose = () => {
314
323
  connectionStatus = 'closed';
@@ -317,7 +326,7 @@ export const provideDrawAPI = () => {
317
326
  };
318
327
  const onError = (event) => {
319
328
  const stringified = JSON.stringify(event);
320
- ws.close();
329
+ ws?.close();
321
330
  if (stringified === '{"isTrusted":true}') {
322
331
  return;
323
332
  }
@@ -409,17 +418,31 @@ export const provideDrawAPI = () => {
409
418
  }
410
419
  invalidate();
411
420
  };
412
- const connect = () => {
413
- if (BACKEND_IP && WS_PORT) {
414
- const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
415
- ws = new WebSocket(`${protocol}://${BACKEND_IP}:${WS_PORT}/ws`);
416
- ws.onclose = onClose;
417
- ws.onerror = onError;
418
- ws.onopen = onOpen;
419
- ws.onmessage = onMessage;
420
- }
421
+ const connect = (backendIP, websocketPort) => {
422
+ const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
423
+ ws = new WebSocket(`${protocol}://${backendIP}:${websocketPort}/ws`);
424
+ ws.onclose = onClose;
425
+ ws.onerror = onError;
426
+ ws.onopen = onOpen;
427
+ ws.onmessage = onMessage;
428
+ };
429
+ const disconnect = () => {
430
+ ws?.removeEventListener('close', onClose);
431
+ ws?.removeEventListener('error', onError);
432
+ ws?.removeEventListener('open', onOpen);
433
+ ws?.removeEventListener('message', onMessage);
434
+ ws?.close();
435
+ ws = undefined;
421
436
  };
422
- connect();
437
+ $effect(() => {
438
+ if (!backendIP || !websocketPort) {
439
+ return;
440
+ }
441
+ connect(backendIP, websocketPort);
442
+ return () => {
443
+ disconnect();
444
+ };
445
+ });
423
446
  setContext(key, {
424
447
  get connectionStatus() {
425
448
  return connectionStatus;
@@ -0,0 +1,10 @@
1
+ export interface DrawConnectionConfig {
2
+ backendIP: string;
3
+ websocketPort: string;
4
+ }
5
+ interface Context {
6
+ current: DrawConnectionConfig | undefined;
7
+ }
8
+ export declare const provideDrawConnectionConfig: (args: () => DrawConnectionConfig | undefined) => void;
9
+ export declare const useDrawConnectionConfig: () => Context;
10
+ export {};
@@ -0,0 +1,13 @@
1
+ import { getContext, setContext } from 'svelte';
2
+ const key = Symbol('draw-connection-config-key');
3
+ export const provideDrawConnectionConfig = (args) => {
4
+ const current = $derived(args());
5
+ setContext(key, {
6
+ get current() {
7
+ return current;
8
+ },
9
+ });
10
+ };
11
+ export const useDrawConnectionConfig = () => {
12
+ return getContext(key);
13
+ };
@@ -18,7 +18,7 @@ export const provideFrames = (partID) => {
18
18
  const machineStatus = useMachineStatus(partID);
19
19
  const logs = useLogs();
20
20
  const query = createRobotQuery(client, 'frameSystemConfig', () => ({
21
- enabled: environment.current.viewerMode === 'monitor',
21
+ enabled: partID() !== '' && environment.current.viewerMode === 'monitor',
22
22
  }));
23
23
  const revision = $derived(machineStatus.current?.config?.revision);
24
24
  const partConfig = usePartConfig();
@@ -0,0 +1,4 @@
1
+ import { commonApi } from '@viamrobotics/sdk';
2
+ export declare const usePose: (name: () => string | undefined, parent: () => string | undefined) => {
3
+ readonly current: import("@bufbuild/protobuf").PlainMessage<commonApi.Pose> | undefined;
4
+ };
@@ -1,8 +1,7 @@
1
- import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk';
1
+ import { createRobotQuery, useRobotClient } from '@viamrobotics/svelte-sdk';
2
2
  import { usePartID } from './usePartID.svelte';
3
- import { MotionClient, Pose, Transform } from '@viamrobotics/sdk';
3
+ import { commonApi, Pose } from '@viamrobotics/sdk';
4
4
  import { RefreshRates, useMachineSettings } from './useMachineSettings.svelte';
5
- import { useMotionClient } from './useMotionClient.svelte';
6
5
  import { useEnvironment } from './useEnvironment.svelte';
7
6
  import { observe } from '@threlte/core';
8
7
  import { untrack } from 'svelte';
@@ -16,7 +15,7 @@ export const usePose = (name, parent) => {
16
15
  const logs = useLogs();
17
16
  const { refreshRates } = useMachineSettings();
18
17
  const partID = usePartID();
19
- const motionClient = useMotionClient();
18
+ const robotClient = useRobotClient(() => partID.current);
20
19
  const currentName = $derived(name());
21
20
  const currentParent = $derived(parent());
22
21
  const resourceByName = useResourceByName();
@@ -25,7 +24,6 @@ export const usePose = (name, parent) => {
25
24
  const parentResource = $derived(currentParent ? resourceByName.current[currentParent] : undefined);
26
25
  const frames = useFrames();
27
26
  let pose = $state(undefined);
28
- const client = createResourceClient(MotionClient, () => partID.current, () => motionClient.current ?? '');
29
27
  const interval = $derived(refreshRates.get(RefreshRates.poses));
30
28
  const resolvedParent = $derived(parentResource?.subtype === 'arm' || parentResource?.subtype === 'gantry'
31
29
  ? `${parent()}_origin`
@@ -33,7 +31,7 @@ export const usePose = (name, parent) => {
33
31
  const resolvedName = $derived(resource?.subtype === 'arm' || resource?.subtype === 'gantry'
34
32
  ? `${currentName}_origin`
35
33
  : currentName);
36
- const query = createResourceQuery(client, 'getPose', () => [resolvedName, resolvedParent ?? 'world', []], () => ({
34
+ const query = createRobotQuery(robotClient, 'getPose', () => [resolvedName, resolvedParent ?? 'world', []], () => ({
37
35
  enabled: interval !== RefetchRates.OFF && environment.current.viewerMode === 'monitor',
38
36
  refetchInterval: interval === RefetchRates.MANUAL ? false : interval,
39
37
  }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viamrobotics/motion-tools",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "Motion visualization with Viam",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -25,7 +25,6 @@
25
25
  "@testing-library/jest-dom": "6.8.0",
26
26
  "@testing-library/svelte": "5.2.8",
27
27
  "@testing-library/user-event": "^14.6.1",
28
- "@thi.ng/paths": "5.2.21",
29
28
  "@threlte/core": "8.3.0",
30
29
  "@threlte/extras": "9.7.0",
31
30
  "@threlte/rapier": "3.2.0",
@@ -36,10 +35,12 @@
36
35
  "@typescript-eslint/eslint-plugin": "8.42.0",
37
36
  "@typescript-eslint/parser": "8.42.0",
38
37
  "@viamrobotics/prime-core": "0.1.5",
39
- "@viamrobotics/sdk": "0.56.0",
38
+ "@viamrobotics/sdk": "0.58.0",
40
39
  "@viamrobotics/svelte-sdk": "1.0.1",
41
40
  "@vitejs/plugin-basic-ssl": "2.1.0",
42
41
  "@vitest/coverage-v8": "^3.2.4",
42
+ "@zag-js/collapsible": "1.22.1",
43
+ "@zag-js/floating-panel": "1.22.1",
43
44
  "@zag-js/svelte": "1.22.1",
44
45
  "@zag-js/tree-view": "1.22.1",
45
46
  "camera-controls": "3.1.0",
@@ -49,8 +50,6 @@
49
50
  "globals": "16.3.0",
50
51
  "idb-keyval": "6.2.2",
51
52
  "jsdom": "26.1.0",
52
- "koota": "^0.5.3",
53
- "lodash-es": "4.17.21",
54
53
  "lucide-svelte": "0.542.0",
55
54
  "prettier": "3.6.2",
56
55
  "prettier-plugin-svelte": "3.4.0",
@@ -62,7 +61,6 @@
62
61
  "svelte-virtuallists": "1.4.2",
63
62
  "tailwindcss": "4.1.13",
64
63
  "three": "0.182.0",
65
- "three-mesh-bvh": "^0.9.1",
66
64
  "threlte-uikit": "1.2.1",
67
65
  "tsx": "4.20.5",
68
66
  "type-fest": "^5.0.1",
@@ -82,8 +80,11 @@
82
80
  "@viamrobotics/prime-core": ">=0.1",
83
81
  "@viamrobotics/sdk": ">=0.38",
84
82
  "@viamrobotics/svelte-sdk": ">=0.1",
83
+ "@zag-js/collapsible": ">=1",
84
+ "@zag-js/floating-panel": ">=1",
85
85
  "@zag-js/svelte": ">=1",
86
86
  "@zag-js/tree-view": ">=1",
87
+ "camera-controls": ">=3",
87
88
  "idb-keyval": ">=6",
88
89
  "lucide-svelte": ">=0.511",
89
90
  "runed": ">=0.28",
@@ -122,6 +123,8 @@
122
123
  "@bufbuild/protobuf": "1.10.1",
123
124
  "@neodrag/svelte": "^2.3.3",
124
125
  "@tanstack/svelte-query-devtools": "^6.0.2",
126
+ "koota": "^0.5.3",
127
+ "lodash-es": "4.17.21",
125
128
  "uuid-tool": "^2.0.3"
126
129
  },
127
130
  "scripts": {
@@ -1,8 +0,0 @@
1
- interface Context {
2
- names: string[];
3
- current: string | undefined;
4
- set(value?: string | undefined): void;
5
- }
6
- export declare const provideMotionClient: (partID: () => string) => void;
7
- export declare const useMotionClient: () => Context;
8
- export {};
@@ -1,32 +0,0 @@
1
- import { useResourceNames } from '@viamrobotics/svelte-sdk';
2
- import { getContext, setContext } from 'svelte';
3
- const key = Symbol('motion-client-context');
4
- export const provideMotionClient = (partID) => {
5
- const motionResources = useResourceNames(partID, 'motion');
6
- const motionNames = $derived(motionResources.current.map((resource) => resource.name));
7
- let current = $state();
8
- $effect.pre(() => {
9
- if (current) {
10
- return;
11
- }
12
- if (motionNames.includes('builtin')) {
13
- current = 'builtin';
14
- return;
15
- }
16
- current = motionNames[0];
17
- });
18
- setContext(key, {
19
- get names() {
20
- return motionNames;
21
- },
22
- get current() {
23
- return current;
24
- },
25
- set(value) {
26
- current = value;
27
- },
28
- });
29
- };
30
- export const useMotionClient = () => {
31
- return getContext(key);
32
- };