@wandelbots/wandelbots-js-react-components 1.7.1 → 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 (96) 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/robots/FANUC_CRX20iAL.d.ts +3 -0
  34. package/dist/components/robots/FANUC_CRX20iAL.d.ts.map +1 -0
  35. package/dist/components/robots/SupportedRobot.d.ts.map +1 -1
  36. package/dist/components/wandelscript-editor/WandelscriptEditor.d.ts +2 -2
  37. package/dist/components/wandelscript-editor/WandelscriptEditor.d.ts.map +1 -1
  38. package/dist/components/wandelscript-editor/WandelscriptEditor.stories.d.ts +2 -2
  39. package/dist/components/wandelscript-editor/WandelscriptEditor.stories.d.ts.map +1 -1
  40. package/dist/externalizeComponent.d.ts +7 -0
  41. package/dist/externalizeComponent.d.ts.map +1 -0
  42. package/dist/index.cjs +29 -48
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.d.ts +49 -9
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +11672 -12089
  47. package/dist/index.js.map +1 -1
  48. package/dist/themes/color.d.ts +1 -1
  49. package/dist/themes/color.d.ts.map +1 -1
  50. package/dist/themes/novaTheme.stories.d.ts +5 -0
  51. package/dist/themes/novaTheme.stories.d.ts.map +1 -0
  52. package/dist/themes/theming.d.ts +49 -0
  53. package/dist/themes/theming.d.ts.map +1 -0
  54. package/package.json +20 -13
  55. package/src/components/3d-viewport/SafetyZonesRenderer.tsx +2 -2
  56. package/src/components/CopyableText.tsx +30 -0
  57. package/src/components/LoadingButton.stories.tsx +19 -26
  58. package/src/components/ThemeSelect.tsx +3 -4
  59. package/src/components/VelocitySlider.stories.tsx +10 -15
  60. package/src/components/VelocitySlider.tsx +7 -2
  61. package/src/components/jogging/JoggingCartesianAxisControl.stories.tsx +21 -21
  62. package/src/components/jogging/JoggingCartesianAxisControl.tsx +1 -1
  63. package/src/components/jogging/JoggingCartesianTab.tsx +37 -44
  64. package/src/components/jogging/JoggingCartesianValues.tsx +37 -33
  65. package/src/components/jogging/JoggingJointLimitDetector.tsx +10 -7
  66. package/src/components/jogging/JoggingJointRotationControl.stories.tsx +31 -19
  67. package/src/components/jogging/JoggingJointRotationControl.tsx +44 -30
  68. package/src/components/jogging/JoggingJointValues.tsx +35 -33
  69. package/src/components/jogging/JoggingOptions.tsx +130 -80
  70. package/src/components/jogging/JoggingPanel.stories.tsx +20 -17
  71. package/src/components/jogging/JoggingPanel.tsx +29 -31
  72. package/src/components/jogging/JoggingStore.tsx +69 -18
  73. package/src/components/jogging/JoggingVelocitySlider.tsx +24 -22
  74. package/src/components/robots/FANUC_CRX20iAL.tsx +176 -0
  75. package/src/components/robots/SupportedRobot.tsx +4 -0
  76. package/src/components/wandelscript-editor/WandelscriptEditor.stories.tsx +7 -7
  77. package/src/components/wandelscript-editor/WandelscriptEditor.tsx +48 -23
  78. package/src/externalizeComponent.tsx +37 -0
  79. package/src/i18n/locales/de/translations.json +2 -1
  80. package/src/i18n/locales/en/translations.json +2 -1
  81. package/src/icons/orientation-coord-system.svg +3 -0
  82. package/src/icons/orientation-tool.svg +3 -0
  83. package/src/index.ts +39 -9
  84. package/src/themes/color.tsx +29 -19
  85. package/src/themes/novaTheme.stories.tsx +77 -0
  86. package/src/themes/themeTypes.d.ts +11 -0
  87. package/src/themes/theming.ts +174 -0
  88. package/dist/themes/theme.d.ts +0 -144
  89. package/dist/themes/theme.d.ts.map +0 -1
  90. package/dist/themes/wbTheme.d.ts +0 -73
  91. package/dist/themes/wbTheme.d.ts.map +0 -1
  92. package/dist/themes/wbTheme.stories.d.ts +0 -7
  93. package/dist/themes/wbTheme.stories.d.ts.map +0 -1
  94. package/src/themes/theme.ts +0 -150
  95. package/src/themes/wbTheme.stories.tsx +0 -64
  96. package/src/themes/wbTheme.ts +0 -186
@@ -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"
@@ -1,41 +1,51 @@
1
- import React, { ReactNode, useEffect, useState } from "react";
1
+ import { Box, Typography, useTheme } from "@mui/material"
2
+ import type { ReactNode} from "react";
3
+ import { useEffect, useState } from "react"
2
4
 
3
5
  export function ColorSection(props: { name: string; children: ReactNode }) {
4
6
  return (
5
7
  <>
6
- <h2>{props.name}</h2>
7
- <div
8
- style={{
8
+ <Typography
9
+ component="h2"
10
+ sx={{
11
+ marginTop: "1rem",
12
+ }}
13
+ >
14
+ {props.name}
15
+ </Typography>
16
+ <Box
17
+ sx={{
9
18
  display: "grid",
10
19
  gridTemplateColumns: "repeat(auto-fill, minmax(200px, 1fr))",
11
20
  gap: "20px",
12
21
  }}
13
22
  >
14
23
  {props.children}
15
- </div>
24
+ </Box>
16
25
  </>
17
- );
26
+ )
18
27
  }
19
28
 
20
29
  export function Color({ name, color }: { name: string; color: string }) {
21
- const [showCopied, setShowCopied] = useState(false);
30
+ const theme = useTheme()
31
+ const [showCopied, setShowCopied] = useState(false)
22
32
 
23
33
  function handleClick(value: string) {
24
34
  if (!navigator.clipboard) {
25
- console.error("can't send value to clipboard");
26
- return;
35
+ console.error("can't send value to clipboard")
36
+ return
27
37
  }
28
- navigator.clipboard.writeText(value);
29
- setShowCopied(true);
38
+ navigator.clipboard.writeText(value)
39
+ setShowCopied(true)
30
40
  }
31
41
 
32
42
  useEffect(() => {
33
43
  if (showCopied) {
34
44
  setTimeout(() => {
35
- setShowCopied(false);
36
- }, 2000);
45
+ setShowCopied(false)
46
+ }, 2000)
37
47
  }
38
- }, [showCopied]);
48
+ }, [showCopied])
39
49
 
40
50
  return (
41
51
  <li
@@ -58,17 +68,17 @@ export function Color({ name, color }: { name: string; color: string }) {
58
68
  // border: "1px solid lightgray",
59
69
  }}
60
70
  />
61
- <span>{name}</span>
71
+ <Typography component="span">{name}</Typography>
62
72
  <br />
63
- <span
73
+ <Typography
64
74
  style={{
65
- color: "gray",
75
+ opacity: 0.7,
66
76
  fontSize: "0.9em",
67
77
  fontFamily: "monospace",
68
78
  }}
69
79
  >
70
80
  {showCopied ? "Copied ✔︎" : color}
71
- </span>
81
+ </Typography>
72
82
  </li>
73
- );
83
+ )
74
84
  }
@@ -0,0 +1,77 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import { Color, ColorSection } from "./color"
3
+ import { useTheme } from "@mui/material"
4
+
5
+ const ColorPalette = () => {
6
+ const theme = useTheme()
7
+
8
+ return (
9
+ <div
10
+ style={{
11
+ fontFamily: "sans-serif",
12
+ }}
13
+ >
14
+ <ColorSection name="Palette">
15
+ <Color name="Primary" color={theme.palette.primary.main} />
16
+ <Color name="Secondary" color={theme.palette.secondary.main} />
17
+ <Color name="Background" color={theme.palette.background.default} />
18
+ </ColorSection>
19
+ <ColorSection name="Text">
20
+ <Color name="Primary" color={theme.palette.text.primary} />
21
+ <Color name="Secondary" color={theme.palette.text.secondary} />
22
+ </ColorSection>
23
+ <ColorSection name="Button">
24
+ <Color
25
+ name="Primary Background"
26
+ color={theme.nova.colors.buttonPrimary.background}
27
+ />
28
+ <Color
29
+ name="Primary Text"
30
+ color={theme.nova.colors.buttonPrimary.text}
31
+ />
32
+ <Color
33
+ name="Secondary Background"
34
+ color={theme.nova.colors.buttonSecondary.background}
35
+ />
36
+ <Color
37
+ name="Secondary Text"
38
+ color={theme.nova.colors.buttonSecondary.background}
39
+ />
40
+ <Color
41
+ name="Back Background"
42
+ color={theme.nova.colors.buttonBack.background}
43
+ />
44
+ <Color name="Back Text" color={theme.nova.colors.buttonBack.text} />
45
+ </ColorSection>
46
+ <ColorSection name="Input Field">
47
+ <Color
48
+ name="Background"
49
+ color={theme.nova.colors.inputField.background}
50
+ />
51
+ <Color name="Text" color={theme.nova.colors.inputField.text} />
52
+ <Color
53
+ name="Unit Background"
54
+ color={theme.nova.colors.inputField.unitBackground}
55
+ />
56
+ <Color name="Unit Text" color={theme.nova.colors.inputField.unitText} />
57
+ </ColorSection>
58
+ </div>
59
+ )
60
+ }
61
+
62
+ const meta: Meta<typeof ColorPalette> = {
63
+ component: ColorPalette,
64
+ parameters: {
65
+ docs: {
66
+ description: {
67
+ story: "",
68
+ },
69
+ },
70
+ },
71
+ }
72
+
73
+ export default meta
74
+
75
+ type Story = StoryObj<typeof ColorPalette>
76
+
77
+ // export const colorPalette: Story = {}
@@ -0,0 +1,11 @@
1
+ import { NovaTheme } from "./novaTheme";
2
+
3
+ declare module "@mui/material/styles" {
4
+ interface Theme {
5
+ nova: NovaTheme
6
+ }
7
+
8
+ interface ThemeOptions {
9
+ nova?: NovaTheme
10
+ }
11
+ }
@@ -0,0 +1,174 @@
1
+ "use client"
2
+
3
+ import type { Theme } from "@mui/material/styles"
4
+ import { createTheme } from "@mui/material/styles"
5
+ import { defaultsDeep } from "lodash-es"
6
+
7
+ /**
8
+ * The palette of named colors we pick from for
9
+ * configuring the default nova themes.
10
+ */
11
+ const colors = {
12
+ white: "#FFFFFF",
13
+ midnightblue: "#001337",
14
+ lightbuttonblue: "#47D3FF",
15
+ midnightgray: "#DDE0E4",
16
+ midnightgray500: "#828B9B",
17
+ skyblue500: "#06B8F1",
18
+ skyblue600: "#0094CE",
19
+ darkishblue: "#262F42",
20
+ darkestblue: "#101629",
21
+ grayishblue: "#505968",
22
+ darkgrayishblue: "#363c4b",
23
+ scaryred: "#FF0E65",
24
+ tealGreen: "#1AC0B2",
25
+ magenta: "#EA3785",
26
+ }
27
+
28
+ /**
29
+ * A Nova components theme is a collection of Nova-specific settings that is
30
+ * not specifically MUI-related, but can be used to construct a MUI
31
+ * theme in turn.
32
+ *
33
+ * This object defines the default Nova theme settings, and the structure
34
+ * of the options here is used to validate alternative themes.
35
+ */
36
+ export const novaDarkTheme = {
37
+ mode: "dark" as "dark" | "light",
38
+ colors: {
39
+ primary: colors.skyblue500,
40
+ textDefault: colors.white,
41
+ textSubtle: colors.midnightgray,
42
+ background: {
43
+ default: colors.darkishblue,
44
+ panel: colors.darkestblue,
45
+ },
46
+ },
47
+ }
48
+
49
+ export type NovaTheme = typeof novaDarkTheme
50
+
51
+ export const novaLightTheme = {
52
+ mode: "light",
53
+ colors: {
54
+ primary: colors.skyblue500,
55
+ textDefault: colors.darkishblue,
56
+ textSubtle: colors.midnightgray,
57
+ background: {
58
+ default: colors.skyblue500,
59
+ panel: colors.white,
60
+ },
61
+ },
62
+ } satisfies NovaTheme
63
+
64
+ /**
65
+ * Configure a Nova theme with the given options.
66
+ * If no options are provided, the default dark theme is used.
67
+ * Otherwise, the default dark or light theme is extended with
68
+ * the overrides provided as appropriate.
69
+ */
70
+ export function createNovaTheme(opts: Partial<NovaTheme> = {}): NovaTheme {
71
+ const defaults = opts.mode === "light" ? novaLightTheme : novaDarkTheme
72
+ return defaultsDeep(opts, defaults)
73
+ }
74
+
75
+ /**
76
+ * Turn a set of Nova theme settings into a Material UI theme.
77
+ *
78
+ * The original Nova settings are available on the resulting MUI
79
+ * theme object under the `nova` key, if needed.
80
+ */
81
+ export function createMUIThemeFromNova(novaTheme: NovaTheme): Theme {
82
+ const nova = novaTheme
83
+ const isDark = nova.mode === "dark"
84
+
85
+ return createTheme({
86
+ palette: {
87
+ mode: nova.mode,
88
+ primary: {
89
+ main: nova.colors.primary,
90
+ },
91
+ background: {
92
+ default: nova.colors.background.default,
93
+ paper: nova.colors.background.panel,
94
+ },
95
+ },
96
+ typography: {
97
+ allVariants: {
98
+ color: nova.colors.textDefault,
99
+ },
100
+ },
101
+ components: {
102
+ MuiSelect: {
103
+ styleOverrides: {
104
+ root: {
105
+ backgroundColor: isDark ? "#505968" : undefined,
106
+ borderRadius: "10px",
107
+ color: "currentColor",
108
+ "& > div": {
109
+ padding: "4px 16px",
110
+ },
111
+ "& fieldset": {
112
+ border: isDark ? "none" : undefined,
113
+ },
114
+ },
115
+ },
116
+ },
117
+ MuiChip: {
118
+ styleOverrides: {
119
+ root: {
120
+ backgroundColor: isDark ? "#505968" : undefined,
121
+ borderRadius: "10px",
122
+ color: "currentColor",
123
+ },
124
+ },
125
+ },
126
+ MuiToggleButtonGroup: {
127
+ styleOverrides: {
128
+ root: {
129
+ "& > button": {
130
+ borderRadius: "8px",
131
+ textTransform: "none",
132
+ paddingTop: "4px",
133
+ paddingBottom: "4px",
134
+ width: "100%",
135
+ borderWidth: 0,
136
+ backgroundColor: isDark ? "#3d4455" : undefined,
137
+ color: isDark ? "rgba(255, 255, 255, 0.8)" : undefined,
138
+
139
+ "&.Mui-selected": isDark
140
+ ? {
141
+ color: "white",
142
+ backgroundColor: "#505968",
143
+ }
144
+ : undefined,
145
+ },
146
+ },
147
+ },
148
+ },
149
+ MuiTabs: {
150
+ styleOverrides: {
151
+ root: {
152
+ backgroundColor: isDark ? "#101629" : undefined,
153
+ minHeight: "42px",
154
+ },
155
+ },
156
+ },
157
+ MuiTab: {
158
+ styleOverrides: {
159
+ root: {
160
+ minHeight: "42px",
161
+ textTransform: "none",
162
+ "&.Mui-selected": isDark
163
+ ? {
164
+ color: "white",
165
+ backgroundColor: "#404554",
166
+ }
167
+ : undefined,
168
+ },
169
+ },
170
+ },
171
+ },
172
+ nova,
173
+ })
174
+ }