@wandelbots/mui 0.0.0 → 1.0.1

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 (100) hide show
  1. package/README.md +131 -1
  2. package/dist/components/AdornedSelect/AdornedSelect.cjs +2 -0
  3. package/dist/components/AdornedSelect/AdornedSelect.d.ts +19 -0
  4. package/dist/components/AdornedSelect/AdornedSelect.d.ts.map +1 -0
  5. package/dist/components/AdornedSelect/AdornedSelect.js +85 -0
  6. package/dist/components/AdornedSelect/index.d.ts +2 -0
  7. package/dist/components/AdornedSelect/index.d.ts.map +1 -0
  8. package/dist/components/AdornedTextField/AdornedAutocomplete.cjs +2 -0
  9. package/dist/components/AdornedTextField/AdornedAutocomplete.d.ts +21 -0
  10. package/dist/components/AdornedTextField/AdornedAutocomplete.d.ts.map +1 -0
  11. package/dist/components/AdornedTextField/AdornedAutocomplete.js +47 -0
  12. package/dist/components/AdornedTextField/AdornedTextField.cjs +2 -0
  13. package/dist/components/AdornedTextField/AdornedTextField.d.ts +12 -0
  14. package/dist/components/AdornedTextField/AdornedTextField.d.ts.map +1 -0
  15. package/dist/components/AdornedTextField/AdornedTextField.js +158 -0
  16. package/dist/components/AdornedTextField/index.d.ts +3 -0
  17. package/dist/components/AdornedTextField/index.d.ts.map +1 -0
  18. package/dist/components/ElevationCard/ElevationCard.cjs +2 -0
  19. package/dist/components/ElevationCard/ElevationCard.d.ts +39 -0
  20. package/dist/components/ElevationCard/ElevationCard.d.ts.map +1 -0
  21. package/dist/components/ElevationCard/ElevationCard.js +43 -0
  22. package/dist/components/ElevationCard/index.d.ts +2 -0
  23. package/dist/components/ElevationCard/index.d.ts.map +1 -0
  24. package/dist/components/PrimaryButton/PrimaryButton.cjs +2 -0
  25. package/dist/components/PrimaryButton/PrimaryButton.d.ts +8 -0
  26. package/dist/components/PrimaryButton/PrimaryButton.d.ts.map +1 -0
  27. package/dist/components/PrimaryButton/PrimaryButton.js +18 -0
  28. package/dist/components/PrimaryButton/index.d.ts +2 -0
  29. package/dist/components/PrimaryButton/index.d.ts.map +1 -0
  30. package/dist/components/RoundedIconButton/RoundedIconButton.cjs +2 -0
  31. package/dist/components/RoundedIconButton/RoundedIconButton.d.ts +30 -0
  32. package/dist/components/RoundedIconButton/RoundedIconButton.d.ts.map +1 -0
  33. package/dist/components/RoundedIconButton/RoundedIconButton.js +45 -0
  34. package/dist/components/RoundedIconButton/index.d.ts +2 -0
  35. package/dist/components/RoundedIconButton/index.d.ts.map +1 -0
  36. package/dist/components/SecondaryButton/SecondaryButton.cjs +2 -0
  37. package/dist/components/SecondaryButton/SecondaryButton.d.ts +8 -0
  38. package/dist/components/SecondaryButton/SecondaryButton.d.ts.map +1 -0
  39. package/dist/components/SecondaryButton/SecondaryButton.js +26 -0
  40. package/dist/components/SecondaryButton/index.d.ts +2 -0
  41. package/dist/components/SecondaryButton/index.d.ts.map +1 -0
  42. package/dist/components/fields/FloatTextField.cjs +2 -0
  43. package/dist/components/fields/FloatTextField.d.ts +5 -0
  44. package/dist/components/fields/FloatTextField.d.ts.map +1 -0
  45. package/dist/components/fields/FloatTextField.js +17 -0
  46. package/dist/components/fields/IntegerTextField.cjs +2 -0
  47. package/dist/components/fields/IntegerTextField.d.ts +5 -0
  48. package/dist/components/fields/IntegerTextField.d.ts.map +1 -0
  49. package/dist/components/fields/IntegerTextField.js +17 -0
  50. package/dist/components/fields/IpAddressTextField.cjs +2 -0
  51. package/dist/components/fields/IpAddressTextField.d.ts +5 -0
  52. package/dist/components/fields/IpAddressTextField.d.ts.map +1 -0
  53. package/dist/components/fields/IpAddressTextField.js +17 -0
  54. package/dist/components/fields/ParsingTextField.cjs +2 -0
  55. package/dist/components/fields/ParsingTextField.d.ts +18 -0
  56. package/dist/components/fields/ParsingTextField.d.ts.map +1 -0
  57. package/dist/components/fields/ParsingTextField.js +35 -0
  58. package/dist/components/fields/PortTextField.cjs +2 -0
  59. package/dist/components/fields/PortTextField.d.ts +5 -0
  60. package/dist/components/fields/PortTextField.d.ts.map +1 -0
  61. package/dist/components/fields/PortTextField.js +17 -0
  62. package/dist/components/fields/StringValidationTextField.cjs +2 -0
  63. package/dist/components/fields/StringValidationTextField.d.ts +5 -0
  64. package/dist/components/fields/StringValidationTextField.d.ts.map +1 -0
  65. package/dist/components/fields/StringValidationTextField.js +9 -0
  66. package/dist/components/fields/index.d.ts +7 -0
  67. package/dist/components/fields/index.d.ts.map +1 -0
  68. package/dist/components/index.d.ts +8 -0
  69. package/dist/components/index.d.ts.map +1 -0
  70. package/dist/index.cjs +1 -0
  71. package/dist/index.d.ts +5 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +53 -0
  74. package/dist/theme/createNovaMuiTheme.cjs +2 -0
  75. package/dist/theme/createNovaMuiTheme.d.ts +144 -0
  76. package/dist/theme/createNovaMuiTheme.d.ts.map +1 -0
  77. package/dist/theme/createNovaMuiTheme.js +374 -0
  78. package/dist/theme/index.d.ts +3 -0
  79. package/dist/theme/index.d.ts.map +1 -0
  80. package/dist/validators/core.cjs +1 -0
  81. package/dist/validators/core.d.ts +7 -0
  82. package/dist/validators/core.d.ts.map +1 -0
  83. package/dist/validators/core.js +10 -0
  84. package/dist/validators/index.cjs +1 -0
  85. package/dist/validators/index.d.ts +5 -0
  86. package/dist/validators/index.d.ts.map +1 -0
  87. package/dist/validators/index.js +25 -0
  88. package/dist/validators/network.cjs +1 -0
  89. package/dist/validators/network.d.ts +21 -0
  90. package/dist/validators/network.d.ts.map +1 -0
  91. package/dist/validators/network.js +40 -0
  92. package/dist/validators/number.cjs +1 -0
  93. package/dist/validators/number.d.ts +13 -0
  94. package/dist/validators/number.d.ts.map +1 -0
  95. package/dist/validators/number.js +40 -0
  96. package/dist/validators/string.cjs +1 -0
  97. package/dist/validators/string.d.ts +7 -0
  98. package/dist/validators/string.d.ts.map +1 -0
  99. package/dist/validators/string.js +32 -0
  100. package/package.json +79 -3
package/README.md CHANGED
@@ -1,3 +1,133 @@
1
1
  # @wandelbots/mui
2
2
 
3
- Placeholder release to register the package name. Real releases start at 1.0.0, published automatically by semantic-release from https://github.com/wandelbotsgmbh/nova-design-system.
3
+ The **MUI layer** of the Wandelbots Nova design system: a thin, **visual-only** React
4
+ component library holding the Wandelbots company-CI **theme** and **small presentational
5
+ components** (inputs, selects, buttons, layout primitives, input parsers/validators). Visual
6
+ building blocks are defined **once** here and reused consistently across apps.
7
+
8
+ **This is the only package that ships a MUI theme.** `@wandelbots/design-tokens` stays
9
+ framework-agnostic (values only); the theme composes those values into MUI shape here.
10
+
11
+ **Non-goals:** no domain logic, no data fetching, no API/WebSocket code, no robot/motion
12
+ knowledge. Those live in `wandelbots-js-react-components` (separate repo).
13
+
14
+ - **Peers:** React 19, MUI 7, emotion 11. Depends on `@wandelbots/design-tokens` (`workspace:*`).
15
+ - **Dark mode only**
16
+ - Built with **Vite library mode** (ESM + CJS), TypeScript strict, Biome, Vitest + Storybook.
17
+
18
+ See [`AGENTS.md`](./AGENTS.md) for the working conventions, and the monorepo root
19
+ [`README.md`](../../README.md#roadmap) for the design-system roadmap.
20
+
21
+ ## Theme
22
+
23
+ **One function.** `createNovaMuiTheme(...overrides)` is the entire theme API — Nova palette,
24
+ `paletteExt`, elevation ramp, typography and component overrides in a single `Theme`. Dark by
25
+ default, since dark is the only mode in v1.
26
+
27
+ ```tsx
28
+ import { ThemeProvider } from "@mui/material/styles"
29
+ import { createNovaMuiTheme } from "@wandelbots/mui"
30
+
31
+ // Build it once, at module scope — a new Theme object on every render would
32
+ // defeat emotion's style caching.
33
+ const theme = createNovaMuiTheme()
34
+
35
+ function App() {
36
+ return <ThemeProvider theme={theme}>...</ThemeProvider>
37
+ }
38
+ ```
39
+
40
+ Nothing else is exported, deliberately: no pre-built theme constant (so importing the package
41
+ never eagerly builds a theme you didn't ask for), and no `darkBaseOptions()` /
42
+ `commonComponents()` building blocks (so the internal layering stays free to change). Customise
43
+ by passing `ThemeOptions`, or compose with MUI's own `createTheme` — and light mode will land
44
+ *inside* this factory rather than as a second export.
45
+
46
+ Importing the package also activates the type augmentation, so `theme.palette.tertiary.main`,
47
+ `theme.paletteExt.primary.hover`, and `theme.palette.backgroundPaperElevation[8]` are all typed.
48
+ Package-specific theme extensions (jogging-panel colors, DataGrid styling slots) belong in the
49
+ consuming package — add your own `declare module "@mui/material/styles"` there.
50
+
51
+ ### Overriding and extending
52
+
53
+ The factory is variadic and uses MUI's canonical `createTheme(base, ...overrides)` for
54
+ deep-merging. Pass any number of `ThemeOptions`; each layer merges on top of the previous one,
55
+ and the last one wins.
56
+
57
+ ```tsx
58
+ const theme = createNovaMuiTheme({
59
+ palette: { primary: { main: "#ff00ff" } },
60
+ components: {
61
+ MuiDialog: { styleOverrides: { paper: { borderRadius: 16 } } },
62
+ },
63
+ })
64
+ // theme.palette.primary.main → "#ff00ff"
65
+ // theme.paletteExt.primary.hover → preserved from base
66
+ // theme.components.MuiButton.* → preserved (deep-merge, not replace)
67
+ ```
68
+
69
+ ```tsx
70
+ // Multi-layer: app-wide plus feature-specific
71
+ const theme = createNovaMuiTheme(appOverrides, joggingPanelOverrides)
72
+
73
+ // Or layer on afterwards with MUI's own createTheme
74
+ import { createTheme } from "@mui/material/styles"
75
+
76
+ const theme = createTheme(createNovaMuiTheme(), myOverrides)
77
+ ```
78
+
79
+ > **How propagation works.** Nova's palette-dependent component overrides are MUI function-form
80
+ > callbacks — they aren't *called* when the theme is built, only stored as function references.
81
+ > MUI invokes them at component render time with the *final merged* theme from
82
+ > `<ThemeProvider>`, so the order in which you build the theme doesn't matter: an override like
83
+ > `createNovaMuiTheme({ palette: { text: { secondary: "#abcdef" } } })` still reaches `MuiTab`'s
84
+ > `color`. The one exception is `MuiCssBaseline.styleOverrides`, deliberately a static object so
85
+ > consumer global selectors deep-merge instead of replacing Nova's scrollbar rules.
86
+
87
+ ### Light mode
88
+
89
+ Not supported yet — `createNovaMuiTheme({ palette: { mode: "light" } })` throws. When the upstream
90
+ Figma sync ships light tokens, light mode will be added *inside* `createNovaMuiTheme` (via MUI 7's
91
+ `colorSchemes`), so existing call sites won't change and no new export appears.
92
+
93
+ ### Migrating from `@wandelbots/design-tokens/mui`
94
+
95
+ The theme moved out of the token package. The function keeps its name, so for most apps it's a
96
+ one-line import change:
97
+
98
+ ```diff
99
+ - import { createNovaMuiTheme } from "@wandelbots/design-tokens/mui"
100
+ + import { createNovaMuiTheme } from "@wandelbots/mui"
101
+ ```
102
+
103
+ **It is also a visual change**, though. `createNovaMuiTheme` now includes the NovaDeck-derived
104
+ styling the old token-package version lacked — `background.default: #161825`, `body2` at 14/400,
105
+ and `MuiAutocomplete` / `MuiSelect` root / `MuiTooltip` overrides. If your app was adding those
106
+ locally to compensate, drop them.
107
+
108
+ Two other things changed:
109
+
110
+ - **`createVisualTheme` is gone** — it was the layer that added exactly that styling. Everything
111
+ it did is now in `createNovaMuiTheme`, so replace the call one-for-one.
112
+ - **`darkTheme`, `darkBaseOptions()` and `commonComponents()` are gone.** Replace a `darkTheme`
113
+ import with a module-scope `const theme = createNovaMuiTheme()`. Anything built on the building
114
+ blocks should use `createNovaMuiTheme(...overrides)`, or `createTheme(createNovaMuiTheme(), ...)`
115
+ to layer on afterwards.
116
+
117
+ Keep `@wandelbots/design-tokens` installed for raw token values and CSS variables — it just no
118
+ longer carries a `/mui` entry.
119
+
120
+ ## Scripts
121
+
122
+ Run from the monorepo root with `pnpm --filter @wandelbots/mui <script>`.
123
+
124
+ | Script | Purpose |
125
+ |---|---|
126
+ | `pnpm build` | Vite library build + `.d.ts` emit → `dist/` |
127
+ | `pnpm dev` | Storybook dev server on :6006 |
128
+ | `pnpm typecheck` | `tsc --noEmit` over shippable source |
129
+ | `pnpm test` / `pnpm test:unit` | Vitest unit tests |
130
+ | `pnpm verify` | build + unit + Storybook interaction/smoke tests → `VERIFY: PASS` |
131
+ | `pnpm screenshot <storyId>` | Playwright screenshot of a story → `.screenshots/` |
132
+
133
+ Lint/format are repo-wide from the root: `pnpm lint`, `pnpm format` (Biome).
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("react/jsx-runtime"),y=require("@mui/material/FormControl"),m=require("@mui/material/InputLabel"),h=require("@mui/material/Select"),s=require("@mui/material/styles"),b=s.styled(h,{shouldForwardProp:e=>e!=="adornedSize"})(({theme:e,adornedSize:n="medium"})=>({"&.MuiInputBase-root":{background:e.palette.secondary.dark,borderRadius:`${e.shape.borderRadius}px`,".MuiSelect-select":{padding:n==="small"?"8px 16px":"16px 14px"},"&:hover .MuiOutlinedInput-notchedOutline":{border:`1px solid ${e.palette.action.hover}`},"&.Mui-focused .MuiOutlinedInput-notchedOutline":{border:`1px solid ${e.palette.primary.main}`},".MuiOutlinedInput-notchedOutline":{borderRadius:`${e.shape.borderRadius}px`,border:"1px solid transparent",legend:{width:0}}}})),S=s.styled(m)({transform:"translate(14px, 8px) scale(0.75)"}),g=({placeholder:e,disabled:n,value:t,label:r,labelId:p,adornedSize:o="medium",renderValue:l,...i})=>{const c=(t==null||t===""||Array.isArray(t)&&t.length===0)&&e,u=p??(r?`${String(r).replace(/\s+/g,"-")}-label`:void 0),x=s.useTheme();return d.jsxs(y,{fullWidth:!0,disabled:n,children:[r&&d.jsx(S,{id:u,shrink:!0,children:r}),d.jsx(b,{...i,adornedSize:o,disabled:n,labelId:u,value:t,displayEmpty:!0,sx:[r?{".MuiSelect-select":{paddingTop:o==="small"?"8px !important":"24px !important",paddingBottom:"8px !important"}}:{},...Array.isArray(i.sx)?i.sx:[i.sx]],renderValue:a=>c?d.jsx("span",{style:{color:x.palette.text.disabled,opacity:1,display:"block"},children:e}):l?l(a):a})]})};exports.AdornedSelect=g;
@@ -0,0 +1,19 @@
1
+ import type { SelectProps } from "@mui/material/Select";
2
+ export type AdornedSelectSize = "small" | "medium";
3
+ export type AdornedSelectProps = Omit<SelectProps, "theme"> & {
4
+ /** Shown (in `text.disabled`) while no value is selected. */
5
+ placeholder?: string;
6
+ adornedSize?: AdornedSelectSize;
7
+ /** Convenience: renders an always-shrunk `InputLabel` above the value. */
8
+ label?: string;
9
+ /** Explicit label id (RobotPad-compat); defaults to one derived from `label`. */
10
+ labelId?: string;
11
+ };
12
+ /**
13
+ * Select in the Wandelbots visual style: filled-looking background
14
+ * (`secondary.dark`), 10px radius, transparent border with hover/focus
15
+ * accents, always-shrunk label, placeholder support. Accepts all MUI
16
+ * `SelectProps`.
17
+ */
18
+ export declare const AdornedSelect: ({ placeholder, disabled, value, label, labelId: labelIdProp, adornedSize, renderValue: customRenderValue, ...props }: AdornedSelectProps) => import("react").JSX.Element;
19
+ //# sourceMappingURL=AdornedSelect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdornedSelect.d.ts","sourceRoot":"","sources":["../../../src/components/AdornedSelect/AdornedSelect.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAKvD,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,QAAQ,CAAA;AA2DlD,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,GAAG;IAC5D,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,sHAS3B,kBAAkB,gCAkEpB,CAAA"}
@@ -0,0 +1,85 @@
1
+ "use client";
2
+ import { jsxs as x, jsx as d } from "react/jsx-runtime";
3
+ import y from "@mui/material/FormControl";
4
+ import h from "@mui/material/InputLabel";
5
+ import b from "@mui/material/Select";
6
+ import { styled as a, useTheme as f } from "@mui/material/styles";
7
+ const g = a(b, {
8
+ shouldForwardProp: (t) => t !== "adornedSize"
9
+ })(
10
+ ({ theme: t, adornedSize: o = "medium" }) => ({
11
+ "&.MuiInputBase-root": {
12
+ background: t.palette.secondary.dark,
13
+ borderRadius: `${t.shape.borderRadius}px`,
14
+ // Default padding (no label); with a label the sx block below overrides
15
+ ".MuiSelect-select": {
16
+ padding: o === "small" ? "8px 16px" : "16px 14px"
17
+ },
18
+ "&:hover .MuiOutlinedInput-notchedOutline": {
19
+ border: `1px solid ${t.palette.action.hover}`
20
+ },
21
+ "&.Mui-focused .MuiOutlinedInput-notchedOutline": {
22
+ border: `1px solid ${t.palette.primary.main}`
23
+ },
24
+ ".MuiOutlinedInput-notchedOutline": {
25
+ borderRadius: `${t.shape.borderRadius}px`,
26
+ border: "1px solid transparent",
27
+ legend: {
28
+ width: 0
29
+ }
30
+ }
31
+ }
32
+ })
33
+ ), I = a(h)({
34
+ transform: "translate(14px, 8px) scale(0.75)"
35
+ }), w = ({
36
+ placeholder: t,
37
+ disabled: o,
38
+ value: r,
39
+ label: e,
40
+ labelId: u,
41
+ adornedSize: n = "medium",
42
+ renderValue: p,
43
+ ...i
44
+ }) => {
45
+ const c = (r == null || r === "" || Array.isArray(r) && r.length === 0) && t, s = u ?? (e ? `${String(e).replace(/\s+/g, "-")}-label` : void 0), m = f();
46
+ return /* @__PURE__ */ x(y, { fullWidth: !0, disabled: o, children: [
47
+ e && /* @__PURE__ */ d(I, { id: s, shrink: !0, children: e }),
48
+ /* @__PURE__ */ d(
49
+ g,
50
+ {
51
+ ...i,
52
+ adornedSize: n,
53
+ disabled: o,
54
+ labelId: s,
55
+ value: r,
56
+ displayEmpty: !0,
57
+ sx: [
58
+ // With a label, make room for it (needs !important to beat the
59
+ // styled() base padding, which carries higher specificity)
60
+ e ? {
61
+ ".MuiSelect-select": {
62
+ paddingTop: n === "small" ? "8px !important" : "24px !important",
63
+ paddingBottom: "8px !important"
64
+ }
65
+ } : {},
66
+ ...Array.isArray(i.sx) ? i.sx : [i.sx]
67
+ ],
68
+ renderValue: (l) => c ? /* @__PURE__ */ d(
69
+ "span",
70
+ {
71
+ style: {
72
+ color: m.palette.text.disabled,
73
+ opacity: 1,
74
+ display: "block"
75
+ },
76
+ children: t
77
+ }
78
+ ) : p ? p(l) : l
79
+ }
80
+ )
81
+ ] });
82
+ };
83
+ export {
84
+ w as AdornedSelect
85
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./AdornedSelect";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/AdornedSelect/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("react/jsx-runtime"),b=require("@mui/material/Autocomplete"),j=require("./AdornedTextField.cjs"),o=({label:t,placeholder:u,adornedSize:i="medium",error:r,helperText:c,slotProps:e,freeSolo:m,...A})=>d.jsx(b,{freeSolo:m??!0,...A,renderInput:({InputProps:n,InputLabelProps:x,...a})=>d.jsx(j.AdornedTextField,{...a,label:t,placeholder:u,adornedSize:i,error:r,helperText:c,slotProps:{...e,input:{...n,...e==null?void 0:e.input,endAdornment:n.endAdornment},inputLabel:{...x,...e==null?void 0:e.inputLabel}}})});exports.AdornedAutocomplete=o;
@@ -0,0 +1,21 @@
1
+ import type { AutocompleteProps } from "@mui/material/Autocomplete";
2
+ import type { ReactNode } from "react";
3
+ import type { AdornedTextFieldProps, AdornedTextFieldSize } from "./AdornedTextField";
4
+ export type AdornedAutocompleteProps<T = string, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = true> = Omit<AutocompleteProps<T, Multiple, DisableClearable, FreeSolo>, "renderInput" | "slotProps"> & {
5
+ label?: string;
6
+ placeholder?: string;
7
+ adornedSize?: AdornedTextFieldSize;
8
+ error?: boolean;
9
+ helperText?: ReactNode;
10
+ /** Forwarded to the underlying `AdornedTextField` (not the Autocomplete popper/listbox). */
11
+ slotProps?: AdornedTextFieldProps["slotProps"];
12
+ };
13
+ /**
14
+ * `Autocomplete` styled like `AdornedTextField` (outlined look,
15
+ * `secondary.dark` background, 10px radius). Accepts all MUI
16
+ * `AutocompleteProps` (minus `renderInput`) — `T`, `multiple`,
17
+ * `disableClearable` and `freeSolo` are all open; `freeSolo` defaults to
18
+ * `true` to match this component's original free-text behavior.
19
+ */
20
+ export declare const AdornedAutocomplete: <T = string, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = true>({ label, placeholder, adornedSize, error, helperText, slotProps, freeSolo, ...props }: AdornedAutocompleteProps<T, Multiple, DisableClearable, FreeSolo>) => import("react").JSX.Element;
21
+ //# sourceMappingURL=AdornedAutocomplete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdornedAutocomplete.d.ts","sourceRoot":"","sources":["../../../src/components/AdornedTextField/AdornedAutocomplete.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EACV,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,oBAAoB,CAAA;AAQ3B,MAAM,MAAM,wBAAwB,CAClC,CAAC,GAAG,MAAM,EACV,QAAQ,SAAS,OAAO,GAAG,SAAS,GAAG,KAAK,EAC5C,gBAAgB,SAAS,OAAO,GAAG,SAAS,GAAG,KAAK,EACpD,QAAQ,SAAS,OAAO,GAAG,SAAS,GAAG,IAAI,IACzC,IAAI,CACN,iBAAiB,CAAC,CAAC,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,CAAC,EAC1D,aAAa,GAAG,WAAW,CAC5B,GAAG;IACF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,oBAAoB,CAAA;IAClC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,SAAS,CAAA;IACtB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAA;CAC/C,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC9B,CAAC,GAAG,MAAM,EACV,QAAQ,SAAS,OAAO,GAAG,SAAS,GAAG,KAAK,EAC5C,gBAAgB,SAAS,OAAO,GAAG,SAAS,GAAG,KAAK,EACpD,QAAQ,SAAS,OAAO,GAAG,SAAS,GAAG,IAAI,EAC3C,uFASC,wBAAwB,CAAC,CAAC,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,CAAC,gCA8BnE,CAAA"}
@@ -0,0 +1,47 @@
1
+ "use client";
2
+ import { jsx as m } from "react/jsx-runtime";
3
+ import a from "@mui/material/Autocomplete";
4
+ import { AdornedTextField as b } from "./AdornedTextField.js";
5
+ const S = ({
6
+ label: d,
7
+ placeholder: i,
8
+ adornedSize: t = "medium",
9
+ error: u,
10
+ helperText: r,
11
+ slotProps: e,
12
+ freeSolo: A,
13
+ ...f
14
+ }) => /* @__PURE__ */ m(
15
+ a,
16
+ {
17
+ freeSolo: A ?? !0,
18
+ ...f,
19
+ renderInput: ({ InputProps: n, InputLabelProps: c, ...x }) => /* @__PURE__ */ m(
20
+ b,
21
+ {
22
+ ...x,
23
+ label: d,
24
+ placeholder: i,
25
+ adornedSize: t,
26
+ error: u,
27
+ helperText: r,
28
+ slotProps: {
29
+ ...e,
30
+ input: {
31
+ ...n,
32
+ ...e == null ? void 0 : e.input,
33
+ // Autocomplete's own popup/clear buttons live here — never let a
34
+ // caller-supplied slotProps.input silently replace them (MUI's
35
+ // TextField lets the new-style slotProps.input fully override the
36
+ // legacy InputProps it's built from when both are present).
37
+ endAdornment: n.endAdornment
38
+ },
39
+ inputLabel: { ...c, ...e == null ? void 0 : e.inputLabel }
40
+ }
41
+ }
42
+ )
43
+ }
44
+ );
45
+ export {
46
+ S as AdornedAutocomplete
47
+ };
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("react/jsx-runtime"),x=require("@mui/material/styles"),g=require("@mui/material/TextField"),m={small:{gutter:"12px",fontSize:"14px",lineHeight:"20px",padding:"11px 12px",paddingWithLabel:"18px 12px 4px",labelOffsetY:"3px",endAdornmentOffset:"7px"},medium:{gutter:"16px",fontSize:"14px",lineHeight:"20px",padding:"16px 16px",paddingWithLabel:"24px 16px 8px",labelOffsetY:"9px",endAdornmentOffset:"8px"}},f=x.styled(g,{shouldForwardProp:t=>t!=="adornedSize"})(({theme:t,adornedSize:n="medium"})=>{const{gutter:e,fontSize:o,lineHeight:a,padding:p,paddingWithLabel:u,labelOffsetY:i,endAdornmentOffset:s}=m[n],r="var(--wb-start-adornment-width, 20px)",d="8px";return{"&.MuiTextField-root":{".MuiInputBase-root":{background:t.palette.secondary.dark,borderRadius:`${t.shape.borderRadius}px`},".MuiInputBase-input":{"&::placeholder":{opacity:"1",color:t.palette.text.disabled}},".MuiInputAdornment-root .MuiTypography-root":{fontSize:o},".MuiInputBase-root .MuiInputBase-input":{padding:p,fontSize:o,lineHeight:a},".MuiFormLabel-root + .MuiInputBase-root .MuiInputBase-input":{padding:u},".MuiFormLabel-root + .MuiInputBase-root .MuiInputAdornment-positionEnd":{marginTop:s},".MuiInputBase-root.MuiAutocomplete-inputRoot":{paddingTop:0,paddingBottom:0,paddingLeft:0,".MuiInputBase-input":{transform:"none"}},".MuiInputBase-root.MuiInputBase-adornedStart":{paddingLeft:e,".MuiInputAdornment-positionStart":{width:r,marginTop:0,marginRight:d,justifyContent:"center"},".MuiInputBase-input":{paddingLeft:0}},".MuiFormLabel-root":{transform:`translate(${e}, ${i}) scale(0.75)`},"&:has(.MuiInputBase-adornedStart) .MuiFormLabel-root":{transform:`translate(calc(${e} + ${r} + ${d}), ${i}) scale(0.75)`},":hover":{fieldset:{border:`1px solid ${t.palette.action.hover}`}},".Mui-focused":{fieldset:{border:`1px solid ${t.palette.primary.main}`,legend:{width:0}}},fieldset:{borderRadius:`${t.shape.borderRadius}px`,border:"1px solid transparent",legend:{width:0}}}}}),M=({adornedSize:t="medium",...n})=>{var e;return l.jsx(f,{adornedSize:t,...n,slotProps:{...n.slotProps,inputLabel:{...(e=n.slotProps)==null?void 0:e.inputLabel,shrink:!0}}})};exports.AdornedTextField=M;
@@ -0,0 +1,12 @@
1
+ import type { TextFieldProps } from "@mui/material/TextField";
2
+ export type AdornedTextFieldSize = "small" | "medium";
3
+ export type AdornedTextFieldProps = TextFieldProps & {
4
+ adornedSize?: AdornedTextFieldSize;
5
+ };
6
+ /**
7
+ * TextField in the Wandelbots visual style: filled-looking background
8
+ * (`secondary.dark`), 10px radius, transparent border with hover/focus
9
+ * accents, always-shrunk label. Accepts all MUI `TextFieldProps`.
10
+ */
11
+ export declare const AdornedTextField: ({ adornedSize, ...props }: AdornedTextFieldProps) => import("react").JSX.Element;
12
+ //# sourceMappingURL=AdornedTextField.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdornedTextField.d.ts","sourceRoot":"","sources":["../../../src/components/AdornedTextField/AdornedTextField.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAG7D,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,QAAQ,CAAA;AA+JrD,MAAM,MAAM,qBAAqB,GAAG,cAAc,GAAG;IACnD,WAAW,CAAC,EAAE,oBAAoB,CAAA;CACnC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,2BAG9B,qBAAqB,gCAcvB,CAAA"}
@@ -0,0 +1,158 @@
1
+ "use client";
2
+ import { jsx as l } from "react/jsx-runtime";
3
+ import { styled as x } from "@mui/material/styles";
4
+ import m from "@mui/material/TextField";
5
+ const f = {
6
+ small: {
7
+ gutter: "12px",
8
+ fontSize: "14px",
9
+ lineHeight: "20px",
10
+ padding: "11px 12px",
11
+ paddingWithLabel: "18px 12px 4px",
12
+ labelOffsetY: "3px",
13
+ endAdornmentOffset: "7px"
14
+ },
15
+ medium: {
16
+ gutter: "16px",
17
+ fontSize: "14px",
18
+ lineHeight: "20px",
19
+ padding: "16px 16px",
20
+ paddingWithLabel: "24px 16px 8px",
21
+ labelOffsetY: "9px",
22
+ endAdornmentOffset: "8px"
23
+ }
24
+ }, g = x(m, {
25
+ shouldForwardProp: (t) => t !== "adornedSize"
26
+ })(({ theme: t, adornedSize: o = "medium" }) => {
27
+ const {
28
+ gutter: e,
29
+ fontSize: n,
30
+ lineHeight: d,
31
+ padding: p,
32
+ paddingWithLabel: u,
33
+ labelOffsetY: i,
34
+ endAdornmentOffset: s
35
+ } = f[o], r = "var(--wb-start-adornment-width, 20px)", a = "8px";
36
+ return {
37
+ "&.MuiTextField-root": {
38
+ ".MuiInputBase-root": {
39
+ background: t.palette.secondary.dark,
40
+ borderRadius: `${t.shape.borderRadius}px`
41
+ },
42
+ ".MuiInputBase-input": {
43
+ "&::placeholder": {
44
+ opacity: "1",
45
+ color: t.palette.text.disabled
46
+ }
47
+ },
48
+ // A text adornment (e.g. a unit like "mm/s") shares the value's row, so it
49
+ // shares its type scale — MUI would otherwise render it at body1.
50
+ ".MuiInputAdornment-root .MuiTypography-root": {
51
+ fontSize: n
52
+ },
53
+ // Input without label (default case). The type scale lives here rather
54
+ // than on `.MuiInputBase-input` so it outranks MUI's own `font: inherit`.
55
+ ".MuiInputBase-root .MuiInputBase-input": {
56
+ padding: p,
57
+ fontSize: n,
58
+ lineHeight: d
59
+ },
60
+ // Input with label - using a more specific selector to override
61
+ ".MuiFormLabel-root + .MuiInputBase-root .MuiInputBase-input": {
62
+ padding: u
63
+ },
64
+ // The label-present padding above is asymmetric (extra top padding
65
+ // reserves room for the label), which pushes the input text down — an end
66
+ // adornment centered on the whole field would sit visibly above it. Nudge
67
+ // it down by half that asymmetry so it lines up with the text.
68
+ ".MuiFormLabel-root + .MuiInputBase-root .MuiInputAdornment-positionEnd": {
69
+ marginTop: s
70
+ },
71
+ // MUI's Autocomplete pads its own input row by 9px, which would stack with
72
+ // the input padding above and push the field past the spec height and
73
+ // gutter. The right pad is left alone — that is where MUI reserves room
74
+ // for the clear/popup buttons.
75
+ ".MuiInputBase-root.MuiAutocomplete-inputRoot": {
76
+ paddingTop: 0,
77
+ paddingBottom: 0,
78
+ paddingLeft: 0,
79
+ // The theme's MuiAutocomplete override (ported from NovaDeck) nudges the
80
+ // value down 6px to sit inside *its* geometry. This component owns its
81
+ // own vertical rhythm, so drop the nudge — otherwise the value lands 6px
82
+ // below the spec and, at small, touches the bottom edge.
83
+ ".MuiInputBase-input": {
84
+ transform: "none"
85
+ }
86
+ },
87
+ // A start adornment is its own full-height column: icon centered on the
88
+ // whole field with the label/value stack to the right of it. The label is
89
+ // an absolutely-positioned sibling of the input, so CSS can't measure the
90
+ // adornment in order to clear it — instead the adornment is pinned to a
91
+ // fixed-width slot and both the label and the input start after that same
92
+ // slot. Override --wb-start-adornment-width for wider adornments.
93
+ ".MuiInputBase-root.MuiInputBase-adornedStart": {
94
+ paddingLeft: e,
95
+ ".MuiInputAdornment-positionStart": {
96
+ width: r,
97
+ marginTop: 0,
98
+ marginRight: a,
99
+ justifyContent: "center"
100
+ },
101
+ ".MuiInputBase-input": {
102
+ paddingLeft: 0
103
+ }
104
+ },
105
+ // Selected by class rather than element so these outrank the theme's
106
+ // MuiAutocomplete override, which hardcodes its own label transform for
107
+ // the focused and has-clear-icon states.
108
+ ".MuiFormLabel-root": {
109
+ transform: `translate(${e}, ${i}) scale(0.75)`
110
+ },
111
+ "&:has(.MuiInputBase-adornedStart) .MuiFormLabel-root": {
112
+ transform: `translate(calc(${e} + ${r} + ${a}), ${i}) scale(0.75)`
113
+ },
114
+ ":hover": {
115
+ fieldset: {
116
+ border: `1px solid ${t.palette.action.hover}`
117
+ }
118
+ },
119
+ ".Mui-focused": {
120
+ fieldset: {
121
+ border: `1px solid ${t.palette.primary.main}`,
122
+ legend: {
123
+ width: 0
124
+ }
125
+ }
126
+ },
127
+ fieldset: {
128
+ borderRadius: `${t.shape.borderRadius}px`,
129
+ border: "1px solid transparent",
130
+ legend: {
131
+ width: 0
132
+ }
133
+ }
134
+ }
135
+ };
136
+ }), h = ({
137
+ adornedSize: t = "medium",
138
+ ...o
139
+ }) => {
140
+ var e;
141
+ return /* @__PURE__ */ l(
142
+ g,
143
+ {
144
+ adornedSize: t,
145
+ ...o,
146
+ slotProps: {
147
+ ...o.slotProps,
148
+ inputLabel: {
149
+ ...(e = o.slotProps) == null ? void 0 : e.inputLabel,
150
+ shrink: !0
151
+ }
152
+ }
153
+ }
154
+ );
155
+ };
156
+ export {
157
+ h as AdornedTextField
158
+ };
@@ -0,0 +1,3 @@
1
+ export { AdornedTextField, type AdornedTextFieldProps, type AdornedTextFieldSize, } from "./AdornedTextField";
2
+ export { AdornedAutocomplete, type AdornedAutocompleteProps, } from "./AdornedAutocomplete";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/AdornedTextField/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,mBAAmB,EACnB,KAAK,wBAAwB,GAC9B,MAAM,uBAAuB,CAAA"}
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("react/jsx-runtime"),c=require("@mui/material/Box"),b={surface:5,raised:8};function p({elevation:d="surface",bordered:i=!0,children:o,sx:r,"data-testid":s,component:t,ref:n}){const u=b[d];return l.jsx(c,{ref:n,...t?{component:t}:{},"data-testid":s,sx:[{borderRadius:e=>`${e.shape.borderRadius}px`,backgroundColor:e=>{var a;return(a=e.palette.backgroundPaperElevation)==null?void 0:a[u]},...i&&{border:e=>`1px solid ${e.palette.divider}`}},...Array.isArray(r)?r:[r]],children:o})}exports.ElevationCard=p;
@@ -0,0 +1,39 @@
1
+ import type { SxProps, Theme } from "@mui/material/styles";
2
+ import type { ElementType, ReactNode, Ref } from "react";
3
+ /**
4
+ * Semantic elevation levels for cards.
5
+ *
6
+ * These map to `theme.palette.backgroundPaperElevation` indices
7
+ * and correspond to specific Figma surface colors:
8
+ *
9
+ * - **surface** (5) → #202233 – outer/panel cards (sidebar, content area)
10
+ * - **raised** (8) → #292b3f – inner/content cards (robot cards, list items)
11
+ */
12
+ export type ElevationLevel = "surface" | "raised";
13
+ export interface ElevationCardProps {
14
+ /** Semantic elevation – determines the background shade. */
15
+ elevation?: ElevationLevel;
16
+ /** Show a subtle border (default: true). */
17
+ bordered?: boolean;
18
+ children?: ReactNode;
19
+ sx?: SxProps<Theme>;
20
+ /** Optional test ID for e2e selectors. */
21
+ "data-testid"?: string;
22
+ /** Root element/component, e.g. "li" for list semantics (default: "div"). */
23
+ component?: ElementType;
24
+ ref?: Ref<HTMLElement>;
25
+ }
26
+ /**
27
+ * A reusable card primitive
28
+ *
29
+ * Usage:
30
+ * ```tsx
31
+ * <ElevationCard elevation="surface"> // outer panel card
32
+ * <ElevationCard elevation="raised"> // inner content card
33
+ * …
34
+ * </ElevationCard>
35
+ * </ElevationCard>
36
+ * ```
37
+ */
38
+ export declare function ElevationCard({ elevation, bordered, children, sx, "data-testid": dataTestId, component, ref, }: ElevationCardProps): import("react").JSX.Element;
39
+ //# sourceMappingURL=ElevationCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ElevationCard.d.ts","sourceRoot":"","sources":["../../../src/components/ElevationCard/ElevationCard.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAExD;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,QAAQ,CAAA;AAOjD,MAAM,WAAW,kBAAkB;IACjC,4DAA4D;IAC5D,SAAS,CAAC,EAAE,cAAc,CAAA;IAC1B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,EAAE,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;IACnB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,WAAW,CAAA;IACvB,GAAG,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAA;CACvB;AAWD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAC5B,SAAqB,EACrB,QAAe,EACf,QAAQ,EACR,EAAE,EACF,aAAa,EAAE,UAAU,EACzB,SAAS,EACT,GAAG,GACJ,EAAE,kBAAkB,+BAuBpB"}
@@ -0,0 +1,43 @@
1
+ "use client";
2
+ import { jsx as u } from "react/jsx-runtime";
3
+ import l from "@mui/material/Box";
4
+ const c = {
5
+ surface: 5,
6
+ raised: 8
7
+ };
8
+ function f({
9
+ elevation: d = "surface",
10
+ bordered: o = !0,
11
+ children: i,
12
+ sx: a,
13
+ "data-testid": s,
14
+ component: e,
15
+ ref: n
16
+ }) {
17
+ const p = c[d];
18
+ return /* @__PURE__ */ u(
19
+ l,
20
+ {
21
+ ref: n,
22
+ ...e ? { component: e } : {},
23
+ "data-testid": s,
24
+ sx: [
25
+ {
26
+ borderRadius: (r) => `${r.shape.borderRadius}px`,
27
+ backgroundColor: (r) => {
28
+ var t;
29
+ return (t = r.palette.backgroundPaperElevation) == null ? void 0 : t[p];
30
+ },
31
+ ...o && {
32
+ border: (r) => `1px solid ${r.palette.divider}`
33
+ }
34
+ },
35
+ ...Array.isArray(a) ? a : [a]
36
+ ],
37
+ children: i
38
+ }
39
+ );
40
+ }
41
+ export {
42
+ f as ElevationCard
43
+ };
@@ -0,0 +1,2 @@
1
+ export { ElevationCard, type ElevationCardProps, type ElevationLevel, } from "./ElevationCard";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ElevationCard/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,cAAc,GACpB,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react/jsx-runtime"),o=require("@mui/material/Button"),e=require("@mui/material/styles"),a=e.styled(o)(({theme:r})=>({backgroundColor:r.palette.primary.main,color:r.palette.primary.contrastText,borderRadius:`${r.shape.borderRadius}px`,"&:hover":{backgroundColor:r.palette.primary.dark}}));function n(r){return t.jsx(a,{variant:"contained",...r})}exports.PrimaryButton=n;
@@ -0,0 +1,8 @@
1
+ import type { ButtonProps } from "@mui/material/Button";
2
+ export type PrimaryButtonProps = ButtonProps;
3
+ /**
4
+ * Contained button in the Wandelbots primary (violet) style.
5
+ * Accepts all MUI `ButtonProps`; `variant` defaults to "contained".
6
+ */
7
+ export declare function PrimaryButton(props: PrimaryButtonProps): import("react").JSX.Element;
8
+ //# sourceMappingURL=PrimaryButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrimaryButton.d.ts","sourceRoot":"","sources":["../../../src/components/PrimaryButton/PrimaryButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAsBvD,MAAM,MAAM,kBAAkB,GAAG,WAAW,CAAA;AAE5C;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,+BAEtD"}