@wandelbots/wandelbots-js-react-components 2.40.0-pr.feature-seperate-timer.383.0494cf4 → 2.41.0-pr.feature-seperate-timer.383.cd7e408
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/TabBar.d.ts +2 -0
- package/dist/components/TabBar.d.ts.map +1 -1
- package/dist/components/jogging/PoseCartesianValues.d.ts.map +1 -1
- package/dist/components/jogging/PoseJointValues.d.ts.map +1 -1
- package/dist/index.cjs +8 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +319 -304
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/TabBar.tsx +35 -8
- package/src/components/jogging/PoseCartesianValues.tsx +69 -66
- package/src/components/jogging/PoseJointValues.tsx +69 -66
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wandelbots/wandelbots-js-react-components",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.41.0-pr.feature-seperate-timer.383.cd7e408",
|
|
4
4
|
"description": "React UI toolkit for building applications on top of the Wandelbots platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { SxProps } from "@mui/material"
|
|
2
2
|
import { Box, Tab, Tabs } from "@mui/material"
|
|
3
3
|
import { observer } from "mobx-react-lite"
|
|
4
|
-
import { useState } from "react"
|
|
4
|
+
import { useEffect, useState } from "react"
|
|
5
5
|
import { externalizeComponent } from "../externalizeComponent"
|
|
6
6
|
|
|
7
7
|
export interface TabItem {
|
|
@@ -18,6 +18,8 @@ export interface TabItem {
|
|
|
18
18
|
export interface TabBarProps {
|
|
19
19
|
/** Array of tab items to display */
|
|
20
20
|
items: TabItem[]
|
|
21
|
+
/** Controlled active tab index */
|
|
22
|
+
activeTab?: number
|
|
21
23
|
/** Default active tab index */
|
|
22
24
|
defaultActiveTab?: number
|
|
23
25
|
/** Callback when tab changes */
|
|
@@ -57,14 +59,39 @@ function TabPanel(props: TabPanelProps) {
|
|
|
57
59
|
*/
|
|
58
60
|
export const TabBar = externalizeComponent(
|
|
59
61
|
observer((props: TabBarProps) => {
|
|
60
|
-
const {
|
|
61
|
-
|
|
62
|
+
const {
|
|
63
|
+
items,
|
|
64
|
+
activeTab,
|
|
65
|
+
defaultActiveTab = 0,
|
|
66
|
+
onTabChange,
|
|
67
|
+
sx,
|
|
68
|
+
ref,
|
|
69
|
+
} = props
|
|
70
|
+
const isControlled = activeTab !== undefined
|
|
71
|
+
const [uncontrolledActiveTab, setUncontrolledActiveTab] =
|
|
72
|
+
useState(defaultActiveTab)
|
|
73
|
+
|
|
74
|
+
// Keep uncontrolled state in range when items change
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (isControlled) return
|
|
77
|
+
if (items.length === 0) return
|
|
78
|
+
if (
|
|
79
|
+
uncontrolledActiveTab < 0 ||
|
|
80
|
+
uncontrolledActiveTab > items.length - 1
|
|
81
|
+
) {
|
|
82
|
+
setUncontrolledActiveTab(0)
|
|
83
|
+
}
|
|
84
|
+
}, [items.length, isControlled, uncontrolledActiveTab])
|
|
85
|
+
|
|
86
|
+
const currentValue = isControlled ? activeTab! : uncontrolledActiveTab
|
|
62
87
|
|
|
63
88
|
const handleTabChange = (
|
|
64
89
|
_event: React.SyntheticEvent,
|
|
65
90
|
newValue: number,
|
|
66
91
|
) => {
|
|
67
|
-
|
|
92
|
+
if (!isControlled) {
|
|
93
|
+
setUncontrolledActiveTab(newValue)
|
|
94
|
+
}
|
|
68
95
|
onTabChange?.(newValue)
|
|
69
96
|
}
|
|
70
97
|
|
|
@@ -76,7 +103,7 @@ export const TabBar = externalizeComponent(
|
|
|
76
103
|
{/* Tabs */}
|
|
77
104
|
<Box sx={{ px: 0, py: 0 }}>
|
|
78
105
|
<Tabs
|
|
79
|
-
value={
|
|
106
|
+
value={currentValue}
|
|
80
107
|
onChange={handleTabChange}
|
|
81
108
|
sx={{
|
|
82
109
|
minHeight: "32px",
|
|
@@ -104,11 +131,11 @@ export const TabBar = externalizeComponent(
|
|
|
104
131
|
backgroundColor: (theme) =>
|
|
105
132
|
theme.palette.backgroundPaperElevation?.[11] || "#32344B",
|
|
106
133
|
color: "text.primary",
|
|
107
|
-
opacity:
|
|
134
|
+
opacity: currentValue === index ? 1 : 0.38,
|
|
108
135
|
fontSize: "13px",
|
|
109
136
|
transition: "all 0.2s ease-in-out",
|
|
110
137
|
"&:hover": {
|
|
111
|
-
opacity:
|
|
138
|
+
opacity: currentValue === index ? 1 : 0.6,
|
|
112
139
|
},
|
|
113
140
|
"&.Mui-selected": {
|
|
114
141
|
opacity: 1,
|
|
@@ -134,7 +161,7 @@ export const TabBar = externalizeComponent(
|
|
|
134
161
|
{/* Tab Content */}
|
|
135
162
|
<Box sx={{ flex: 1, overflow: "auto" }}>
|
|
136
163
|
{items.map((item, index) => (
|
|
137
|
-
<TabPanel key={item.id} value={
|
|
164
|
+
<TabPanel key={item.id} value={currentValue} index={index}>
|
|
138
165
|
{item.content}
|
|
139
166
|
</TabPanel>
|
|
140
167
|
))}
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
} from "@wandelbots/nova-js/v1"
|
|
8
8
|
import { observer } from "mobx-react-lite"
|
|
9
9
|
import { useRef, useState } from "react"
|
|
10
|
+
import { externalizeComponent } from "../../externalizeComponent"
|
|
10
11
|
import { CopyableText } from "../CopyableText"
|
|
11
12
|
import { useAnimationFrame } from "../utils/hooks"
|
|
12
13
|
|
|
@@ -39,81 +40,83 @@ export type PoseCartesianValuesProps = {
|
|
|
39
40
|
showCopyButton?: boolean
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
export const PoseCartesianValues =
|
|
43
|
-
(
|
|
44
|
-
|
|
45
|
-
connectedMotionGroup,
|
|
46
|
-
showCopyButton = false,
|
|
47
|
-
}: PoseCartesianValuesProps) => {
|
|
48
|
-
const poseHolderRef = useRef<HTMLDivElement>(null)
|
|
49
|
-
const [copyMessage, setCopyMessage] = useState("")
|
|
50
|
-
|
|
51
|
-
const activeMotionStream = createMotionStateProvider(
|
|
43
|
+
export const PoseCartesianValues = externalizeComponent(
|
|
44
|
+
observer(
|
|
45
|
+
({
|
|
52
46
|
motionStream,
|
|
53
47
|
connectedMotionGroup,
|
|
54
|
-
|
|
48
|
+
showCopyButton = false,
|
|
49
|
+
}: PoseCartesianValuesProps) => {
|
|
50
|
+
const poseHolderRef = useRef<HTMLDivElement>(null)
|
|
51
|
+
const [copyMessage, setCopyMessage] = useState("")
|
|
55
52
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
const activeMotionStream = createMotionStateProvider(
|
|
54
|
+
motionStream,
|
|
55
|
+
connectedMotionGroup,
|
|
59
56
|
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function getCurrentPoseString() {
|
|
63
|
-
if (!activeMotionStream) return ""
|
|
64
|
-
const tcpPose = activeMotionStream.rapidlyChangingMotionState.tcp_pose
|
|
65
|
-
if (!tcpPose) return ""
|
|
66
|
-
return poseToWandelscriptString(tcpPose)
|
|
67
|
-
}
|
|
68
57
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
setTimeout(() => setCopyMessage(""), 2000)
|
|
74
|
-
} catch {
|
|
75
|
-
setCopyMessage("Copy failed")
|
|
76
|
-
setTimeout(() => setCopyMessage(""), 2000)
|
|
58
|
+
if (!activeMotionStream) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
"PoseCartesianValues requires either motionStream or connectedMotionGroup prop",
|
|
61
|
+
)
|
|
77
62
|
}
|
|
78
|
-
}
|
|
79
63
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
64
|
+
function getCurrentPoseString() {
|
|
65
|
+
if (!activeMotionStream) return ""
|
|
66
|
+
const tcpPose = activeMotionStream.rapidlyChangingMotionState.tcp_pose
|
|
67
|
+
if (!tcpPose) return ""
|
|
68
|
+
return poseToWandelscriptString(tcpPose)
|
|
83
69
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
70
|
+
|
|
71
|
+
const handleCopy = async () => {
|
|
72
|
+
try {
|
|
73
|
+
await navigator.clipboard.writeText(getCurrentPoseString())
|
|
74
|
+
setCopyMessage("Copied!")
|
|
75
|
+
setTimeout(() => setCopyMessage(""), 2000)
|
|
76
|
+
} catch {
|
|
77
|
+
setCopyMessage("Copy failed")
|
|
78
|
+
setTimeout(() => setCopyMessage(""), 2000)
|
|
79
|
+
}
|
|
87
80
|
}
|
|
88
81
|
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
useAnimationFrame(() => {
|
|
83
|
+
if (!poseHolderRef.current) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
const newPoseContent = getCurrentPoseString()
|
|
87
|
+
if (poseHolderRef.current.textContent === newPoseContent) {
|
|
88
|
+
return
|
|
89
|
+
}
|
|
91
90
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
91
|
+
poseHolderRef.current.textContent = newPoseContent
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<Stack
|
|
96
|
+
direction="row"
|
|
97
|
+
alignItems="center"
|
|
98
|
+
spacing={1}
|
|
99
|
+
sx={{ flexGrow: 1, minWidth: 0, overflow: "hidden" }}
|
|
100
|
+
>
|
|
101
|
+
<CopyableText value={getCurrentPoseString()} ref={poseHolderRef} />
|
|
102
|
+
{showCopyButton && (
|
|
103
|
+
<Button
|
|
104
|
+
variant="contained"
|
|
105
|
+
color="secondary"
|
|
106
|
+
size="small"
|
|
107
|
+
onClick={handleCopy}
|
|
108
|
+
sx={{ flexShrink: 0 }}
|
|
109
|
+
>
|
|
110
|
+
Copy
|
|
111
|
+
</Button>
|
|
112
|
+
)}
|
|
113
|
+
{copyMessage && (
|
|
114
|
+
<Typography variant="caption" color="success.main">
|
|
115
|
+
{copyMessage}
|
|
116
|
+
</Typography>
|
|
117
|
+
)}
|
|
118
|
+
</Stack>
|
|
119
|
+
)
|
|
120
|
+
},
|
|
121
|
+
),
|
|
119
122
|
)
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
} from "@wandelbots/nova-js/v1"
|
|
7
7
|
import { observer } from "mobx-react-lite"
|
|
8
8
|
import { useRef, useState } from "react"
|
|
9
|
+
import { externalizeComponent } from "../../externalizeComponent"
|
|
9
10
|
import { CopyableText } from "../CopyableText"
|
|
10
11
|
import { useAnimationFrame } from "../utils/hooks"
|
|
11
12
|
|
|
@@ -38,81 +39,83 @@ export type PoseJointValuesProps = {
|
|
|
38
39
|
showCopyButton?: boolean
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
export const PoseJointValues =
|
|
42
|
-
(
|
|
43
|
-
|
|
44
|
-
connectedMotionGroup,
|
|
45
|
-
showCopyButton = false,
|
|
46
|
-
}: PoseJointValuesProps) => {
|
|
47
|
-
const poseHolderRef = useRef<HTMLDivElement>(null)
|
|
48
|
-
const [copyMessage, setCopyMessage] = useState("")
|
|
49
|
-
|
|
50
|
-
const activeMotionStream = createMotionStateProvider(
|
|
42
|
+
export const PoseJointValues = externalizeComponent(
|
|
43
|
+
observer(
|
|
44
|
+
({
|
|
51
45
|
motionStream,
|
|
52
46
|
connectedMotionGroup,
|
|
53
|
-
|
|
47
|
+
showCopyButton = false,
|
|
48
|
+
}: PoseJointValuesProps) => {
|
|
49
|
+
const poseHolderRef = useRef<HTMLDivElement>(null)
|
|
50
|
+
const [copyMessage, setCopyMessage] = useState("")
|
|
54
51
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
const activeMotionStream = createMotionStateProvider(
|
|
53
|
+
motionStream,
|
|
54
|
+
connectedMotionGroup,
|
|
58
55
|
)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function getCurrentPoseString() {
|
|
62
|
-
if (!activeMotionStream) return ""
|
|
63
|
-
const { joints } =
|
|
64
|
-
activeMotionStream.rapidlyChangingMotionState.state.joint_position
|
|
65
|
-
return `[${joints.map((j: number) => parseFloat(j.toFixed(4))).join(", ")}]`
|
|
66
|
-
}
|
|
67
56
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
setTimeout(() => setCopyMessage(""), 2000)
|
|
73
|
-
} catch {
|
|
74
|
-
setCopyMessage("Copy failed")
|
|
75
|
-
setTimeout(() => setCopyMessage(""), 2000)
|
|
57
|
+
if (!activeMotionStream) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
"PoseJointValues requires either motionStream or connectedMotionGroup prop",
|
|
60
|
+
)
|
|
76
61
|
}
|
|
77
|
-
}
|
|
78
62
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
63
|
+
function getCurrentPoseString() {
|
|
64
|
+
if (!activeMotionStream) return ""
|
|
65
|
+
const { joints } =
|
|
66
|
+
activeMotionStream.rapidlyChangingMotionState.state.joint_position
|
|
67
|
+
return `[${joints.map((j: number) => parseFloat(j.toFixed(4))).join(", ")}]`
|
|
82
68
|
}
|
|
83
69
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
70
|
+
const handleCopy = async () => {
|
|
71
|
+
try {
|
|
72
|
+
await navigator.clipboard.writeText(getCurrentPoseString())
|
|
73
|
+
setCopyMessage("Copied!")
|
|
74
|
+
setTimeout(() => setCopyMessage(""), 2000)
|
|
75
|
+
} catch {
|
|
76
|
+
setCopyMessage("Copy failed")
|
|
77
|
+
setTimeout(() => setCopyMessage(""), 2000)
|
|
78
|
+
}
|
|
87
79
|
}
|
|
88
|
-
poseHolderRef.current.textContent = newPoseContent
|
|
89
|
-
})
|
|
90
80
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
81
|
+
useAnimationFrame(() => {
|
|
82
|
+
if (!poseHolderRef.current) {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const newPoseContent = getCurrentPoseString()
|
|
87
|
+
if (poseHolderRef.current.textContent === newPoseContent) {
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
poseHolderRef.current.textContent = newPoseContent
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<Stack
|
|
95
|
+
direction="row"
|
|
96
|
+
alignItems="center"
|
|
97
|
+
spacing={1}
|
|
98
|
+
sx={{ flexGrow: 1, minWidth: 0, overflow: "hidden" }}
|
|
99
|
+
>
|
|
100
|
+
<CopyableText value={getCurrentPoseString()} ref={poseHolderRef} />
|
|
101
|
+
{showCopyButton && (
|
|
102
|
+
<Button
|
|
103
|
+
variant="contained"
|
|
104
|
+
color="secondary"
|
|
105
|
+
size="small"
|
|
106
|
+
onClick={handleCopy}
|
|
107
|
+
sx={{ flexShrink: 0 }}
|
|
108
|
+
>
|
|
109
|
+
Copy
|
|
110
|
+
</Button>
|
|
111
|
+
)}
|
|
112
|
+
{copyMessage && (
|
|
113
|
+
<Typography variant="caption" color="success.main">
|
|
114
|
+
{copyMessage}
|
|
115
|
+
</Typography>
|
|
116
|
+
)}
|
|
117
|
+
</Stack>
|
|
118
|
+
)
|
|
119
|
+
},
|
|
120
|
+
),
|
|
118
121
|
)
|