@wandelbots/wandelbots-js-react-components 1.8.0 → 1.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.
Files changed (91) hide show
  1. package/README.md +30 -16
  2. package/dist/components/3d-viewport/SafetyZonesRenderer.d.ts +1 -1
  3. package/dist/components/3d-viewport/SafetyZonesRenderer.d.ts.map +1 -1
  4. package/dist/components/CopyableText.d.ts +5 -0
  5. package/dist/components/CopyableText.d.ts.map +1 -0
  6. package/dist/components/LoadingButton.d.ts +1 -1
  7. package/dist/components/LoadingButton.stories.d.ts +1 -1
  8. package/dist/components/LoadingButton.stories.d.ts.map +1 -1
  9. package/dist/components/ThemeSelect.d.ts.map +1 -1
  10. package/dist/components/VelocitySlider.d.ts.map +1 -1
  11. package/dist/components/VelocitySlider.stories.d.ts +2 -2
  12. package/dist/components/VelocitySlider.stories.d.ts.map +1 -1
  13. package/dist/components/jogging/JoggingCartesianAxisControl.stories.d.ts +1 -1
  14. package/dist/components/jogging/JoggingCartesianAxisControl.stories.d.ts.map +1 -1
  15. package/dist/components/jogging/JoggingCartesianTab.d.ts.map +1 -1
  16. package/dist/components/jogging/JoggingCartesianValues.d.ts +1 -1
  17. package/dist/components/jogging/JoggingCartesianValues.d.ts.map +1 -1
  18. package/dist/components/jogging/JoggingJointLimitDetector.d.ts +2 -2
  19. package/dist/components/jogging/JoggingJointLimitDetector.d.ts.map +1 -1
  20. package/dist/components/jogging/JoggingJointRotationControl.d.ts.map +1 -1
  21. package/dist/components/jogging/JoggingJointRotationControl.stories.d.ts +2 -2
  22. package/dist/components/jogging/JoggingJointRotationControl.stories.d.ts.map +1 -1
  23. package/dist/components/jogging/JoggingJointValues.d.ts +1 -1
  24. package/dist/components/jogging/JoggingJointValues.d.ts.map +1 -1
  25. package/dist/components/jogging/JoggingOptions.d.ts.map +1 -1
  26. package/dist/components/jogging/JoggingPanel.d.ts +8 -1
  27. package/dist/components/jogging/JoggingPanel.d.ts.map +1 -1
  28. package/dist/components/jogging/JoggingPanel.stories.d.ts +2 -2
  29. package/dist/components/jogging/JoggingPanel.stories.d.ts.map +1 -1
  30. package/dist/components/jogging/JoggingStore.d.ts +14 -1
  31. package/dist/components/jogging/JoggingStore.d.ts.map +1 -1
  32. package/dist/components/jogging/JoggingVelocitySlider.d.ts.map +1 -1
  33. package/dist/components/wandelscript-editor/WandelscriptEditor.d.ts +2 -2
  34. package/dist/components/wandelscript-editor/WandelscriptEditor.d.ts.map +1 -1
  35. package/dist/components/wandelscript-editor/WandelscriptEditor.stories.d.ts +2 -2
  36. package/dist/components/wandelscript-editor/WandelscriptEditor.stories.d.ts.map +1 -1
  37. package/dist/externalizeComponent.d.ts +7 -0
  38. package/dist/externalizeComponent.d.ts.map +1 -0
  39. package/dist/index.cjs +29 -48
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.ts +49 -9
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +11681 -12331
  44. package/dist/index.js.map +1 -1
  45. package/dist/themes/color.d.ts +1 -1
  46. package/dist/themes/color.d.ts.map +1 -1
  47. package/dist/themes/novaTheme.stories.d.ts +5 -0
  48. package/dist/themes/novaTheme.stories.d.ts.map +1 -0
  49. package/dist/themes/theming.d.ts +49 -0
  50. package/dist/themes/theming.d.ts.map +1 -0
  51. package/package.json +20 -13
  52. package/src/components/3d-viewport/SafetyZonesRenderer.tsx +2 -2
  53. package/src/components/CopyableText.tsx +30 -0
  54. package/src/components/LoadingButton.stories.tsx +19 -26
  55. package/src/components/ThemeSelect.tsx +3 -4
  56. package/src/components/VelocitySlider.stories.tsx +10 -15
  57. package/src/components/VelocitySlider.tsx +7 -2
  58. package/src/components/jogging/JoggingCartesianAxisControl.stories.tsx +21 -21
  59. package/src/components/jogging/JoggingCartesianAxisControl.tsx +1 -1
  60. package/src/components/jogging/JoggingCartesianTab.tsx +37 -44
  61. package/src/components/jogging/JoggingCartesianValues.tsx +37 -33
  62. package/src/components/jogging/JoggingJointLimitDetector.tsx +10 -7
  63. package/src/components/jogging/JoggingJointRotationControl.stories.tsx +31 -19
  64. package/src/components/jogging/JoggingJointRotationControl.tsx +44 -30
  65. package/src/components/jogging/JoggingJointValues.tsx +35 -33
  66. package/src/components/jogging/JoggingOptions.tsx +130 -80
  67. package/src/components/jogging/JoggingPanel.stories.tsx +20 -17
  68. package/src/components/jogging/JoggingPanel.tsx +29 -31
  69. package/src/components/jogging/JoggingStore.tsx +69 -18
  70. package/src/components/jogging/JoggingVelocitySlider.tsx +24 -22
  71. package/src/components/wandelscript-editor/WandelscriptEditor.stories.tsx +7 -7
  72. package/src/components/wandelscript-editor/WandelscriptEditor.tsx +48 -23
  73. package/src/externalizeComponent.tsx +37 -0
  74. package/src/i18n/locales/de/translations.json +2 -1
  75. package/src/i18n/locales/en/translations.json +2 -1
  76. package/src/icons/orientation-coord-system.svg +3 -0
  77. package/src/icons/orientation-tool.svg +3 -0
  78. package/src/index.ts +39 -9
  79. package/src/themes/color.tsx +29 -19
  80. package/src/themes/novaTheme.stories.tsx +77 -0
  81. package/src/themes/themeTypes.d.ts +11 -0
  82. package/src/themes/theming.ts +174 -0
  83. package/dist/themes/theme.d.ts +0 -144
  84. package/dist/themes/theme.d.ts.map +0 -1
  85. package/dist/themes/wbTheme.d.ts +0 -73
  86. package/dist/themes/wbTheme.d.ts.map +0 -1
  87. package/dist/themes/wbTheme.stories.d.ts +0 -7
  88. package/dist/themes/wbTheme.stories.d.ts.map +0 -1
  89. package/src/themes/theme.ts +0 -150
  90. package/src/themes/wbTheme.stories.tsx +0 -64
  91. package/src/themes/wbTheme.ts +0 -186
@@ -1,26 +1,29 @@
1
- import { Meta, StoryObj } from "@storybook/react";
2
- import { JoggingPanel } from "./JoggingPanel";
3
- import { useArgs } from "@storybook/preview-api";
4
- import { NovaClient } from "@wandelbots/wandelbots-js";
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import { JoggingPanel } from "../../index"
3
+ import { useArgs } from "@storybook/preview-api"
4
+ import { NovaClient } from "@wandelbots/wandelbots-js"
5
5
 
6
6
  const meta: Meta<typeof JoggingPanel> = {
7
7
  component: JoggingPanel,
8
8
 
9
9
  args: {
10
- motionGroupId: "0@mock-ur5e"
10
+ motionGroupId: "0@mock-ur5e",
11
11
  },
12
12
  render: function Component(args) {
13
- const [, setArgs] = useArgs();
14
- return <JoggingPanel
15
- {...args}
16
- nova={new NovaClient({
17
- instanceUrl: "https://mock",
18
- mock: true
19
- })}
20
- />;
13
+ const [, setArgs] = useArgs()
14
+ return (
15
+ <JoggingPanel
16
+ {...args}
17
+ nova={
18
+ new NovaClient({
19
+ instanceUrl: "https://mock",
20
+ mock: true,
21
+ })
22
+ }
23
+ />
24
+ )
21
25
  },
22
- };
23
- export default meta;
26
+ }
27
+ export default meta
24
28
 
25
- export const Default: StoryObj<typeof JoggingPanel> = {
26
- };
29
+ export const Default: StoryObj<typeof JoggingPanel> = {}
@@ -6,11 +6,17 @@ import { JoggingJointTab } from "./JoggingJointTab"
6
6
  import { JoggingStore } from "./JoggingStore"
7
7
  import { LoadingCover } from "../LoadingCover"
8
8
  import { runInAction } from "mobx"
9
- import { NovaClient } from "@wandelbots/wandelbots-js"
9
+ import type { NovaClient } from "@wandelbots/wandelbots-js"
10
10
 
11
11
  export type JoggingPanelProps = {
12
+ /** Connection to a Nova instance to use for jogging */
12
13
  nova: NovaClient
14
+ /** Id of the motion group to move e.g. 0@ur5e **/
13
15
  motionGroupId: string
16
+ /** Callback with the jogging panel's state store for further customization/config */
17
+ onSetup?: (store: JoggingStore) => void
18
+ /** Any children will go at the bottom of the panel under the default components */
19
+ children?: React.ReactNode
14
20
  }
15
21
 
16
22
  export const JoggingPanel = observer((props: JoggingPanelProps) => {
@@ -28,6 +34,9 @@ export const JoggingPanel = observer((props: JoggingPanelProps) => {
28
34
  runInAction(() => {
29
35
  state.joggingStore = joggingStore
30
36
  })
37
+ if (props.onSetup) {
38
+ props.onSetup(joggingStore)
39
+ }
31
40
  } catch (err) {
32
41
  state.loadingError = err
33
42
  }
@@ -47,7 +56,7 @@ export const JoggingPanel = observer((props: JoggingPanelProps) => {
47
56
  const {
48
57
  currentTab,
49
58
  selectedTcpId,
50
- selectedCoordSystemId,
59
+ activeCoordSystemId,
51
60
  selectedDiscreteIncrement,
52
61
  } = state.joggingStore
53
62
 
@@ -55,40 +64,27 @@ export const JoggingPanel = observer((props: JoggingPanelProps) => {
55
64
 
56
65
  const cartesianJoggingOpts = {
57
66
  tcpId: selectedTcpId,
58
- coordSystemId: selectedCoordSystemId,
67
+ coordSystemId: activeCoordSystemId,
59
68
  }
60
69
 
61
70
  if (selectedDiscreteIncrement && currentTab.id === "cartesian") {
62
- state.joggingStore.jogger.setJoggingMode("increment", cartesianJoggingOpts)
71
+ state.joggingStore.jogger.setJoggingMode(
72
+ "increment",
73
+ cartesianJoggingOpts,
74
+ )
63
75
  } else {
64
- state.joggingStore.jogger.setJoggingMode(currentTab.id, cartesianJoggingOpts)
76
+ state.joggingStore.jogger.setJoggingMode(
77
+ currentTab.id,
78
+ cartesianJoggingOpts,
79
+ )
65
80
  }
66
81
  }, [
67
82
  state.joggingStore?.currentTab,
68
83
  state.joggingStore?.selectedTcpId,
69
- state.joggingStore?.selectedCoordSystemId,
84
+ state.joggingStore?.activeCoordSystemId,
70
85
  state.joggingStore?.selectedDiscreteIncrement,
71
86
  ])
72
87
 
73
- useEffect(() => {
74
-
75
- // Set the robot to default control mode (JoZi says is important for physical robot jogging)
76
- async function init() {
77
- if (!state.joggingStore) return
78
-
79
- try {
80
- await nova.api.controller.setDefaultMode(
81
- state.joggingStore.jogger.motionStream.controllerId,
82
- "MODE_CONTROL",
83
- )
84
- } catch (err) {
85
- console.error(err)
86
- }
87
- }
88
-
89
- init()
90
- }, [state.joggingStore?.jogger.motionStream.controllerId])
91
-
92
88
  if (!state.joggingStore) {
93
89
  return (
94
90
  <JoggingPanelOuter>
@@ -119,9 +115,8 @@ export const JoggingPanel = observer((props: JoggingPanelProps) => {
119
115
  {store.currentTab.id === "cartesian" && (
120
116
  <JoggingCartesianTab store={store} />
121
117
  )}
122
- {store.currentTab.id === "joint" && (
123
- <JoggingJointTab store={store} />
124
- )}
118
+ {store.currentTab.id === "joint" && <JoggingJointTab store={store} />}
119
+ {props.children}
125
120
  </Stack>
126
121
  </Stack>
127
122
  </JoggingPanelOuter>
@@ -136,11 +131,14 @@ function JoggingPanelOuter({ children }: { children: React.ReactNode }) {
136
131
  minWidth: "350px",
137
132
  overflowY: "auto",
138
133
  position: "relative",
134
+ height: "100%",
139
135
  }}
140
136
  >
141
- <Paper sx={{
142
- minHeight: "90vh"
143
- }}>
137
+ <Paper
138
+ sx={{
139
+ height: "100%",
140
+ }}
141
+ >
144
142
  {children}
145
143
  </Paper>
146
144
  </Stack>
@@ -1,6 +1,11 @@
1
- import { keyBy } from "lodash-es"
1
+ import { keyBy, uniqueId } from "lodash-es"
2
2
  import { autorun, makeAutoObservable, type IReactionDisposer } from "mobx"
3
- import type { CoordinateSystem, JoggerConnection, MotionGroupSpecification, RobotTcp } from "@wandelbots/wandelbots-js"
3
+ import type {
4
+ CoordinateSystem,
5
+ JoggerConnection,
6
+ MotionGroupSpecification,
7
+ RobotTcp,
8
+ } from "@wandelbots/wandelbots-js"
4
9
  import { tryParseJson } from "@wandelbots/wandelbots-js"
5
10
 
6
11
  const discreteIncrementOptions = [
@@ -22,8 +27,8 @@ export type IncrementOptionId = IncrementOption["id"]
22
27
  export class JoggingStore {
23
28
  selectedTabId: "cartesian" | "joint" | "debug" = "cartesian"
24
29
 
25
- // TODO
26
- isLocked: boolean = false
30
+ /** Locks to prevent UI interactions during certain operations */
31
+ locks = new Set<string>()
27
32
 
28
33
  /**
29
34
  * Id of selected coordinate system from among those defined on the API side
@@ -33,6 +38,13 @@ export class JoggingStore {
33
38
  /** Id of selected tool center point from among the options available on the robot */
34
39
  selectedTcpId: string = ""
35
40
 
41
+ /**
42
+ * Whether the user is jogging in the coordinate system or tool orientation.
43
+ * When in tool orientation, the robot moves in a direction relative to the
44
+ * attached tool rotation.
45
+ */
46
+ selectedOrientation: "coordsys" | "tool" = "coordsys"
47
+
36
48
  /**
37
49
  * Id of selected increment amount for jogging. Options are defined by robot pad.
38
50
  * When non-continuous, jogging moves the robot by a fixed number of mm or degrees
@@ -74,20 +86,28 @@ export class JoggingStore {
74
86
  const { nova } = jogger
75
87
 
76
88
  // Find out what TCPs this motion group has (we need it for jogging)
77
- const [motionGroupSpec, { coordinatesystems }, { tcps }] = await Promise.all([
78
- nova.api.motionGroupInfos.getMotionGroupSpecification(jogger.motionGroupId),
79
-
80
- // Fetch coord systems so user can select between them
81
- nova.api.coordinateSystems.listCoordinateSystems("ROTATION_VECTOR"),
82
-
83
- // Same for TCPs
84
- nova.api.motionGroupInfos.listTcps(
85
- jogger.motionGroupId,
86
- "ROTATION_VECTOR",
87
- ),
88
- ])
89
-
90
- return new JoggingStore(jogger, motionGroupSpec, coordinatesystems || [], tcps || [])
89
+ const [motionGroupSpec, { coordinatesystems }, { tcps }] =
90
+ await Promise.all([
91
+ nova.api.motionGroupInfos.getMotionGroupSpecification(
92
+ jogger.motionGroupId,
93
+ ),
94
+
95
+ // Fetch coord systems so user can select between them
96
+ nova.api.coordinateSystems.listCoordinateSystems("ROTATION_VECTOR"),
97
+
98
+ // Same for TCPs
99
+ nova.api.motionGroupInfos.listTcps(
100
+ jogger.motionGroupId,
101
+ "ROTATION_VECTOR",
102
+ ),
103
+ ])
104
+
105
+ return new JoggingStore(
106
+ jogger,
107
+ motionGroupSpec,
108
+ coordinatesystems || [],
109
+ tcps || [],
110
+ )
91
111
  }
92
112
 
93
113
  constructor(
@@ -147,6 +167,10 @@ export class JoggingStore {
147
167
  if (["translate", "rotate"].includes(save.selectedCartesianMotionType)) {
148
168
  this.selectedCartesianMotionType = save.selectedCartesianMotionType
149
169
  }
170
+
171
+ if (["coordsys", "tool"].includes(save.selectedOrientation)) {
172
+ this.selectedOrientation = save.selectedOrientation
173
+ }
150
174
  }
151
175
 
152
176
  saveToLocalStorage() {
@@ -156,11 +180,16 @@ export class JoggingStore {
156
180
  )
157
181
  }
158
182
 
183
+ get isLocked() {
184
+ return this.locks.size > 0
185
+ }
186
+
159
187
  get localStorageSave() {
160
188
  return {
161
189
  selectedTabId: this.selectedTabId,
162
190
  selectedCoordSystemId: this.selectedCoordSystemId,
163
191
  selectedTcpId: this.selectedTcpId,
192
+ selectedOrientation: this.selectedOrientation,
164
193
  selectedIncrementId: this.selectedIncrementId,
165
194
  selectedCartesianMotionType: this.selectedCartesianMotionType,
166
195
  }
@@ -211,6 +240,12 @@ export class JoggingStore {
211
240
  return this.coordSystemsById[this.selectedCoordSystemId]
212
241
  }
213
242
 
243
+ get activeCoordSystemId() {
244
+ return this.selectedOrientation === "tool"
245
+ ? "tool"
246
+ : this.selectedCoordSystemId
247
+ }
248
+
214
249
  get tcpsById() {
215
250
  return keyBy(this.tcps, (tcp) => tcp.id)
216
251
  }
@@ -272,6 +307,10 @@ export class JoggingStore {
272
307
  this.selectedTcpId = id
273
308
  }
274
309
 
310
+ setSelectedOrientation(orientation: "coordsys" | "tool") {
311
+ this.selectedOrientation = orientation
312
+ }
313
+
275
314
  setSelectedIncrementId(id: IncrementOptionId) {
276
315
  this.selectedIncrementId = id
277
316
  }
@@ -291,4 +330,16 @@ export class JoggingStore {
291
330
  setSelectedCartesianMotionType(type: "translate" | "rotate") {
292
331
  this.selectedCartesianMotionType = type
293
332
  }
333
+
334
+ /** Lock the UI until the given async callback resolves */
335
+ async withMotionLock(fn: () => Promise<void>) {
336
+ const lockId = uniqueId()
337
+ this.locks.add(lockId)
338
+
339
+ try {
340
+ return await fn()
341
+ } finally {
342
+ this.locks.delete(lockId)
343
+ }
344
+ }
294
345
  }
@@ -1,4 +1,4 @@
1
- import { Stack, Divider, Typography } from "@mui/material"
1
+ import { Stack, Typography } from "@mui/material"
2
2
  import { observer, useLocalObservable } from "mobx-react-lite"
3
3
  import type { JoggingStore } from "./JoggingStore"
4
4
  import { VelocitySlider } from "../VelocitySlider"
@@ -21,35 +21,37 @@ export const JoggingVelocitySlider = observer(
21
21
  }))
22
22
 
23
23
  return (
24
- <Stack>
25
- <Divider />
26
- <Stack
27
- sx={{
28
- margin: "0px 20px",
29
- marginTop: "0.8rem",
30
- marginBottom: "0.8rem",
31
- }}
32
- >
33
- <Stack sx={{ width: "380px", maxWidth: "90%", margin: "auto" }}>
24
+ <Stack
25
+ sx={{
26
+ margin: "0px 20px",
27
+ marginTop: "24px",
28
+ marginBottom: "24px",
29
+ }}
30
+ >
31
+ <Stack sx={{ width: "380px", maxWidth: "90%", margin: "auto" }}>
32
+ <Stack
33
+ sx={{
34
+ justifyContent: "center",
35
+ }}
36
+ >
34
37
  <Typography
35
38
  sx={{
36
- fontWeight: "bold",
37
- fontSize: "15px",
39
+ fontSize: "12px",
40
+ opacity: 0.6,
38
41
  }}
39
42
  >
40
43
  {t("Jogging.Velocity.lb")}
41
44
  </Typography>
42
- <VelocitySlider
43
- velocity={store.velocityInCurrentUnits}
44
- min={store.minVelocityInCurrentUnits}
45
- max={store.maxVelocityInCurrentUnits}
46
- onVelocityChange={store.setVelocityFromSlider}
47
- disabled={store.isLocked}
48
- valueLabelFormat={state.valueLabelFormat}
49
- />
50
45
  </Stack>
46
+ <VelocitySlider
47
+ velocity={store.velocityInCurrentUnits}
48
+ min={store.minVelocityInCurrentUnits}
49
+ max={store.maxVelocityInCurrentUnits}
50
+ onVelocityChange={store.setVelocityFromSlider}
51
+ disabled={store.isLocked}
52
+ valueLabelFormat={state.valueLabelFormat}
53
+ />
51
54
  </Stack>
52
- <Divider />
53
55
  </Stack>
54
56
  )
55
57
  },
@@ -1,10 +1,10 @@
1
- import { Meta, StoryObj } from "@storybook/react";
2
- import { WandelscriptEditor } from "./WandelscriptEditor";
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import { WandelscriptEditor } from "../../index"
3
3
 
4
4
  const meta: Meta<typeof WandelscriptEditor> = {
5
5
  component: WandelscriptEditor,
6
- };
7
- export default meta;
6
+ }
7
+ export default meta
8
8
 
9
9
  const defaultCode = `start = [832, -452, 289] # The start position of the edge
10
10
  end = [817, 168, 288] # The end position of the edge
@@ -29,7 +29,7 @@ for i = 0..<int(n / 2) - 1:
29
29
  move via arc(a) to b
30
30
  if i == 10:
31
31
  test_pose = planned_pose()
32
- `;
32
+ `
33
33
 
34
34
  export const Editor: StoryObj<typeof WandelscriptEditor> = {
35
35
  args: {
@@ -40,6 +40,6 @@ export const Editor: StoryObj<typeof WandelscriptEditor> = {
40
40
  <div style={{ height: "400px" }}>
41
41
  <WandelscriptEditor {...props} />
42
42
  </div>
43
- );
43
+ )
44
44
  },
45
- };
45
+ }
@@ -1,29 +1,46 @@
1
1
  import Editor, { useMonaco, type Monaco } from "@monaco-editor/react"
2
- import React, { useEffect } from "react"
3
- import { createHighlighter, type BundledTheme } from "shiki"
2
+ import { useEffect, useRef, useState } from "react"
3
+ import type {
4
+ BundledLanguage,
5
+ HighlighterGeneric} from "shiki";
6
+ import {
7
+ createHighlighter,
8
+ type BundledTheme,
9
+ } from "shiki"
4
10
  import { shikiToMonaco } from "@shikijs/monaco"
5
11
 
6
12
  import wandelscriptTextmateGrammar from "./wandelscript.tmLanguage"
7
13
  import { useTheme } from "@mui/material"
8
- import { editor } from "monaco-editor"
14
+ import type { editor } from "monaco-editor"
9
15
 
10
16
  type WandelscriptEditorProps = {
11
17
  /** The current Wandelscript content of the code editor (controlled component) */
12
18
  code?: string
13
19
  /** What to do when the user edits the code */
14
- onChange?: (code: string|undefined, ev: editor.IModelContentChangedEvent) => void
15
- /** Callback to further configure monaco on startup if needed */
20
+ onChange?: (
21
+ code: string | undefined,
22
+ ev: editor.IModelContentChangedEvent,
23
+ ) => void
24
+ /** Options for monaco editor */
16
25
  monacoOptions?: editor.IEditorOptions
17
26
  /** Callback to further configure monaco on startup if needed */
18
27
  monacoSetup?: (monaco: Monaco) => void
19
28
  }
20
29
 
21
- const shikiTheme: BundledTheme = "dark-plus"
22
-
23
30
  /** A Monaco (VSCode-style) embedded code editor with Wandelscript syntax highlighting */
24
31
  export const WandelscriptEditor = (props: WandelscriptEditorProps) => {
25
32
  const monaco = useMonaco()
26
33
  const theme = useTheme()
34
+ const shikiHighlighterRef = useRef<HighlighterGeneric<
35
+ BundledLanguage,
36
+ BundledTheme
37
+ > | null>(null)
38
+
39
+ const [activeShikiTheme, setActiveShikiTheme] =
40
+ useState<BundledTheme>("dark-plus")
41
+
42
+ const targetShikiTheme =
43
+ theme.palette.mode === "dark" ? "dark-plus" : "light-plus"
27
44
 
28
45
  async function setupEditor(monaco: Monaco) {
29
46
  // Register and configure the Wandelscript language
@@ -50,38 +67,46 @@ export const WandelscriptEditor = (props: WandelscriptEditorProps) => {
50
67
  // Monaco doesn't support TextMate grammar config directly, so we
51
68
  // use Shiki as an intermediary
52
69
 
53
- const highlighter = await createHighlighter({
54
- // Our textmate grammar doesn't quite conform to the expected type
55
- // here; I'm not sure what the missing properties mean exactly
56
- langs: [wandelscriptTextmateGrammar as any],
57
- themes: [shikiTheme],
58
- })
70
+ if (!shikiHighlighterRef.current) {
71
+ shikiHighlighterRef.current = await createHighlighter({
72
+ // Our textmate grammar doesn't quite conform to the expected type
73
+ // here; I'm not sure what the missing properties mean exactly
74
+ langs: [wandelscriptTextmateGrammar as any],
75
+ themes: ["dark-plus", "light-plus"],
76
+ })
77
+ }
59
78
 
60
- shikiToMonaco(highlighter, monaco)
79
+ shikiToMonaco(shikiHighlighterRef.current, monaco)
61
80
 
62
81
  // Override the generated shiki theme to use shiki syntax highlighting
63
82
  // but vscode colors
64
- monaco.editor.defineTheme(shikiTheme, {
83
+ monaco.editor.defineTheme(targetShikiTheme, {
65
84
  base: theme.palette.mode === "dark" ? "vs-dark" : "vs",
66
85
  inherit: true,
67
86
  rules: [],
68
- colors: {
69
- "editor.background": "#262F42",
70
- "editorLineNumber.foreground": "#797979",
71
- "editorLineNumber.activeForeground": "#e9e9e9",
72
- },
87
+ colors:
88
+ theme.palette.mode === "dark"
89
+ ? {
90
+ "editor.background": "#262F42",
91
+ "editorLineNumber.foreground": "#797979",
92
+ "editorLineNumber.activeForeground": "#e9e9e9",
93
+ "editor.lineHighlightBorder": "#494949",
94
+ }
95
+ : {},
73
96
  })
74
97
 
75
98
  if (props.monacoSetup) {
76
99
  props.monacoSetup(monaco)
77
100
  }
101
+
102
+ setActiveShikiTheme(targetShikiTheme)
78
103
  }
79
104
 
80
105
  useEffect(() => {
81
106
  if (monaco) {
82
107
  setupEditor(monaco)
83
108
  }
84
- }, [monaco])
109
+ }, [monaco, targetShikiTheme])
85
110
 
86
111
  if (!monaco) {
87
112
  return null
@@ -92,7 +117,7 @@ export const WandelscriptEditor = (props: WandelscriptEditorProps) => {
92
117
  value={props.code}
93
118
  onChange={props.onChange}
94
119
  defaultLanguage="wandelscript"
95
- theme={shikiTheme}
120
+ theme={activeShikiTheme}
96
121
  options={{
97
122
  minimap: { enabled: false },
98
123
  wordWrap: "on",
@@ -101,4 +126,4 @@ export const WandelscriptEditor = (props: WandelscriptEditorProps) => {
101
126
  }}
102
127
  />
103
128
  )
104
- }
129
+ }
@@ -0,0 +1,37 @@
1
+ import { ThemeProvider } from "@emotion/react"
2
+ import { createMUIThemeFromNova, createNovaTheme } from "./themes/theming"
3
+ import type { FC } from "react"
4
+ import { useTheme } from "@mui/material"
5
+ import { I18nextProvider } from "react-i18next"
6
+ // @ts-expect-error invalid type-only import error
7
+ import i18n from "./i18n/config"
8
+
9
+ /**
10
+ * Our components require a certain context that may or may not
11
+ * be provided by the user application; this wrapper ensures
12
+ * they can be used either way.
13
+ */
14
+ export function externalizeComponent<T>(
15
+ Component: (props: T) => React.ReactNode,
16
+ ) {
17
+ return (props: T) => (
18
+ <NovaComponentsProvider>
19
+ <Component {...(props as T & JSX.IntrinsicAttributes)} />
20
+ </NovaComponentsProvider>
21
+ )
22
+ }
23
+
24
+ const NovaComponentsProvider: FC<{ children: React.ReactNode }> = ({
25
+ children,
26
+ }) => {
27
+ const theme = useTheme()
28
+ const defaultNovaTheme = createNovaTheme({
29
+ mode: theme.palette.mode,
30
+ })
31
+ const defaultTheme = createMUIThemeFromNova(defaultNovaTheme)
32
+ return (
33
+ <ThemeProvider theme={defaultTheme}>
34
+ <I18nextProvider i18n={i18n}>{children}</I18nextProvider>
35
+ </ThemeProvider>
36
+ )
37
+ }
@@ -8,5 +8,6 @@
8
8
  "Jogging.Cartesian.Translation.bt": "Translation",
9
9
  "Jogging.Cartesian.Rotation.bt": "Rotation",
10
10
  "Jogging.Joints.JointValues.lb": "Gelenkwerte",
11
- "Jogging.Increment.Continuous.dd": "Fortlaufend"
11
+ "Jogging.Increment.Continuous.dd": "Fortlaufend",
12
+ "Jogging.Cartesian.Orientation.lb": "Orientierung"
12
13
  }
@@ -8,5 +8,6 @@
8
8
  "Jogging.Cartesian.Translation.bt": "Translation",
9
9
  "Jogging.Cartesian.Rotation.bt": "Rotation",
10
10
  "Jogging.Joints.JointValues.lb": "Joint values",
11
- "Jogging.Increment.Continuous.dd": "Continuous"
11
+ "Jogging.Increment.Continuous.dd": "Continuous",
12
+ "Jogging.Cartesian.Orientation.lb": "Orientation"
12
13
  }
@@ -0,0 +1,3 @@
1
+ <svg width="21" height="21" viewBox="0 0 23 22" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M21.7099 16.2621L20.6205 16.608L21.2793 18.679L18.3573 17.2179V9.85689L12.0715 6.71409V2.89269L13.3795 4.21073L14.1921 3.40503L11.5179 0.714233L8.81153 3.40223L9.61723 4.21363L10.9286 2.91113V6.71413L4.64295 9.85693V17.2179L1.72915 18.6747L2.38625 16.6083L1.29687 16.2625L0.0714111 20.1429L3.89721 21.2858L4.24307 20.1966L2.40729 19.6134L5.28149 18.1766L11.5001 21.2856L17.7183 18.1764L20.5947 19.6146L18.7635 20.1964L19.1094 21.2856L22.9286 20.1427L21.7099 16.2621ZM11.5001 12.6463L6.55967 10.1763L11.5001 7.70633L16.4409 10.1767L11.5001 12.6463ZM12.0715 13.6388L17.2145 11.0672V17.1504L12.0715 19.722V13.6388ZM5.78567 11.0672L10.9287 13.6388V19.722L5.78567 17.1504V11.0672Z" fill="currentColor"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M11.87 7.12001L13.56 8.81002L16.55 5.82001L12.82 2.09001L11.87 1.14001L4.21001 8.80001L3.26001 9.75001L7.25001 13.74V17.18H14.8V13.63L10.08 8.91001L11.87 7.12001ZM10.96 4.13001L11.87 3.22001L14.47 5.82001L13.56 6.73001L10.96 4.13001ZM8.71001 14.37H12.45L11.11 13.03L11.07 12.99H8.57001L5.32001 9.74001L9.91001 5.15001L10.83 6.07001L8.00001 8.90001L13.33 14.23V15.71H8.70001V14.36L8.71001 14.37Z" fill="currentColor" fill-opacity="0.8"/>
3
+ </svg>
package/src/index.ts CHANGED
@@ -1,10 +1,40 @@
1
- export * from "./components/wandelscript-editor/WandelscriptEditor"
2
- export * from "./components/robots/SupportedRobot"
3
- export * from "./components/robots/Robot"
4
- export * from "./components/robots/AxisConfig"
5
- export * from "./components/3d-viewport/PresetEnvironment"
6
- export * from "./components/3d-viewport/SafetyZonesRenderer"
7
- export * from "./components/jogging/JoggingCartesianAxisControl"
8
- export * from "./components/jogging/JoggingJointRotationControl"
9
- export * from "./components/jogging/JoggingPanel"
1
+ import { externalizeComponent } from "./externalizeComponent"
2
+
3
+ export type * from "./components/wandelscript-editor/WandelscriptEditor"
4
+ import { WandelscriptEditor as WE } from "./components/wandelscript-editor/WandelscriptEditor"
5
+ export const WandelscriptEditor = externalizeComponent(WE)
6
+
7
+ export type * from "./components/robots/SupportedRobot"
8
+ import { SupportedRobot as SR } from "./components/robots/SupportedRobot"
9
+ export const SupportedRobot = externalizeComponent(SR)
10
+
11
+ export type * from "./components/robots/Robot"
12
+ import { Robot as R } from "./components/robots/Robot"
13
+ export const Robot = externalizeComponent(R)
14
+
15
+ export type * from "./components/3d-viewport/PresetEnvironment"
16
+ import { PresetEnvironment as PE } from "./components/3d-viewport/PresetEnvironment"
17
+ export const PresetEnvironment = externalizeComponent(PE)
18
+
19
+ export type * from "./components/3d-viewport/SafetyZonesRenderer"
20
+ import { SafetyZonesRenderer as SZR } from "./components/3d-viewport/SafetyZonesRenderer"
21
+ export const SafetyZonesRenderer = externalizeComponent(SZR)
22
+
23
+ export type * from "./components/jogging/JoggingCartesianAxisControl"
24
+ import { JoggingCartesianAxisControl as JCAC } from "./components/jogging/JoggingCartesianAxisControl"
25
+ export const JoggingCartesianAxisControl = externalizeComponent(JCAC)
26
+
27
+ export type * from "./components/jogging/JoggingJointRotationControl"
28
+ import { JoggingJointRotationControl as JJRC } from "./components/jogging/JoggingJointRotationControl"
29
+ export const JoggingJointRotationControl = externalizeComponent(JJRC)
30
+
31
+ export type { JoggingStore } from "./components/jogging/JoggingStore"
32
+ export type * from "./components/jogging/JoggingPanel"
33
+ import { JoggingPanel as JP } from "./components/jogging/JoggingPanel"
34
+ export const JoggingPanel = externalizeComponent(JP)
35
+
36
+ export type * from "./components/VelocitySlider"
37
+ import { VelocitySlider as VS } from "./components/VelocitySlider"
38
+ export const VelocitySlider = externalizeComponent(VS)
39
+
10
40
  export * from "./components/utils/hooks"