@viamrobotics/test-widgets 0.11.0 → 0.11.2

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.
@@ -57,75 +57,77 @@
57
57
 
58
58
  <ConnectionStatus {partID}>
59
59
  {#snippet connected()}
60
- <div class="flex flex-col gap-4 lg:flex-row lg:gap-0 lg:divide-x">
61
- <!-- Main control sections -->
62
- <div
63
- class="flex flex-col gap-4 lg:grid lg:grow lg:grid-cols-2 lg:gap-0 lg:divide-x xl:grid-cols-3"
64
- >
65
- <ApiSection
66
- title="GetJointPositions"
67
- api="rdk:component:arm"
68
- bottomText="Updates automatically"
60
+ <div class="@container">
61
+ <div class="flex flex-col gap-4 @2xl:flex-row @2xl:gap-0 @2xl:divide-x">
62
+ <!-- Main control sections -->
63
+ <div
64
+ class="flex flex-col gap-4 @2xl:grid @2xl:grow @2xl:grid-cols-2 @2xl:gap-0 @2xl:divide-x @4xl:grid-cols-3"
69
65
  >
70
- <Query query={jointPositionsQuery}>
71
- {#if jointPositionsQuery.data}
72
- <GetJointPositions positions={jointPositionsQuery.data.values} />
73
- {/if}
74
- </Query>
75
- </ApiSection>
76
- <ApiSection
77
- title="MoveToJointPositions"
78
- api="rdk:component:arm"
79
- >
80
- <Query query={jointPositionsQuery}>
81
- {#if jointPositionsQuery.data}
82
- <MoveToJointPositions
83
- positions={jointPositionsQuery.data.values}
84
- {moveToJointPositions}
85
- lastError={moveToJointPosMutation.error}
86
- {jointLimitsDegrees}
87
- isMoving={isMovingQuery.data ?? false}
88
- />
89
- {/if}
90
- </Query>
91
- </ApiSection>
92
- <ApiSection
93
- title="MoveToPosition"
94
- api="rdk:component:arm"
95
- >
96
- <Query query={endPositionQuery}>
97
- {#if endPositionQuery.data}
98
- <MoveToPosition
99
- endPosition={endPositionQuery.data}
100
- {moveToPosition}
101
- lastError={moveToPosMutation.error}
102
- />
103
- {/if}
104
- </Query>
105
- </ApiSection>
106
- </div>
66
+ <ApiSection
67
+ title="GetJointPositions"
68
+ api="rdk:component:arm"
69
+ bottomText="Updates automatically"
70
+ >
71
+ <Query query={jointPositionsQuery}>
72
+ {#if jointPositionsQuery.data}
73
+ <GetJointPositions positions={jointPositionsQuery.data.values} />
74
+ {/if}
75
+ </Query>
76
+ </ApiSection>
77
+ <ApiSection
78
+ title="MoveToJointPositions"
79
+ api="rdk:component:arm"
80
+ >
81
+ <Query query={jointPositionsQuery}>
82
+ {#if jointPositionsQuery.data}
83
+ <MoveToJointPositions
84
+ positions={jointPositionsQuery.data.values}
85
+ {moveToJointPositions}
86
+ lastError={moveToJointPosMutation.error}
87
+ {jointLimitsDegrees}
88
+ isMoving={isMovingQuery.data ?? false}
89
+ />
90
+ {/if}
91
+ </Query>
92
+ </ApiSection>
93
+ <ApiSection
94
+ title="MoveToPosition"
95
+ api="rdk:component:arm"
96
+ >
97
+ <Query query={endPositionQuery}>
98
+ {#if endPositionQuery.data}
99
+ <MoveToPosition
100
+ endPosition={endPositionQuery.data}
101
+ {moveToPosition}
102
+ lastError={moveToPosMutation.error}
103
+ />
104
+ {/if}
105
+ </Query>
106
+ </ApiSection>
107
+ </div>
107
108
 
108
- <!-- Control actions sidebar -->
109
- <div
110
- class="flex flex-row gap-4 lg:ml-auto lg:w-full lg:max-w-40 lg:flex-col lg:gap-0 lg:divide-y"
111
- >
112
- <ApiSection
113
- title="Stop"
114
- api="rdk:component:arm"
109
+ <!-- Control actions sidebar -->
110
+ <div
111
+ class="flex flex-row gap-4 @2xl:ml-auto @2xl:w-full @2xl:max-w-40 @2xl:flex-col @2xl:gap-0 @2xl:divide-y"
115
112
  >
116
- <StopButton
117
- error={stopMutation.error}
118
- onStop={() => {
119
- stopMutation.mutate([], {})
120
- }}
113
+ <ApiSection
114
+ title="Stop"
115
+ api="rdk:component:arm"
116
+ >
117
+ <StopButton
118
+ error={stopMutation.error}
119
+ onStop={() => {
120
+ stopMutation.mutate([], {})
121
+ }}
122
+ />
123
+ </ApiSection>
124
+ <IsMoving
125
+ client={ArmClient}
126
+ api="rdk:component:arm"
127
+ {partID}
128
+ {resourceName}
121
129
  />
122
- </ApiSection>
123
- <IsMoving
124
- client={ArmClient}
125
- api="rdk:component:arm"
126
- {partID}
127
- {resourceName}
128
- />
130
+ </div>
129
131
  </div>
130
132
  </div>
131
133
  {/snippet}
@@ -60,46 +60,48 @@
60
60
 
61
61
  <ConnectionStatus {partID}>
62
62
  {#snippet connected()}
63
- <div class="flex flex-row divide-x">
64
- <MutationSection
65
- title="Quick move"
66
- lastError={quickSetPowerMutation.error}
67
- >
68
- {#snippet titleInput()}
69
- <Label>
70
- Keyboard control
63
+ <div class="@container">
64
+ <div class="flex flex-col divide-y @4xl:flex-row @4xl:divide-x @4xl:divide-y-0">
65
+ <MutationSection
66
+ title="Quick move"
67
+ lastError={quickSetPowerMutation.error}
68
+ >
69
+ {#snippet titleInput()}
70
+ <Label>
71
+ Keyboard control
71
72
 
72
- <Switch
73
- slot="input"
74
- on={quickMoveKeyboardControl}
75
- on:change={() => (quickMoveKeyboardControl = !quickMoveKeyboardControl)}
76
- />
77
- </Label>
78
- {/snippet}
73
+ <Switch
74
+ slot="input"
75
+ on={quickMoveKeyboardControl}
76
+ on:change={() => (quickMoveKeyboardControl = !quickMoveKeyboardControl)}
77
+ />
78
+ </Label>
79
+ {/snippet}
79
80
 
80
- <QuickMove
81
- isKeyboardEnabled={quickMoveKeyboardControl}
82
- setPower={quickSetPower}
83
- />
84
- </MutationSection>
85
- <div class="ml-auto flex w-full max-w-40 grow flex-col divide-y">
86
- <ApiSection
87
- title="Stop"
88
- api="rdk:component:base"
89
- >
90
- <StopButton
91
- error={stopMutation.error}
92
- onStop={() => {
93
- stopMutation.mutate([])
94
- }}
81
+ <QuickMove
82
+ isKeyboardEnabled={quickMoveKeyboardControl}
83
+ setPower={quickSetPower}
84
+ />
85
+ </MutationSection>
86
+ <div class="flex grow flex-col divide-y @4xl:ml-auto @4xl:w-full @4xl:max-w-40">
87
+ <ApiSection
88
+ title="Stop"
89
+ api="rdk:component:base"
90
+ >
91
+ <StopButton
92
+ error={stopMutation.error}
93
+ onStop={() => {
94
+ stopMutation.mutate([])
95
+ }}
96
+ />
97
+ </ApiSection>
98
+ <IsMoving
99
+ client={BaseClient}
100
+ api="rdk:component:base"
101
+ {partID}
102
+ {resourceName}
95
103
  />
96
- </ApiSection>
97
- <IsMoving
98
- client={BaseClient}
99
- api="rdk:component:base"
100
- {partID}
101
- {resourceName}
102
- />
104
+ </div>
103
105
  </div>
104
106
  </div>
105
107
  <MutationSection
@@ -13,7 +13,7 @@
13
13
  let mmPerSec = $state(100)
14
14
  </script>
15
15
 
16
- <div class="flex flex-row gap-4">
16
+ <div class="flex flex-wrap gap-4">
17
17
  <Label cx="max-w-[96px] gap-1 text-xs whitespace-nowrap">
18
18
  <span class="flex gap-1">
19
19
  Distance
@@ -15,7 +15,7 @@
15
15
  let angularPower = $state<Vector3>({ x: 0, y: 0, z: 0.75 })
16
16
  </script>
17
17
 
18
- <div class="flex flex-row gap-4">
18
+ <div class="flex flex-wrap gap-4">
19
19
  <Vec3Builder
20
20
  title="Linear power"
21
21
  titleTooltip="The percentage of max power of the base’s linear propulsion. In the range of –1.0 to 1.0, with 1.0 meaning 100% power."
@@ -15,7 +15,7 @@
15
15
  let angularVelocity = $state<Vector3>({ x: 0, y: 0, z: 15 })
16
16
  </script>
17
17
 
18
- <div class="flex flex-row gap-4">
18
+ <div class="flex flex-wrap gap-4">
19
19
  <Vec3Builder
20
20
  title="Linear velocity"
21
21
  titleUnits="(mm/s)"
@@ -13,7 +13,7 @@
13
13
  let degsPerSec = $state(45)
14
14
  </script>
15
15
 
16
- <div class="flex flex-row gap-4">
16
+ <div class="flex flex-wrap gap-4">
17
17
  <Label cx="max-w-[96px] gap-1 text-xs">
18
18
  <span class="flex gap-1">
19
19
  Angle
@@ -405,7 +405,7 @@
405
405
  lastError={resolutionMutation.error}
406
406
  class="-m-4 mt-4"
407
407
  >
408
- <div class="flex w-full flex-row justify-between">
408
+ <div class="flex w-full flex-wrap justify-between gap-2">
409
409
  <Label cx="max-w-[96px] gap-1 text-xs">
410
410
  <span class="flex gap-1 whitespace-nowrap">
411
411
  Resolution
@@ -61,42 +61,44 @@
61
61
  />
62
62
  </div>
63
63
 
64
- <div class="grid w-full grid-cols-2 divide-x">
65
- <ApiSection
66
- title="GetPosition"
67
- api="rdk:component:encoder"
68
- tooltip="Relative encoders return ticks since last zeroing. Absolute encoders return degrees."
69
- class="gap-3"
70
- >
71
- <Queries queries={[propertiesQuery, positionQuery]}>
72
- {#if positionQuery.data !== undefined}
73
- {@const [position, encoderPositionType] = positionQuery.data}
74
- <div class="font-roboto-mono flex flex-col gap-2 text-sm">
75
- <Position
76
- {position}
77
- {encoderPositionType}
78
- />
79
- </div>
80
- {/if}
81
- </Queries>
82
- </ApiSection>
64
+ <div class="@container">
65
+ <div class="grid w-full grid-cols-1 divide-y @lg:grid-cols-2 @lg:divide-x @lg:divide-y-0">
66
+ <ApiSection
67
+ title="GetPosition"
68
+ api="rdk:component:encoder"
69
+ tooltip="Relative encoders return ticks since last zeroing. Absolute encoders return degrees."
70
+ class="gap-3"
71
+ >
72
+ <Queries queries={[propertiesQuery, positionQuery]}>
73
+ {#if positionQuery.data !== undefined}
74
+ {@const [position, encoderPositionType] = positionQuery.data}
75
+ <div class="font-roboto-mono flex flex-col gap-2 text-sm">
76
+ <Position
77
+ {position}
78
+ {encoderPositionType}
79
+ />
80
+ </div>
81
+ {/if}
82
+ </Queries>
83
+ </ApiSection>
83
84
 
84
- <ApiSection
85
- title="ResetPosition"
86
- api="rdk:component:encoder"
87
- description="Set the current position as the new zero position"
88
- >
89
- <Button
90
- icon="play-circle-outline"
91
- class="w-fit"
92
- onclick={() => {
93
- resetMutation.mutate([], {})
94
- }}
85
+ <ApiSection
86
+ title="ResetPosition"
87
+ api="rdk:component:encoder"
88
+ description="Set the current position as the new zero position"
95
89
  >
96
- Execute
97
- </Button>
98
- <ErrorDisplay lastError={resetMutation.error} />
99
- </ApiSection>
90
+ <Button
91
+ icon="play-circle-outline"
92
+ class="w-fit"
93
+ onclick={() => {
94
+ resetMutation.mutate([], {})
95
+ }}
96
+ >
97
+ Execute
98
+ </Button>
99
+ <ErrorDisplay lastError={resetMutation.error} />
100
+ </ApiSection>
101
+ </div>
100
102
  </div>
101
103
  {/snippet}
102
104
  </ConnectionStatus>
@@ -45,113 +45,117 @@
45
45
 
46
46
  <ConnectionStatus {partID}>
47
47
  {#snippet connected()}
48
- <div class="flex flex-row divide-x">
49
- <div class="flex grow flex-row divide-x">
50
- <ApiSection
51
- bottomText="Updates automatically"
52
- aria-labelledby={positionHeadingID}
53
- >
54
- <h3
55
- class="text-subtle-2 flex flex-row items-center gap-1 text-sm"
56
- id={positionHeadingID}
57
- >
58
- <a
59
- href={apiDocsHref('rdk:component:gantry', 'getPosition')}
60
- target="_blank"
61
- rel="noopener noreferrer external"
62
- class="decoration-gray-5 hover:decoration-default text-default font-mono font-semibold underline underline-offset-3"
48
+ <div class="@container">
49
+ <div class="flex flex-col divide-y @4xl:flex-row @4xl:divide-x @4xl:divide-y-0">
50
+ <div class="@container grow">
51
+ <div class="flex flex-col divide-y @2xl:flex-row @2xl:divide-x @2xl:divide-y-0">
52
+ <ApiSection
53
+ bottomText="Updates automatically"
54
+ aria-labelledby={positionHeadingID}
63
55
  >
64
- GetPosition
65
- </a>
66
- and
67
- <a
68
- href={apiDocsHref('rdk:component:gantry', 'getLengths')}
69
- target="_blank"
70
- rel="noopener noreferrer external"
71
- class="decoration-gray-5 hover:decoration-default text-default font-mono font-semibold underline underline-offset-3"
56
+ <h3
57
+ class="text-subtle-2 flex flex-row items-center gap-1 text-sm"
58
+ id={positionHeadingID}
59
+ >
60
+ <a
61
+ href={apiDocsHref('rdk:component:gantry', 'getPosition')}
62
+ target="_blank"
63
+ rel="noopener noreferrer external"
64
+ class="decoration-gray-5 hover:decoration-default text-default font-mono font-semibold underline underline-offset-3"
65
+ >
66
+ GetPosition
67
+ </a>
68
+ and
69
+ <a
70
+ href={apiDocsHref('rdk:component:gantry', 'getLengths')}
71
+ target="_blank"
72
+ rel="noopener noreferrer external"
73
+ class="decoration-gray-5 hover:decoration-default text-default font-mono font-semibold underline underline-offset-3"
74
+ >
75
+ GetLengths
76
+ </a>
77
+ </h3>
78
+ <Queries queries={[positionQuery, lengthsQuery]}>
79
+ {@const positions = positionQuery.data}
80
+ {@const lengths = lengthsQuery.data ?? []}
81
+ {#if positions !== undefined}
82
+ <PositionAndLengths
83
+ {positions}
84
+ {lengths}
85
+ />
86
+ {/if}
87
+ </Queries>
88
+ </ApiSection>
89
+ <ApiSection
90
+ title="MoveToPosition"
91
+ api="rdk:component:gantry"
72
92
  >
73
- GetLengths
74
- </a>
75
- </h3>
76
- <Queries queries={[positionQuery, lengthsQuery]}>
77
- {@const positions = positionQuery.data}
78
- {@const lengths = lengthsQuery.data ?? []}
79
- {#if positions !== undefined}
80
- <PositionAndLengths
81
- {positions}
82
- {lengths}
83
- />
84
- {/if}
85
- </Queries>
86
- </ApiSection>
87
- <ApiSection
88
- title="MoveToPosition"
89
- api="rdk:component:gantry"
90
- >
91
- <Query query={positionQuery}>
92
- {@const positions = positionQuery.data}
93
- {#if positions !== undefined}
94
- <MoveToPosition
95
- {positions}
96
- lastError={moveMutation.error}
97
- moveTo={(newPos: number[], speeds: number[]) => {
98
- moveMutation.mutate([newPos, speeds], {})
99
- }}
100
- />
101
- {/if}
102
- </Query>
103
- </ApiSection>
104
- <div class="flex grow flex-col divide-y">
105
- <ApiSection
106
- title="Quick move"
107
- bottomText="Press a button to execute"
108
- >
109
- <Query
110
- query={positionQuery}
111
- contentCx="h-6"
112
- >
113
- {@const positions = positionQuery.data}
114
- {#if positions !== undefined}
115
- <QuickMove
116
- {positions}
117
- lastError={quickMoveMutation.error}
118
- moveTo={(newPos: number[], speeds: number[]) => {
119
- quickMoveMutation.mutate([newPos, speeds], {})
120
- }}
93
+ <Query query={positionQuery}>
94
+ {@const positions = positionQuery.data}
95
+ {#if positions !== undefined}
96
+ <MoveToPosition
97
+ {positions}
98
+ lastError={moveMutation.error}
99
+ moveTo={(newPos: number[], speeds: number[]) => {
100
+ moveMutation.mutate([newPos, speeds], {})
101
+ }}
102
+ />
103
+ {/if}
104
+ </Query>
105
+ </ApiSection>
106
+ <div class="flex grow flex-col divide-y">
107
+ <ApiSection
108
+ title="Quick move"
109
+ bottomText="Press a button to execute"
110
+ >
111
+ <Query
112
+ query={positionQuery}
113
+ contentCx="h-6"
114
+ >
115
+ {@const positions = positionQuery.data}
116
+ {#if positions !== undefined}
117
+ <QuickMove
118
+ {positions}
119
+ lastError={quickMoveMutation.error}
120
+ moveTo={(newPos: number[], speeds: number[]) => {
121
+ quickMoveMutation.mutate([newPos, speeds], {})
122
+ }}
123
+ />
124
+ {/if}
125
+ </Query>
126
+ </ApiSection>
127
+ <ApiSection
128
+ title="Home"
129
+ api="rdk:component:gantry"
130
+ description="Run the homing sequence"
131
+ >
132
+ <Home
133
+ {partID}
134
+ {resourceName}
121
135
  />
122
- {/if}
123
- </Query>
124
- </ApiSection>
136
+ </ApiSection>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ <div class="flex flex-col divide-y @4xl:ml-auto @4xl:w-full @4xl:max-w-40">
125
141
  <ApiSection
126
- title="Home"
142
+ title="Stop"
127
143
  api="rdk:component:gantry"
128
- description="Run the homing sequence"
129
144
  >
130
- <Home
131
- {partID}
132
- {resourceName}
145
+ <StopButton
146
+ error={stopMutation.error}
147
+ onStop={() => {
148
+ stopMutation.mutate([])
149
+ }}
133
150
  />
134
151
  </ApiSection>
135
- </div>
136
- </div>
137
- <div class="ml-auto flex w-full max-w-40 flex-col divide-y">
138
- <ApiSection
139
- title="Stop"
140
- api="rdk:component:gantry"
141
- >
142
- <StopButton
143
- error={stopMutation.error}
144
- onStop={() => {
145
- stopMutation.mutate([])
146
- }}
152
+ <IsMoving
153
+ client={GantryClient}
154
+ api="rdk:component:gantry"
155
+ {partID}
156
+ {resourceName}
147
157
  />
148
- </ApiSection>
149
- <IsMoving
150
- client={GantryClient}
151
- api="rdk:component:gantry"
152
- {partID}
153
- {resourceName}
154
- />
158
+ </div>
155
159
  </div>
156
160
  </div>
157
161
  {/snippet}
@@ -109,7 +109,7 @@
109
109
  </span>
110
110
  </Tooltip>
111
111
  </span>
112
- <div class="flex flex-row gap-2">
112
+ <div class="flex flex-wrap gap-2">
113
113
  <Button onclick={resetToZero}>Zero</Button>
114
114
  <Button onclick={resetToCurrent}>Current position</Button>
115
115
  </div>
@@ -39,7 +39,7 @@
39
39
 
40
40
  <ConnectionStatus {partID}>
41
41
  {#snippet connected()}
42
- <div class="flex flex-row items-center justify-between p-4 pb-3">
42
+ <div class="flex flex-wrap items-center justify-between gap-2 p-4 pb-3">
43
43
  <RefetchController
44
44
  {refetchInterval}
45
45
  queries={[eventsQuery]}
@@ -43,7 +43,7 @@
43
43
 
44
44
  <ConnectionStatus {partID}>
45
45
  {#snippet connected()}
46
- <div class="flex gap-4 p-4 pb-3">
46
+ <div class="flex flex-wrap gap-4 p-4 pb-3">
47
47
  <RefetchController
48
48
  allowLive
49
49
  {refetchInterval}
@@ -13,7 +13,7 @@
13
13
  let rpm = $state(10)
14
14
  </script>
15
15
 
16
- <div class="flex flex-row gap-4">
16
+ <div class="flex flex-wrap gap-4">
17
17
  <Label cx="max-w-[96px] grow gap-1 text-xs">
18
18
  <p class="flex flex-row gap-1">
19
19
  RPM
@@ -13,7 +13,7 @@
13
13
  let rpm = $state(10)
14
14
  </script>
15
15
 
16
- <div class="flex flex-row gap-4">
16
+ <div class="flex flex-wrap gap-4">
17
17
  <Label cx="max-w-[96px] grow gap-1 text-xs">
18
18
  <p class="flex flex-row gap-1">
19
19
  RPM
@@ -76,107 +76,109 @@
76
76
 
77
77
  <ConnectionStatus {partID}>
78
78
  {#snippet connected()}
79
- <div class="flex flex-row divide-x">
80
- <div class="flex w-full flex-col divide-y">
81
- <MutationSection
82
- title="Quick move"
83
- lastError={quickSetPowerMutation.error}
84
- >
85
- <QuickMove setPower={quickSetPower} />
86
- </MutationSection>
87
- <MutationSection
88
- title="SetPower"
89
- api="rdk:component:motor"
90
- description="Move continuously"
91
- lastError={setPowerMutation.error}
92
- >
93
- <SetPower {setPower} />
94
- </MutationSection>
95
- {#if propertiesQuery.data?.positionReporting}
79
+ <div class="@container">
80
+ <div class="flex flex-col divide-y @2xl:flex-row @2xl:divide-x @2xl:divide-y-0">
81
+ <div class="flex w-full flex-col divide-y">
96
82
  <MutationSection
97
- title="SetRPM"
98
- api="rdk:component:motor"
99
- description="Move indefinitely at a specified speed."
100
- lastError={setRPMMutation.error}
101
- >
102
- <SetRPM {setRPM} />
103
- </MutationSection>
104
- <MutationSection
105
- title="GoFor"
106
- api="rdk:component:motor"
107
- description="Move a specified number of revolutions"
108
- lastError={goForMutation.error}
83
+ title="Quick move"
84
+ lastError={quickSetPowerMutation.error}
109
85
  >
110
- <GoFor {goFor} />
86
+ <QuickMove setPower={quickSetPower} />
111
87
  </MutationSection>
112
88
  <MutationSection
113
- title="GoTo"
89
+ title="SetPower"
114
90
  api="rdk:component:motor"
115
- description="Turn to a specified position"
116
- lastError={goToMutation.error}
91
+ description="Move continuously"
92
+ lastError={setPowerMutation.error}
117
93
  >
118
- <GoTo {goTo} />
94
+ <SetPower {setPower} />
119
95
  </MutationSection>
120
- {/if}
121
- </div>
122
-
123
- <div class="ml-auto flex w-full max-w-1/2 flex-col divide-y sm:max-w-1/3">
124
- <ApiSection
125
- title="Stop"
126
- api="rdk:component:motor"
127
- >
128
- <StopButton
129
- error={stopMutation.error}
130
- onStop={() => {
131
- stopMutation.mutate([])
132
- }}
133
- />
134
- </ApiSection>
135
- <IsMoving
136
- client={MotorClient}
137
- api="rdk:component:motor"
138
- {partID}
139
- {resourceName}
140
- >
141
- <div class="flex flex-col gap-6 pt-2">
142
- <ApiSection
143
- title="IsPowered"
96
+ {#if propertiesQuery.data?.positionReporting}
97
+ <MutationSection
98
+ title="SetRPM"
144
99
  api="rdk:component:motor"
145
- class="gap-3 p-0"
146
- tooltip="Returns whether or not the motor is running and the current portion of max power.
147
-
148
- Stepper motors will report ”true” if they are being powered while holding
149
- a position and while they are turning."
100
+ description="Move indefinitely at a specified speed."
101
+ lastError={setRPMMutation.error}
150
102
  >
151
- <Query query={isPoweredQuery}>
152
- {#if isPoweredQuery.data !== undefined}
153
- {@const [isPowered, powerPct] = isPoweredQuery.data}
154
- <span class="font-roboto-mono flex flex-row gap-1 text-xs">
155
- <p class="text-default">{isPowered}</p>
156
- <p class="text-disabled">/</p>
157
- <p class="text-subtle-1">
158
- {formatNumeric(powerPct * 100, 1)}%
159
- </p>
160
- </span>
161
- {/if}
162
- </Query>
163
- </ApiSection>
164
- {#if propertiesQuery.data?.positionReporting === true}
103
+ <SetRPM {setRPM} />
104
+ </MutationSection>
105
+ <MutationSection
106
+ title="GoFor"
107
+ api="rdk:component:motor"
108
+ description="Move a specified number of revolutions"
109
+ lastError={goForMutation.error}
110
+ >
111
+ <GoFor {goFor} />
112
+ </MutationSection>
113
+ <MutationSection
114
+ title="GoTo"
115
+ api="rdk:component:motor"
116
+ description="Turn to a specified position"
117
+ lastError={goToMutation.error}
118
+ >
119
+ <GoTo {goTo} />
120
+ </MutationSection>
121
+ {/if}
122
+ </div>
123
+
124
+ <div class="flex w-full flex-col divide-y @2xl:ml-auto @2xl:max-w-1/2 @4xl:max-w-1/3">
125
+ <ApiSection
126
+ title="Stop"
127
+ api="rdk:component:motor"
128
+ >
129
+ <StopButton
130
+ error={stopMutation.error}
131
+ onStop={() => {
132
+ stopMutation.mutate([])
133
+ }}
134
+ />
135
+ </ApiSection>
136
+ <IsMoving
137
+ client={MotorClient}
138
+ api="rdk:component:motor"
139
+ {partID}
140
+ {resourceName}
141
+ >
142
+ <div class="flex flex-col gap-6 pt-2">
165
143
  <ApiSection
166
- title="GetPosition"
144
+ title="IsPowered"
167
145
  api="rdk:component:motor"
168
146
  class="gap-3 p-0"
169
- tooltip="Reports the position of an encoded motor in revolutions from zero/home."
147
+ tooltip="Returns whether or not the motor is running and the current portion of max power.
148
+
149
+ Stepper motors will report ”true” if they are being powered while holding
150
+ a position and while they are turning."
170
151
  >
171
- <Query query={positionQuery}>
172
- <p class="font-roboto-mono text-default text-xs">
173
- {formatNumeric(positionQuery.data, 4)}
174
- </p>
152
+ <Query query={isPoweredQuery}>
153
+ {#if isPoweredQuery.data !== undefined}
154
+ {@const [isPowered, powerPct] = isPoweredQuery.data}
155
+ <span class="font-roboto-mono flex flex-row gap-1 text-xs">
156
+ <p class="text-default">{isPowered}</p>
157
+ <p class="text-disabled">/</p>
158
+ <p class="text-subtle-1">
159
+ {formatNumeric(powerPct * 100, 1)}%
160
+ </p>
161
+ </span>
162
+ {/if}
175
163
  </Query>
176
164
  </ApiSection>
177
- {/if}
178
- </div>
179
- </IsMoving>
165
+ {#if propertiesQuery.data?.positionReporting === true}
166
+ <ApiSection
167
+ title="GetPosition"
168
+ api="rdk:component:motor"
169
+ class="gap-3 p-0"
170
+ tooltip="Reports the position of an encoded motor in revolutions from zero/home."
171
+ >
172
+ <Query query={positionQuery}>
173
+ <p class="font-roboto-mono text-default text-xs">
174
+ {formatNumeric(positionQuery.data, 4)}
175
+ </p>
176
+ </Query>
177
+ </ApiSection>
178
+ {/if}
179
+ </div>
180
+ </IsMoving>
181
+ </div>
180
182
  </div>
181
183
  </div>
182
184
  {/snippet}
@@ -34,49 +34,58 @@
34
34
  {#if formattedOperations.length === 0}
35
35
  <p class="text-subtle-2 text-xs">No operations currently available</p>
36
36
  {:else}
37
- <table class="w-full table-fixed">
38
- <thead>
39
- <tr class="bg-light text-subtle-1 border text-left text-xs">
40
- <th class="w-1/4 p-2 font-normal">ID</th>
41
- <th class="w-1/4 p-2 font-normal">Session</th>
42
- <th class="w-1/4 p-2 font-normal">Method</th>
43
- <th class="w-1/6 p-2 font-normal">Elapsed Time</th>
44
- <th class="w-16"></th>
45
- </tr>
46
- </thead>
47
- <tbody class="text-xs">
48
- {#each formattedOperations as operation (operation.id)}
49
- <tr class="border border-b text-left">
50
- <td
51
- class="truncate p-2"
52
- title={operation.id}
53
- >{operation.id}
54
- </td>
55
- <td
56
- class="truncate p-2"
57
- title={operation.sessionId}
58
- >{operation.sessionId}
59
- </td>
60
- <td
61
- class="truncate p-2"
62
- title={operation.method}
63
- >{operation.method}
64
- </td>
65
- <td
66
- class="truncate p-2"
67
- title={`${formatNumeric(operation.elapsedTime, 0)} ms`}
68
- >
69
- {formatNumeric(operation.elapsedTime, 0)} ms
70
- </td>
71
- <td class="p-2">
72
- <Tooltip hoverDelayMS={500}>
73
- <Button onclick={() => cancelOperation(operation.id)}>Kill</Button>
74
-
75
- <span slot="description"> Request cancellation of the operation. </span>
76
- </Tooltip>
77
- </td>
37
+ <!-- Scroll region: keyboard users need focus on the wrapper to scroll the overflow (WCAG 2.1.1). -->
38
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
39
+ <div
40
+ class="overflow-x-auto"
41
+ role="region"
42
+ aria-label="Operations"
43
+ tabindex="0"
44
+ >
45
+ <table class="w-full min-w-md table-fixed">
46
+ <thead>
47
+ <tr class="bg-light text-subtle-1 border text-left text-xs">
48
+ <th class="w-1/4 p-2 font-normal">ID</th>
49
+ <th class="w-1/4 p-2 font-normal">Session</th>
50
+ <th class="w-1/4 p-2 font-normal">Method</th>
51
+ <th class="w-1/6 p-2 font-normal">Elapsed Time</th>
52
+ <th class="w-16"></th>
78
53
  </tr>
79
- {/each}
80
- </tbody>
81
- </table>
54
+ </thead>
55
+ <tbody class="text-xs">
56
+ {#each formattedOperations as operation (operation.id)}
57
+ <tr class="border border-b text-left">
58
+ <td
59
+ class="truncate p-2"
60
+ title={operation.id}
61
+ >{operation.id}
62
+ </td>
63
+ <td
64
+ class="truncate p-2"
65
+ title={operation.sessionId}
66
+ >{operation.sessionId}
67
+ </td>
68
+ <td
69
+ class="truncate p-2"
70
+ title={operation.method}
71
+ >{operation.method}
72
+ </td>
73
+ <td
74
+ class="truncate p-2"
75
+ title={`${formatNumeric(operation.elapsedTime, 0)} ms`}
76
+ >
77
+ {formatNumeric(operation.elapsedTime, 0)} ms
78
+ </td>
79
+ <td class="p-2">
80
+ <Tooltip hoverDelayMS={500}>
81
+ <Button onclick={() => cancelOperation(operation.id)}>Kill</Button>
82
+
83
+ <span slot="description"> Request cancellation of the operation. </span>
84
+ </Tooltip>
85
+ </td>
86
+ </tr>
87
+ {/each}
88
+ </tbody>
89
+ </table>
90
+ </div>
82
91
  {/if}
@@ -38,41 +38,50 @@
38
38
  {#if flattenedSessions.length === 0}
39
39
  <p class="text-subtle-2 text-xs">No sessions currently available</p>
40
40
  {:else}
41
- <table class="w-full table-fixed">
42
- <thead>
43
- <tr class="bg-light text-subtle-1 border text-left text-xs">
44
- <th class="w-1/4 p-2 font-normal">ID</th>
45
- <th class="w-1/8 p-2 font-normal">Type</th>
46
- <th class="w-1/4 p-2 font-normal">Remote Address</th>
47
- <th class="w-1/4 p-2 font-normal">Local Address</th>
48
- </tr>
49
- </thead>
50
- <tbody class="text-xs">
51
- {#each flattenedSessions as session (session.id)}
52
- <tr class="border border-b text-left">
53
- <td
54
- class="truncate p-2 text-left"
55
- title={session.id}
56
- >
57
- {session.id}
58
- {#if session.id === ourSessionId}
59
- <div class="text-subtle-2 text-xs">(Ours)</div>
60
- {/if}
61
- </td>
62
- <td class="truncate p-2">{session.typeString}</td>
63
- <td
64
- class="truncate p-2"
65
- title={session.remoteAddress}
66
- >{session.remoteAddress}
67
- </td>
68
- <td
69
- class="truncate p-2"
70
- title={session.localAddress}
71
- >
72
- {session.localAddress}
73
- </td>
41
+ <!-- Scroll region: keyboard users need focus on the wrapper to scroll the overflow (WCAG 2.1.1). -->
42
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
43
+ <div
44
+ class="overflow-x-auto"
45
+ role="region"
46
+ aria-label="Sessions"
47
+ tabindex="0"
48
+ >
49
+ <table class="w-full min-w-md table-fixed">
50
+ <thead>
51
+ <tr class="bg-light text-subtle-1 border text-left text-xs">
52
+ <th class="w-1/4 p-2 font-normal">ID</th>
53
+ <th class="w-1/8 p-2 font-normal">Type</th>
54
+ <th class="w-1/4 p-2 font-normal">Remote Address</th>
55
+ <th class="w-1/4 p-2 font-normal">Local Address</th>
74
56
  </tr>
75
- {/each}
76
- </tbody>
77
- </table>
57
+ </thead>
58
+ <tbody class="text-xs">
59
+ {#each flattenedSessions as session (session.id)}
60
+ <tr class="border border-b text-left">
61
+ <td
62
+ class="truncate p-2 text-left"
63
+ title={session.id}
64
+ >
65
+ {session.id}
66
+ {#if session.id === ourSessionId}
67
+ <div class="text-subtle-2 text-xs">(Ours)</div>
68
+ {/if}
69
+ </td>
70
+ <td class="truncate p-2">{session.typeString}</td>
71
+ <td
72
+ class="truncate p-2"
73
+ title={session.remoteAddress}
74
+ >{session.remoteAddress}
75
+ </td>
76
+ <td
77
+ class="truncate p-2"
78
+ title={session.localAddress}
79
+ >
80
+ {session.localAddress}
81
+ </td>
82
+ </tr>
83
+ {/each}
84
+ </tbody>
85
+ </table>
86
+ </div>
78
87
  {/if}
@@ -63,49 +63,51 @@
63
63
  />
64
64
  </div>
65
65
 
66
- <div class="grid w-full grid-cols-3 divide-x">
67
- <ApiSection
68
- title="GetCurrent"
69
- api="rdk:component:power_sensor"
70
- class="pb-5"
71
- >
72
- <Query
73
- query={currentQuery}
74
- contentCx="h-6"
66
+ <div class="@container">
67
+ <div class="grid w-full grid-cols-1 divide-y @2xl:grid-cols-3 @2xl:divide-x @2xl:divide-y-0">
68
+ <ApiSection
69
+ title="GetCurrent"
70
+ api="rdk:component:power_sensor"
71
+ class="pb-5"
75
72
  >
76
- {#if currentQuery.data !== undefined}
77
- <CurrentReading data={currentQuery.data} />
78
- {/if}
79
- </Query>
80
- </ApiSection>
81
- <ApiSection
82
- title="GetVoltage"
83
- api="rdk:component:power_sensor"
84
- class="pb-5"
85
- >
86
- <Query
87
- query={voltageQuery}
88
- contentCx="h-6"
73
+ <Query
74
+ query={currentQuery}
75
+ contentCx="h-6"
76
+ >
77
+ {#if currentQuery.data !== undefined}
78
+ <CurrentReading data={currentQuery.data} />
79
+ {/if}
80
+ </Query>
81
+ </ApiSection>
82
+ <ApiSection
83
+ title="GetVoltage"
84
+ api="rdk:component:power_sensor"
85
+ class="pb-5"
89
86
  >
90
- {#if voltageQuery.data !== undefined}
91
- <VoltageReading data={voltageQuery.data} />
92
- {/if}
93
- </Query>
94
- </ApiSection>
95
- <ApiSection
96
- title="GetPower"
97
- api="rdk:component:power_sensor"
98
- class="pb-5"
99
- >
100
- <Query
101
- query={powerQuery}
102
- contentCx="h-6"
87
+ <Query
88
+ query={voltageQuery}
89
+ contentCx="h-6"
90
+ >
91
+ {#if voltageQuery.data !== undefined}
92
+ <VoltageReading data={voltageQuery.data} />
93
+ {/if}
94
+ </Query>
95
+ </ApiSection>
96
+ <ApiSection
97
+ title="GetPower"
98
+ api="rdk:component:power_sensor"
99
+ class="pb-5"
103
100
  >
104
- {#if powerQuery.data !== undefined}
105
- <PowerReading data={powerQuery.data} />
106
- {/if}
107
- </Query>
108
- </ApiSection>
101
+ <Query
102
+ query={powerQuery}
103
+ contentCx="h-6"
104
+ >
105
+ {#if powerQuery.data !== undefined}
106
+ <PowerReading data={powerQuery.data} />
107
+ {/if}
108
+ </Query>
109
+ </ApiSection>
110
+ </div>
109
111
  </div>
110
112
 
111
113
  <ApiSection
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viamrobotics/test-widgets",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "wireit": {
@@ -103,7 +103,8 @@
103
103
  "!coverage/**",
104
104
  "!test-results/**",
105
105
  "!.env*",
106
- "!**/*.tgz"
106
+ "!**/*.tgz",
107
+ "!.claude/**"
107
108
  ],
108
109
  "output": [],
109
110
  "packageLocks": [
@@ -120,7 +121,8 @@
120
121
  "!coverage/**",
121
122
  "!test-results/**",
122
123
  "!.env*",
123
- "!**/*.tgz"
124
+ "!**/*.tgz",
125
+ "!.claude/**"
124
126
  ],
125
127
  "output": [],
126
128
  "packageLocks": [
@@ -216,18 +218,27 @@
216
218
  "@fontsource-variable/public-sans": "^5.2.7",
217
219
  "@fontsource-variable/roboto-mono": "^5.2.8",
218
220
  "@fontsource-variable/space-grotesk": "^5.2.10",
221
+ "@houserules/cli": "^0.4.1",
222
+ "@houserules/plugin-accessibility": "^0.1.3",
223
+ "@houserules/plugin-changesets": "^0.2.2",
224
+ "@houserules/plugin-design": "^0.2.2",
225
+ "@houserules/plugin-prose": "^0.1.4",
226
+ "@houserules/plugin-svelte": "^0.1.2",
227
+ "@houserules/plugin-testing": "^0.2.1",
228
+ "@houserules/plugin-three": "^0.2.1",
229
+ "@houserules/plugin-typescript": "^0.1.2",
219
230
  "@playwright/test": "^1.59.1",
220
231
  "@sentry/svelte": "^10.50.0",
221
232
  "@sveltejs/adapter-static": "^3.0.10",
222
233
  "@sveltejs/kit": "^2.69.1",
223
234
  "@sveltejs/package": "^2.5.7",
224
235
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
236
+ "@tailwindcss/oxide": "^4.2.4",
225
237
  "@tailwindcss/postcss": "^4.2.4",
226
238
  "@tailwindcss/vite": "^4.2.4",
227
239
  "@tanstack/svelte-query": "^6.1.25",
228
240
  "@tanstack/svelte-query-devtools": "^6.1.25",
229
241
  "@testing-library/dom": "^10.4.1",
230
- "@testing-library/jest-dom": "^6.9.1",
231
242
  "@testing-library/svelte": "^5.3.1",
232
243
  "@testing-library/user-event": "^14.6.1",
233
244
  "@threlte/core": "^8.5.9",
@@ -239,7 +250,7 @@
239
250
  "@viamrobotics/prime-core": "^0.1.22",
240
251
  "@viamrobotics/sdk": "^0.69.0",
241
252
  "@viamrobotics/svelte-sdk": "^1.2.1",
242
- "@viamrobotics/tailwind-config": "^1.0.0",
253
+ "@viamrobotics/tailwind-config": "^1.2.0",
243
254
  "@vitest/browser": "^4.1.10",
244
255
  "@vitest/browser-playwright": "^4.1.5",
245
256
  "@vitest/coverage-v8": "^4.1.5",
@@ -252,7 +263,6 @@
252
263
  "globals": "^17.5.0",
253
264
  "lodash-es": "^4.18.1",
254
265
  "maplibre-gl": "^5.24.0",
255
- "mock-match-media": "^1.0.3",
256
266
  "playwright": "^1.59.1",
257
267
  "prettier": "^3.8.3",
258
268
  "prettier-plugin-svelte": "^3.5.1",