@wandelbots/wandelbots-js-react-components 2.38.1 → 2.39.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/dist/components/RobotCard.d.ts +24 -30
- package/dist/components/RobotCard.d.ts.map +1 -1
- package/dist/index.cjs +41 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1800 -1844
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/CycleTimer/DefaultVariant.tsx +3 -3
- package/src/components/CycleTimer/useTimerLogic.ts +2 -2
- package/src/components/RobotCard.tsx +49 -126
package/package.json
CHANGED
|
@@ -117,7 +117,7 @@ export const DefaultVariant = ({
|
|
|
117
117
|
currentState !== "countup" &&
|
|
118
118
|
currentState !== "success"
|
|
119
119
|
}
|
|
120
|
-
timeout={
|
|
120
|
+
timeout={300}
|
|
121
121
|
>
|
|
122
122
|
<Typography
|
|
123
123
|
variant="body2"
|
|
@@ -237,7 +237,7 @@ export const DefaultVariant = ({
|
|
|
237
237
|
currentState !== "idle" &&
|
|
238
238
|
currentState !== "success"
|
|
239
239
|
}
|
|
240
|
-
timeout={
|
|
240
|
+
timeout={300}
|
|
241
241
|
>
|
|
242
242
|
<Typography
|
|
243
243
|
variant="h1"
|
|
@@ -280,7 +280,7 @@ export const DefaultVariant = ({
|
|
|
280
280
|
currentState !== "countup" &&
|
|
281
281
|
currentState !== "success"
|
|
282
282
|
}
|
|
283
|
-
timeout={
|
|
283
|
+
timeout={300}
|
|
284
284
|
>
|
|
285
285
|
<Typography
|
|
286
286
|
variant="body2"
|
|
@@ -53,10 +53,10 @@ export const useTimerLogic = ({
|
|
|
53
53
|
...prev,
|
|
54
54
|
currentState: "idle",
|
|
55
55
|
maxTime: null,
|
|
56
|
-
remainingTime
|
|
56
|
+
// Don't reset remainingTime - keep the last value
|
|
57
57
|
isRunning: false,
|
|
58
58
|
isPausedState: false,
|
|
59
|
-
currentProgress: 0, //
|
|
59
|
+
currentProgress: 0, // Reset progress to 0 for gauge
|
|
60
60
|
}))
|
|
61
61
|
pausedTimeRef.current = 0
|
|
62
62
|
startTimeRef.current = null
|
|
@@ -12,7 +12,6 @@ import { useTranslation } from "react-i18next"
|
|
|
12
12
|
import type { Group } from "three"
|
|
13
13
|
import { externalizeComponent } from "../externalizeComponent"
|
|
14
14
|
import { PresetEnvironment } from "./3d-viewport/PresetEnvironment"
|
|
15
|
-
import { CycleTimer } from "./CycleTimer"
|
|
16
15
|
import type { ProgramState } from "./ProgramControl"
|
|
17
16
|
import { ProgramStateIndicator } from "./ProgramStateIndicator"
|
|
18
17
|
import { Robot } from "./robots/Robot"
|
|
@@ -58,34 +57,8 @@ export interface RobotCardProps {
|
|
|
58
57
|
transparentColor?: string
|
|
59
58
|
getModel?: (modelFromController: string) => string
|
|
60
59
|
}>
|
|
61
|
-
/** Custom
|
|
62
|
-
|
|
63
|
-
variant?: "default" | "small"
|
|
64
|
-
compact?: boolean
|
|
65
|
-
onCycleComplete: (controls: {
|
|
66
|
-
startNewCycle: (maxTimeSeconds?: number, elapsedSeconds?: number) => void
|
|
67
|
-
pause: () => void
|
|
68
|
-
resume: () => void
|
|
69
|
-
isPaused: () => boolean
|
|
70
|
-
}) => void
|
|
71
|
-
onCycleEnd?: () => void
|
|
72
|
-
autoStart?: boolean
|
|
73
|
-
hasError?: boolean
|
|
74
|
-
className?: string
|
|
75
|
-
}>
|
|
76
|
-
/** Callback to receive cycle timer controls for external timer management */
|
|
77
|
-
onCycleTimerReady?: (controls: {
|
|
78
|
-
startNewCycle: (maxTimeSeconds?: number, elapsedSeconds?: number) => void
|
|
79
|
-
pause: () => void
|
|
80
|
-
resume: () => void
|
|
81
|
-
isPaused: () => boolean
|
|
82
|
-
}) => void
|
|
83
|
-
/** Callback fired when a cycle completes (reaches zero) */
|
|
84
|
-
onCycleEnd?: () => void
|
|
85
|
-
/** Whether the cycle timer should auto-start when a new cycle is set */
|
|
86
|
-
cycleTimerAutoStart?: boolean
|
|
87
|
-
/** Whether the cycle timer is in an error state (pauses timer and shows error styling) */
|
|
88
|
-
cycleTimerHasError?: boolean
|
|
60
|
+
/** Custom component to render in the content area (optional) */
|
|
61
|
+
customContentComponent?: React.ComponentType<Record<string, unknown>>
|
|
89
62
|
/** Additional CSS class name */
|
|
90
63
|
className?: string
|
|
91
64
|
}
|
|
@@ -108,11 +81,31 @@ export interface RobotCardProps {
|
|
|
108
81
|
* - Robot name displayed in Typography h6 at top-left
|
|
109
82
|
* - Program state indicator below the name
|
|
110
83
|
* - Auto-fitting 3D robot model that scales with container size
|
|
111
|
-
* -
|
|
84
|
+
* - Customizable content area for displaying custom React components
|
|
112
85
|
* - Transparent gray divider line
|
|
113
86
|
* - "Drive to Home" button with press-and-hold functionality
|
|
114
87
|
* - Localization support via react-i18next
|
|
115
88
|
* - Material-UI theming integration
|
|
89
|
+
*
|
|
90
|
+
* Usage with custom content:
|
|
91
|
+
* ```tsx
|
|
92
|
+
* // Example custom timer component
|
|
93
|
+
* const CustomTimer = () => (
|
|
94
|
+
* <Box>
|
|
95
|
+
* <Typography variant="body1" sx={{ color: "text.secondary" }}>
|
|
96
|
+
* Runtime
|
|
97
|
+
* </Typography>
|
|
98
|
+
* <Typography variant="h6">05:23</Typography>
|
|
99
|
+
* </Box>
|
|
100
|
+
* )
|
|
101
|
+
*
|
|
102
|
+
* <RobotCard
|
|
103
|
+
* robotName="UR5e Robot"
|
|
104
|
+
* programState={ProgramState.RUNNING}
|
|
105
|
+
* customContentComponent={CustomTimer}
|
|
106
|
+
* // ... other props
|
|
107
|
+
* />
|
|
108
|
+
* ```
|
|
116
109
|
*/
|
|
117
110
|
export const RobotCard = externalizeComponent(
|
|
118
111
|
observer(
|
|
@@ -126,11 +119,7 @@ export const RobotCard = externalizeComponent(
|
|
|
126
119
|
onDriveToHomeRelease,
|
|
127
120
|
connectedMotionGroup,
|
|
128
121
|
robotComponent: RobotComponent = Robot,
|
|
129
|
-
|
|
130
|
-
onCycleTimerReady,
|
|
131
|
-
onCycleEnd,
|
|
132
|
-
cycleTimerAutoStart = true,
|
|
133
|
-
cycleTimerHasError = false,
|
|
122
|
+
customContentComponent: CustomContentComponent,
|
|
134
123
|
className,
|
|
135
124
|
}: RobotCardProps) => {
|
|
136
125
|
const theme = useTheme()
|
|
@@ -145,17 +134,6 @@ export const RobotCard = externalizeComponent(
|
|
|
145
134
|
}>({ width: 400, height: 600 })
|
|
146
135
|
const [modelRenderTrigger, setModelRenderTrigger] = useState(0)
|
|
147
136
|
|
|
148
|
-
// Store cycle timer controls for external control
|
|
149
|
-
const cycleControlsRef = useRef<{
|
|
150
|
-
startNewCycle: (
|
|
151
|
-
maxTimeSeconds?: number,
|
|
152
|
-
elapsedSeconds?: number,
|
|
153
|
-
) => void
|
|
154
|
-
pause: () => void
|
|
155
|
-
resume: () => void
|
|
156
|
-
isPaused: () => boolean
|
|
157
|
-
} | null>(null)
|
|
158
|
-
|
|
159
137
|
// Hook to detect aspect ratio and size changes
|
|
160
138
|
useEffect(() => {
|
|
161
139
|
const checkDimensions = () => {
|
|
@@ -204,38 +182,16 @@ export const RobotCard = externalizeComponent(
|
|
|
204
182
|
}
|
|
205
183
|
}, [isDriveToHomePressed, onDriveToHomeRelease])
|
|
206
184
|
|
|
207
|
-
// Store and provide cycle timer controls for external use
|
|
208
|
-
const handleCycleComplete = useCallback(
|
|
209
|
-
(controls: {
|
|
210
|
-
startNewCycle: (
|
|
211
|
-
maxTimeSeconds?: number,
|
|
212
|
-
elapsedSeconds?: number,
|
|
213
|
-
) => void
|
|
214
|
-
pause: () => void
|
|
215
|
-
resume: () => void
|
|
216
|
-
isPaused: () => boolean
|
|
217
|
-
}) => {
|
|
218
|
-
// Store the controls for potential future use
|
|
219
|
-
cycleControlsRef.current = controls
|
|
220
|
-
|
|
221
|
-
// Notify parent component that timer controls are ready
|
|
222
|
-
if (onCycleTimerReady) {
|
|
223
|
-
onCycleTimerReady(controls)
|
|
224
|
-
}
|
|
225
|
-
},
|
|
226
|
-
[onCycleTimerReady],
|
|
227
|
-
)
|
|
228
|
-
|
|
229
185
|
// Determine if robot should be hidden at small sizes to save space
|
|
230
186
|
const shouldHideRobot = isLandscape
|
|
231
187
|
? cardSize.width < 350
|
|
232
188
|
: cardSize.height < 200 // Hide robot at height < 200px in portrait
|
|
233
189
|
|
|
234
|
-
// Determine if
|
|
235
|
-
//
|
|
236
|
-
const
|
|
237
|
-
? cardSize.height < 310 // Landscape: hide
|
|
238
|
-
: cardSize.height < 450 // Portrait: hide
|
|
190
|
+
// Determine if custom content should be hidden when height is too low
|
|
191
|
+
// Custom content should be hidden BEFORE the robot (at higher threshold)
|
|
192
|
+
const shouldHideCustomContent = isLandscape
|
|
193
|
+
? cardSize.height < 310 // Landscape: hide custom content at height < 310px
|
|
194
|
+
: cardSize.height < 450 // Portrait: hide custom content at height < 450px
|
|
239
195
|
|
|
240
196
|
return (
|
|
241
197
|
<Card
|
|
@@ -337,7 +293,7 @@ export const RobotCard = externalizeComponent(
|
|
|
337
293
|
/>
|
|
338
294
|
</Box>
|
|
339
295
|
|
|
340
|
-
{/* Bottom section with
|
|
296
|
+
{/* Bottom section with custom content and button */}
|
|
341
297
|
<Box
|
|
342
298
|
sx={{
|
|
343
299
|
p: { xs: 1.5, sm: 2, md: 3 },
|
|
@@ -348,32 +304,10 @@ export const RobotCard = externalizeComponent(
|
|
|
348
304
|
justifyContent: "space-between",
|
|
349
305
|
}}
|
|
350
306
|
>
|
|
351
|
-
{/*
|
|
352
|
-
{!
|
|
307
|
+
{/* Custom content section - hidden if height is too low in landscape mode */}
|
|
308
|
+
{!shouldHideCustomContent && CustomContentComponent && (
|
|
353
309
|
<Box>
|
|
354
|
-
|
|
355
|
-
<Typography
|
|
356
|
-
variant="body1"
|
|
357
|
-
sx={{
|
|
358
|
-
mb: 0,
|
|
359
|
-
color: theme.palette.text.secondary,
|
|
360
|
-
textAlign: "left",
|
|
361
|
-
}}
|
|
362
|
-
>
|
|
363
|
-
{t("RobotCard.Runtime.lb")}
|
|
364
|
-
</Typography>
|
|
365
|
-
|
|
366
|
-
{/* Compact cycle time component directly below runtime */}
|
|
367
|
-
<Box sx={{ textAlign: "left" }}>
|
|
368
|
-
<CycleTimerComponent
|
|
369
|
-
variant="small"
|
|
370
|
-
compact
|
|
371
|
-
onCycleComplete={handleCycleComplete}
|
|
372
|
-
onCycleEnd={onCycleEnd}
|
|
373
|
-
autoStart={cycleTimerAutoStart}
|
|
374
|
-
hasError={cycleTimerHasError}
|
|
375
|
-
/>
|
|
376
|
-
</Box>
|
|
310
|
+
<CustomContentComponent />
|
|
377
311
|
|
|
378
312
|
{/* Divider */}
|
|
379
313
|
<Divider
|
|
@@ -387,7 +321,14 @@ export const RobotCard = externalizeComponent(
|
|
|
387
321
|
</Box>
|
|
388
322
|
)}
|
|
389
323
|
|
|
390
|
-
<Box
|
|
324
|
+
<Box
|
|
325
|
+
sx={{
|
|
326
|
+
mt:
|
|
327
|
+
!shouldHideCustomContent && CustomContentComponent
|
|
328
|
+
? "auto"
|
|
329
|
+
: 0,
|
|
330
|
+
}}
|
|
331
|
+
>
|
|
391
332
|
{/* Drive to Home button with some space */}
|
|
392
333
|
<Box
|
|
393
334
|
sx={{
|
|
@@ -488,31 +429,12 @@ export const RobotCard = externalizeComponent(
|
|
|
488
429
|
)}
|
|
489
430
|
</Box>
|
|
490
431
|
|
|
491
|
-
{/* Bottom section with
|
|
432
|
+
{/* Bottom section with custom content and button */}
|
|
492
433
|
<Box>
|
|
493
|
-
{/*
|
|
494
|
-
{!
|
|
434
|
+
{/* Custom content section - hidden if height is too low */}
|
|
435
|
+
{!shouldHideCustomContent && CustomContentComponent && (
|
|
495
436
|
<>
|
|
496
|
-
|
|
497
|
-
<Typography
|
|
498
|
-
variant="body1"
|
|
499
|
-
sx={{
|
|
500
|
-
mb: 0,
|
|
501
|
-
color: theme.palette.text.secondary,
|
|
502
|
-
}}
|
|
503
|
-
>
|
|
504
|
-
{t("RobotCard.Runtime.lb")}
|
|
505
|
-
</Typography>
|
|
506
|
-
|
|
507
|
-
{/* Compact cycle time component directly below runtime */}
|
|
508
|
-
<CycleTimerComponent
|
|
509
|
-
variant="small"
|
|
510
|
-
compact
|
|
511
|
-
onCycleComplete={handleCycleComplete}
|
|
512
|
-
onCycleEnd={onCycleEnd}
|
|
513
|
-
autoStart={cycleTimerAutoStart}
|
|
514
|
-
hasError={cycleTimerHasError}
|
|
515
|
-
/>
|
|
437
|
+
<CustomContentComponent />
|
|
516
438
|
|
|
517
439
|
{/* Divider */}
|
|
518
440
|
<Divider
|
|
@@ -531,9 +453,10 @@ export const RobotCard = externalizeComponent(
|
|
|
531
453
|
sx={{
|
|
532
454
|
display: "flex",
|
|
533
455
|
justifyContent: "flex-start",
|
|
534
|
-
mt:
|
|
535
|
-
|
|
536
|
-
|
|
456
|
+
mt:
|
|
457
|
+
!shouldHideCustomContent && CustomContentComponent
|
|
458
|
+
? { xs: 1, sm: 2, md: 5 }
|
|
459
|
+
: { xs: 0.5, sm: 1, md: 2 },
|
|
537
460
|
mb: { xs: 0.5, sm: 0.75, md: 1 },
|
|
538
461
|
}}
|
|
539
462
|
>
|