@12-apps/ui 1.23.0 → 2.1.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 (82) hide show
  1. package/package.json +3 -1
  2. package/src/components/data-display/Alert/Alert.types.ts +2 -1
  3. package/src/components/data-display/Avatar/Avatar.types.ts +10 -2
  4. package/src/components/data-display/Badge/Badge.types.ts +3 -2
  5. package/src/components/data-display/Carousel/Carousel.parts.tsx +12 -10
  6. package/src/components/data-display/Carousel/Carousel.styles.ts +4 -3
  7. package/src/components/data-display/Carousel/Carousel.tsx +2 -1
  8. package/src/components/data-display/Carousel/Carousel.types.ts +7 -6
  9. package/src/components/data-display/Chart/Chart.tsx +2 -1
  10. package/src/components/data-display/Chart/Chart.types.ts +3 -2
  11. package/src/components/data-display/Chart/ChartSpec.types.ts +6 -7
  12. package/src/components/data-display/Chart/SpecChart.tsx +2 -1
  13. package/src/components/data-display/Chart/chart-internals.ts +3 -2
  14. package/src/components/data-display/Chart/chart-spec.ts +11 -1
  15. package/src/components/data-display/Chip/Chip.tsx +23 -3
  16. package/src/components/data-display/Chip/Chip.types.ts +37 -3
  17. package/src/components/data-display/Chip/chip.md +7 -3
  18. package/src/components/data-display/Chip/index.ts +1 -1
  19. package/src/components/data-display/DataViews/DataViewsGrid.tsx +10 -0
  20. package/src/components/data-display/DataViews/DataViewsTableBase.tsx +3 -0
  21. package/src/components/data-display/DataViews/data-views-grid-bodies.tsx +113 -62
  22. package/src/components/data-display/DataViews/data-views-grid-parts.tsx +4 -0
  23. package/src/components/data-display/DataViews/data-views-overflow.ts +23 -51
  24. package/src/components/data-display/DataViews/index.ts +4 -0
  25. package/src/components/data-display/DataViews/list-card-rails.tsx +29 -0
  26. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +8 -5
  27. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.types.ts +2 -1
  28. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.types.ts +2 -1
  29. package/src/components/data-display/LoadingState/LoadingState.types.ts +2 -1
  30. package/src/components/data-display/Progress/Progress.types.ts +3 -2
  31. package/src/components/data-display/Sheet/Sheet.body.tsx +2 -1
  32. package/src/components/data-display/Sheet/Sheet.styles.ts +3 -2
  33. package/src/components/data-display/Sheet/Sheet.types.ts +7 -2
  34. package/src/components/data-display/Stepper/Stepper.types.ts +2 -1
  35. package/src/components/data-display/Table/Table.styles.ts +1 -1
  36. package/src/components/data-display/Table/Table.types.ts +3 -1
  37. package/src/components/data-display/Tooltip/Tooltip.types.ts +2 -1
  38. package/src/components/feedback/Dialog/Dialog.types.ts +2 -1
  39. package/src/components/feedback/Modal/Modal.types.ts +2 -1
  40. package/src/components/form/Button/Button.types.ts +3 -2
  41. package/src/components/form/Calendar/CalendarMonth.tsx +6 -1
  42. package/src/components/form/Command/Command.styles.ts +8 -7
  43. package/src/components/form/Command/Command.types.ts +3 -2
  44. package/src/components/form/CreatableSelect/CreatableSelect.types.ts +2 -1
  45. package/src/components/form/Input/Input.types.ts +2 -1
  46. package/src/components/form/InputOTP/InputOTP.types.ts +3 -2
  47. package/src/components/form/Label/Label.styles.ts +8 -5
  48. package/src/components/form/Label/Label.tsx +1 -1
  49. package/src/components/form/Label/Label.types.ts +3 -2
  50. package/src/components/form/Menubar/Menubar.styles.ts +10 -8
  51. package/src/components/form/Menubar/Menubar.tsx +2 -1
  52. package/src/components/form/Menubar/Menubar.types.ts +7 -6
  53. package/src/components/form/RadioGroup/RadioGroup.types.ts +3 -2
  54. package/src/components/form/Select/Select.tsx +13 -1
  55. package/src/components/form/Select/Select.types.ts +5 -2
  56. package/src/components/form/Slider/Slider.types.ts +3 -2
  57. package/src/components/form/Switch/Switch.types.ts +3 -2
  58. package/src/components/form/Textarea/Textarea.types.ts +3 -2
  59. package/src/components/form/Toggle/Toggle.types.ts +3 -2
  60. package/src/components/form/ToggleGroup/ToggleGroup.types.ts +3 -2
  61. package/src/components/layout/Separator/Separator.types.ts +2 -1
  62. package/src/components/layout/Spacer/Spacer.types.ts +2 -1
  63. package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +1 -1
  64. package/src/components/navigation/Breadcrumbs/Breadcrumbs.types.ts +7 -2
  65. package/src/components/navigation/ContextMenu/ContextMenu.types.ts +3 -2
  66. package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +1 -0
  67. package/src/components/navigation/DropdownMenu/DropdownMenu.types.ts +12 -2
  68. package/src/components/navigation/NavigationMenu/NavigationMenu.types.ts +7 -2
  69. package/src/components/navigation/Pagination/Pagination.tsx +3 -1
  70. package/src/components/navigation/Pagination/Pagination.types.ts +5 -3
  71. package/src/components/navigation/Tabs/Tabs.types.ts +3 -2
  72. package/src/components/typography/Blockquote/Blockquote.types.ts +2 -1
  73. package/src/components/typography/Code/Code.types.ts +2 -1
  74. package/src/components/typography/Heading/Heading.types.ts +2 -1
  75. package/src/components/typography/Paragraph/Paragraph.types.ts +3 -2
  76. package/src/components/typography/Text/Text.types.ts +3 -2
  77. package/src/components/utility/AnimatedIcon/AnimatedIcon.types.ts +2 -1
  78. package/src/components/utility/Overflow/index.ts +6 -0
  79. package/src/components/utility/Overflow/overflow.ts +125 -0
  80. package/src/components/utility/WorkflowStep/WorkflowStep.types.ts +3 -2
  81. package/src/components/utility/index.ts +1 -0
  82. package/src/tokens/scales.ts +153 -0
@@ -1,8 +1,9 @@
1
+ import type { SizeValue } from '../../../tokens/scales';
1
2
  import type { DialogProps as MuiDialogProps } from '@mui/material';
2
3
  import type { ReactNode } from 'react';
3
4
 
4
5
  export type DialogVariant = 'default' | 'glass' | 'fullscreen' | 'drawer';
5
- export type DialogSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
6
+ export type DialogSize = SizeValue;
6
7
 
7
8
  export interface DialogProps extends Omit<MuiDialogProps, 'variant' | 'title'> {
8
9
  children: ReactNode;
@@ -1,8 +1,9 @@
1
+ import type { SizeValue } from '../../../tokens/scales';
1
2
  import type { ModalProps as MuiModalProps } from '@mui/material';
2
3
  import type { ReactNode } from 'react';
3
4
 
4
5
  export type ModalVariant = 'center' | 'top' | 'bottom' | 'glass';
5
- export type ModalSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
6
+ export type ModalSize = SizeValue;
6
7
 
7
8
  export interface ModalProps extends Omit<MuiModalProps, 'children'> {
8
9
  children: ReactNode;
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { ButtonProps as MuiButtonProps } from '@mui/material';
2
3
  import type * as React from 'react';
3
4
 
@@ -10,12 +11,12 @@ export interface ButtonProps extends Omit<MuiButtonProps, 'variant' | 'color' |
10
11
  /**
11
12
  * The color of the button
12
13
  */
13
- color?: 'primary' | 'secondary' | 'success' | 'warning' | 'info' | 'danger' | 'neutral';
14
+ color?: ColorValue;
14
15
 
15
16
  /**
16
17
  * The size of the button
17
18
  */
18
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
19
+ size?: SizeValue;
19
20
 
20
21
  /**
21
22
  * Whether the button is in loading state
@@ -102,7 +102,12 @@ export const CalendarMonth: FC<CalendarMonthProps> = ({
102
102
  const title = renderHeader ? renderHeader({ month: matrix.month, year: matrix.year }) : monthName;
103
103
 
104
104
  return (
105
- <Box sx={{ minWidth: 280 }}>
105
+ /* The month is addressable by its position, because in a multi-month
106
+ calendar every day number appears once PER MONTH — `calendar-date-5` is
107
+ January's 5th and February's. Without a per-month hook a test can only
108
+ reach a day positionally, which is exactly what the flakiness gate
109
+ refuses. Additive: `calendar-grid` below is unchanged. */
110
+ <Box sx={{ minWidth: 280 }} data-testid={`calendar-month-${monthIndex}`}>
106
111
  <MonthNavHeader
107
112
  title={title}
108
113
  showPrevious={monthIndex === 0}
@@ -2,6 +2,7 @@ import { alpha } from '@mui/material';
2
2
  import type { CSSObject, Theme } from '@mui/material';
3
3
 
4
4
  import type { CommandProps } from './Command.types';
5
+ import { accentFor } from '../../../tokens/scales';
5
6
 
6
7
  type CommandVariant = NonNullable<CommandProps['variant']>;
7
8
  type CommandColor = NonNullable<CommandProps['color']>;
@@ -24,14 +25,14 @@ const emphasisStyles = (
24
25
  pulse: boolean,
25
26
  ): CSSObject => ({
26
27
  ...(glow && {
27
- boxShadow: `0 0 20px ${alpha(theme.palette[color].main, 0.4)}`,
28
+ boxShadow: `0 0 20px ${alpha(accentFor(theme, color).main, 0.4)}`,
28
29
  }),
29
30
  ...(pulse && {
30
31
  animation: 'pulse 2s infinite',
31
32
  '@keyframes pulse': {
32
- '0%': { boxShadow: `0 0 0 0 ${alpha(theme.palette[color].main, 0.4)}` },
33
- '70%': { boxShadow: `0 0 0 10px ${alpha(theme.palette[color].main, 0)}` },
34
- '100%': { boxShadow: `0 0 0 0 ${alpha(theme.palette[color].main, 0)}` },
33
+ '0%': { boxShadow: `0 0 0 0 ${alpha(accentFor(theme, color).main, 0.4)}` },
34
+ '70%': { boxShadow: `0 0 0 10px ${alpha(accentFor(theme, color).main, 0)}` },
35
+ '100%': { boxShadow: `0 0 0 0 ${alpha(accentFor(theme, color).main, 0)}` },
35
36
  },
36
37
  }),
37
38
  });
@@ -46,12 +47,12 @@ const surfaceStyles = (
46
47
  return {
47
48
  backgroundColor: alpha(theme.palette.background.paper, 0.1),
48
49
  backdropFilter: 'blur(20px)',
49
- border: `1px solid ${alpha(theme.palette[color].main, 0.2)}`,
50
+ border: `1px solid ${alpha(accentFor(theme, color).main, 0.2)}`,
50
51
  };
51
52
  case 'gradient':
52
53
  return {
53
- background: `linear-gradient(135deg, ${theme.palette[color].main}, ${theme.palette[color].dark})`,
54
- color: theme.palette[color].contrastText,
54
+ background: `linear-gradient(135deg, ${accentFor(theme, color).main}, ${accentFor(theme, color).dark})`,
55
+ color: accentFor(theme, color).contrastText,
55
56
  };
56
57
  case 'elevated':
57
58
  return { boxShadow: theme.shadows[8] };
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { CSSProperties,ReactNode } from 'react';
2
3
 
3
4
  export interface CommandItem {
@@ -21,8 +22,8 @@ export interface CommandProps {
21
22
  onValueChange?: (value: string) => void;
22
23
  onSelect?: (item: CommandItem) => void;
23
24
  variant?: 'default' | 'glass' | 'gradient' | 'minimal' | 'elevated';
24
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
25
- color?: 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'info';
25
+ size?: SizeValue;
26
+ color?: Exclude<ColorValue, 'neutral'>;
26
27
  glow?: boolean;
27
28
  pulse?: boolean;
28
29
  loading?: boolean;
@@ -1,3 +1,4 @@
1
+ import type { SizeValue } from '../../../tokens/scales';
1
2
  /** One selectable option: a stable `value` and its human `label`. */
2
3
  export interface CreatableSelectOption {
3
4
  value: string;
@@ -44,7 +45,7 @@ export interface CreatableSelectProps {
44
45
  * Control height, matching {@link Input}'s scale so the two line up when they
45
46
  * share a grid row (default: `md`).
46
47
  */
47
- size?: 'sm' | 'md';
48
+ size?: Extract<SizeValue, 'sm' | 'md'>;
48
49
  /** Base test id; the input is `<dataTestId>-input`. */
49
50
  dataTestId?: string;
50
51
  }
@@ -1,9 +1,10 @@
1
+ import type { SizeValue } from '../../../tokens/scales';
1
2
  import type { InputLabelProps as MuiInputLabelProps } from '@mui/material';
2
3
  import type { InputHTMLAttributes, ReactNode } from 'react';
3
4
  import type React from 'react';
4
5
 
5
6
  export type InputVariant = 'outlined' | 'filled' | 'glass' | 'underline' | 'gradient';
6
- export type InputSize = 'sm' | 'md' | 'lg';
7
+ export type InputSize = Extract<SizeValue, 'sm' | 'md' | 'lg'>;
7
8
 
8
9
  export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'color'> {
9
10
  variant?: InputVariant;
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
 
2
3
  export interface InputOTPProps {
3
4
  /**
@@ -8,12 +9,12 @@ export interface InputOTPProps {
8
9
  /**
9
10
  * The color theme of the OTP input
10
11
  */
11
- color?: 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'neutral';
12
+ color?: Exclude<ColorValue, 'info'>;
12
13
 
13
14
  /**
14
15
  * The size of the OTP input
15
16
  */
16
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
17
+ size?: SizeValue;
17
18
 
18
19
  /**
19
20
  * Number of OTP digits
@@ -2,6 +2,7 @@ import { alpha } from '@mui/material';
2
2
  import type { CSSObject, Theme } from '@mui/material';
3
3
 
4
4
  import type { LabelProps } from './Label.types';
5
+ import { accentFor} from '../../../tokens/scales';
5
6
 
6
7
  type Size = NonNullable<LabelProps['size']>;
7
8
  type Variant = NonNullable<LabelProps['variant']>;
@@ -53,8 +54,8 @@ export interface LabelStyleFlags {
53
54
  export const textColor = (theme: Theme, flags: LabelStyleFlags): string => {
54
55
  if (flags.error) return theme.palette.error.main;
55
56
  if (flags.disabled) return theme.palette.text.disabled;
56
- if (flags.color === 'default') return theme.palette.text.primary;
57
- return theme.palette[flags.color].main;
57
+ if (flags.color === 'neutral') return theme.palette.text.primary;
58
+ return accentFor(theme, flags.color).main;
58
59
  };
59
60
 
60
61
  /** The ripple that expands from the centre on press, for clickable labels. */
@@ -119,7 +120,9 @@ const SURFACES: Record<Variant, (input: SurfaceInput) => CSSObject> = {
119
120
  }),
120
121
 
121
122
  gradient: ({ theme, flags }) => {
122
- const key = flags.color === 'default' ? 'primary' : flags.color;
123
+ // `neutral` has no accent of its own in the gradient; it borrows primary,
124
+ // which is what this branch already did before the vocabulary was named.
125
+ const accent = accentFor(theme, flags.color === 'neutral' ? 'primary' : flags.color);
123
126
  // The gradient paints the glyphs themselves rather than the box behind them.
124
127
  const clip = {
125
128
  WebkitBackgroundClip: 'text',
@@ -128,11 +131,11 @@ const SURFACES: Record<Variant, (input: SurfaceInput) => CSSObject> = {
128
131
  };
129
132
 
130
133
  return {
131
- background: `linear-gradient(135deg, ${theme.palette[key].light}, ${theme.palette[key].main})`,
134
+ background: `linear-gradient(135deg, ${accent.light}, ${accent.main})`,
132
135
  ...clip,
133
136
  '&:hover': flags.clickable
134
137
  ? {
135
- background: `linear-gradient(135deg, ${theme.palette[key].main}, ${theme.palette[key].dark})`,
138
+ background: `linear-gradient(135deg, ${accent.main}, ${accent.dark})`,
136
139
  ...clip,
137
140
  }
138
141
  : {},
@@ -14,7 +14,7 @@ const DEFAULTS = {
14
14
  error: false,
15
15
  variant: 'default',
16
16
  size: 'md',
17
- color: 'default',
17
+ color: 'neutral',
18
18
  glow: false,
19
19
  pulse: false,
20
20
  ripple: false,
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { CSSProperties, HTMLAttributes,ReactNode } from 'react';
2
3
 
3
4
  export interface LabelProps extends HTMLAttributes<globalThis.HTMLLabelElement> {
@@ -7,8 +8,8 @@ export interface LabelProps extends HTMLAttributes<globalThis.HTMLLabelElement>
7
8
  disabled?: boolean;
8
9
  error?: boolean;
9
10
  variant?: 'default' | 'filled' | 'outlined' | 'glass' | 'gradient' | 'minimal';
10
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
11
- color?: 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'info' | 'default';
11
+ size?: SizeValue;
12
+ color?: ColorValue;
12
13
  glow?: boolean;
13
14
  pulse?: boolean;
14
15
  glass?: boolean;
@@ -2,6 +2,7 @@ import { alpha } from '@mui/material';
2
2
  import type { CSSObject, Theme } from '@mui/material';
3
3
 
4
4
  import type { MenubarProps } from './Menubar.types';
5
+ import { accentFor} from '../../../tokens/scales';
5
6
 
6
7
  type Size = NonNullable<MenubarProps['size']>;
7
8
  type Variant = NonNullable<MenubarProps['variant']>;
@@ -20,13 +21,13 @@ export const sizeStyles = (theme: Theme, size: Size): CSSObject =>
20
21
 
21
22
  /** `default` is not a palette entry — it means the paper surface and its text. */
22
23
  const accentOf = (theme: Theme, color: Color) =>
23
- color === 'default' ? theme.palette.primary.main : theme.palette[color].main;
24
+ color === 'neutral' ? theme.palette.primary.main : accentFor(theme, color).main;
24
25
 
25
26
  const colorStyles = (theme: Theme, color: Color, transparent: boolean): CSSObject => {
26
27
  const surface =
27
- color === 'default'
28
+ color === 'neutral'
28
29
  ? { backgroundColor: theme.palette.background.paper, color: theme.palette.text.primary }
29
- : { backgroundColor: theme.palette[color].main, color: theme.palette[color].contrastText };
30
+ : { backgroundColor: accentFor(theme, color).main, color: accentFor(theme, color).contrastText };
30
31
 
31
32
  return transparent ? { ...surface, backgroundColor: 'transparent' } : surface;
32
33
  };
@@ -57,12 +58,13 @@ const SURFACES: Record<Variant, (theme: Theme, flags: MenubarStyleFlags) => CSSO
57
58
  }),
58
59
 
59
60
  gradient: (theme, { color, gradient }) => {
60
- const key = color === 'default' ? 'primary' : color;
61
+ // `neutral` borrows primary for the gradient, as this branch always did.
62
+ const accent = accentFor(theme, color === 'neutral' ? 'primary' : color);
61
63
  return {
62
64
  background: gradient
63
- ? `linear-gradient(135deg, ${theme.palette[key].light}, ${theme.palette[key].dark})`
64
- : theme.palette[key].main,
65
- color: theme.palette[key].contrastText,
65
+ ? `linear-gradient(135deg, ${accent.light}, ${accent.dark})`
66
+ : accent.main,
67
+ color: accent.contrastText,
66
68
  };
67
69
  },
68
70
 
@@ -80,7 +82,7 @@ const SURFACES: Record<Variant, (theme: Theme, flags: MenubarStyleFlags) => CSSO
80
82
  bordered: (theme, { blur, color }) => ({
81
83
  ...(blur && { backdropFilter: 'blur(10px)' }),
82
84
  borderBottom: `2px solid ${
83
- color === 'default' ? theme.palette.divider : theme.palette[color].main
85
+ color === 'neutral' ? theme.palette.divider : accentFor(theme, color).main
84
86
  }`,
85
87
  }),
86
88
 
@@ -18,6 +18,7 @@ import { withDefaults } from '../../../utils/withDefaults';
18
18
  import { useMenubarMenus } from './Menubar.hooks';
19
19
  import { barStyles } from './Menubar.styles';
20
20
  import { MenubarToolbar } from './Menubar.toolbar';
21
+
21
22
  import type {
22
23
  MenubarGroupProps,
23
24
  MenubarItem,
@@ -27,7 +28,7 @@ import type {
27
28
  const DEFAULTS = {
28
29
  variant: 'default',
29
30
  size: 'md',
30
- color: 'default',
31
+ color: 'neutral',
31
32
  orientation: 'horizontal',
32
33
  glow: false,
33
34
  pulse: false,
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { CSSProperties,ReactNode } from 'react';
2
3
 
3
4
  export interface MenubarItem {
@@ -14,8 +15,8 @@ export interface MenubarItem {
14
15
  export interface MenubarProps {
15
16
  items: MenubarItem[];
16
17
  variant?: 'default' | 'glass' | 'gradient' | 'elevated' | 'minimal' | 'bordered';
17
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
18
- color?: 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'info' | 'default';
18
+ size?: SizeValue;
19
+ color?: ColorValue;
19
20
  orientation?: 'horizontal' | 'vertical';
20
21
  glow?: boolean;
21
22
  pulse?: boolean;
@@ -47,8 +48,8 @@ export interface MenubarGroupProps {
47
48
  open?: boolean;
48
49
  onOpenChange?: (open: boolean) => void;
49
50
  onClick?: (item: MenubarItem) => void;
50
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
51
- color?: 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'info' | 'default';
51
+ size?: SizeValue;
52
+ color?: ColorValue;
52
53
  className?: string;
53
54
  style?: CSSProperties;
54
55
  }
@@ -56,8 +57,8 @@ export interface MenubarGroupProps {
56
57
  export interface MenubarItemProps extends MenubarItem {
57
58
  selected?: boolean;
58
59
  onClick?: () => void;
59
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
60
- color?: 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'info' | 'default';
60
+ size?: SizeValue;
61
+ color?: ColorValue;
61
62
  showShortcut?: boolean;
62
63
  ripple?: boolean;
63
64
  className?: string;
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { RadioGroupProps as MuiRadioGroupProps } from '@mui/material';
2
3
  import type React from 'react';
3
4
 
@@ -18,12 +19,12 @@ export interface RadioGroupProps extends Omit<MuiRadioGroupProps, 'color'> {
18
19
  /**
19
20
  * The color theme of the radio group
20
21
  */
21
- color?: 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'neutral';
22
+ color?: Exclude<ColorValue, 'info'>;
22
23
 
23
24
  /**
24
25
  * The size of the radio group
25
26
  */
26
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
27
+ size?: SizeValue;
27
28
 
28
29
  /**
29
30
  * Array of radio options
@@ -172,6 +172,18 @@ function renderMenuItems(
172
172
  return items;
173
173
  }
174
174
 
175
+ /**
176
+ * The house scale as a FormControl size.
177
+ *
178
+ * Not `muiSize`: that collapses five onto MUI's three, and a FormControl takes
179
+ * only two. This component's scale is already narrowed to `sm | md`, so the map
180
+ * is exact rather than lossy.
181
+ */
182
+ const formControlSize = (size: SelectProps['size']): 'small' | 'medium' | undefined => {
183
+ if (size === undefined) return undefined;
184
+ return size === 'sm' ? 'small' : 'medium';
185
+ };
186
+
175
187
  export const Select = React.forwardRef<HTMLDivElement, SelectProps>(
176
188
  (
177
189
  {
@@ -202,7 +214,7 @@ export const Select = React.forwardRef<HTMLDivElement, SelectProps>(
202
214
  return (
203
215
  <StyledFormControl
204
216
  fullWidth={fullWidth}
205
- size={size}
217
+ size={formControlSize(size)}
206
218
  error={error}
207
219
  customVariant={variant}
208
220
  glow={glow}
@@ -1,3 +1,4 @@
1
+ import type { SizeValue } from '../../../tokens/scales';
1
2
  import type { SelectProps as MuiSelectProps } from '@mui/material';
2
3
 
3
4
  export type SelectVariant = 'default' | 'glass' | 'gradient';
@@ -8,7 +9,9 @@ export interface SelectOption {
8
9
  disabled?: boolean;
9
10
  }
10
11
 
11
- export interface SelectProps extends Omit<MuiSelectProps, 'variant'> {
12
+ // `size` is omitted alongside `variant`: MUI declares it in its own words
13
+ // (`small | medium`), and this component speaks the house scale.
14
+ export interface SelectProps extends Omit<MuiSelectProps, 'variant' | 'size'> {
12
15
  /**
13
16
  * Visual variant of the select component
14
17
  * @default 'default'
@@ -35,7 +38,7 @@ export interface SelectProps extends Omit<MuiSelectProps, 'variant'> {
35
38
  * Size of the select component
36
39
  * @default 'medium'
37
40
  */
38
- size?: 'small' | 'medium';
41
+ size?: Extract<SizeValue, 'sm' | 'md'>;
39
42
  /**
40
43
  * Placeholder text when no option is selected
41
44
  */
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { SliderProps as MuiSliderProps } from '@mui/material';
2
3
 
3
4
  export interface SliderProps extends Omit<MuiSliderProps, 'color' | 'size'> {
@@ -9,12 +10,12 @@ export interface SliderProps extends Omit<MuiSliderProps, 'color' | 'size'> {
9
10
  /**
10
11
  * The color theme of the slider
11
12
  */
12
- color?: 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'neutral';
13
+ color?: Exclude<ColorValue, 'info'>;
13
14
 
14
15
  /**
15
16
  * The size of the slider
16
17
  */
17
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
18
+ size?: SizeValue;
18
19
 
19
20
  /**
20
21
  * Label for the slider
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { SwitchProps as MuiSwitchProps } from '@mui/material';
2
3
  import type { FocusEventHandler,MouseEventHandler, ReactNode } from 'react';
3
4
 
@@ -10,12 +11,12 @@ export interface SwitchProps extends Omit<MuiSwitchProps, 'color' | 'size'> {
10
11
  /**
11
12
  * The color theme of the switch
12
13
  */
13
- color?: 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'neutral';
14
+ color?: Exclude<ColorValue, 'info'>;
14
15
 
15
16
  /**
16
17
  * The size of the switch
17
18
  */
18
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
19
+ size?: SizeValue;
19
20
 
20
21
  /**
21
22
  * Label text for the switch
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { TextareaAutosizeProps } from '@mui/material';
2
3
  import type React from 'react';
3
4
 
@@ -10,12 +11,12 @@ export interface TextareaProps extends Omit<TextareaAutosizeProps, 'variant' | '
10
11
  /**
11
12
  * The color theme of the textarea
12
13
  */
13
- color?: 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'neutral';
14
+ color?: Exclude<ColorValue, 'info'>;
14
15
 
15
16
  /**
16
17
  * The size of the textarea
17
18
  */
18
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
19
+ size?: SizeValue;
19
20
 
20
21
  /**
21
22
  * Whether the textarea has an error
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { ToggleButtonProps } from '@mui/material';
2
3
  import type React from 'react';
3
4
 
@@ -10,12 +11,12 @@ export interface ToggleProps extends Omit<ToggleButtonProps, 'color' | 'size'> {
10
11
  /**
11
12
  * The color theme of the toggle
12
13
  */
13
- color?: 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'neutral';
14
+ color?: Exclude<ColorValue, 'info'>;
14
15
 
15
16
  /**
16
17
  * The size of the toggle
17
18
  */
18
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
19
+ size?: SizeValue;
19
20
 
20
21
  /**
21
22
  * Icon for the toggle
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { ToggleButtonGroupProps } from '@mui/material';
2
3
  import type React from 'react';
3
4
 
@@ -17,12 +18,12 @@ export interface ToggleGroupProps extends Omit<ToggleButtonGroupProps, 'color' |
17
18
  /**
18
19
  * The color theme of the toggle group
19
20
  */
20
- color?: 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'neutral';
21
+ color?: Exclude<ColorValue, 'info'>;
21
22
 
22
23
  /**
23
24
  * The size of the toggle group
24
25
  */
25
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
26
+ size?: SizeValue;
26
27
 
27
28
  /**
28
29
  * Array of toggle options
@@ -1,8 +1,9 @@
1
+ import type { SizeValue } from '../../../tokens/scales';
1
2
  import type { ReactNode } from 'react';
2
3
 
3
4
  export type SeparatorVariant = 'solid' | 'dashed' | 'dotted' | 'gradient';
4
5
  export type SeparatorOrientation = 'horizontal' | 'vertical';
5
- export type SeparatorSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
6
+ export type SeparatorSize = SizeValue;
6
7
 
7
8
  export interface SeparatorProps {
8
9
  variant?: SeparatorVariant;
@@ -1,4 +1,5 @@
1
- export type SpacerSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
1
+ import type { SizeValue } from '../../../tokens/scales';
2
+ export type SpacerSize = SizeValue;
2
3
  export type SpacerDirection = 'horizontal' | 'vertical' | 'both';
3
4
 
4
5
  export interface SpacerProps {
@@ -114,7 +114,7 @@ const BREADCRUMBS_DEFAULTS: Pick<BreadcrumbsProps, BreadcrumbsDefaultedKeys> = {
114
114
  maxItems: 8,
115
115
  showHomeIcon: true,
116
116
  size: 'md',
117
- color: 'default',
117
+ color: 'neutral',
118
118
  elevation: 1,
119
119
  collapseBehavior: 'menu',
120
120
  mobileMaxItems: 3 };
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { BreadcrumbsProps as MuiBreadcrumbsProps } from '@mui/material';
2
3
  import type { ReactNode } from 'react';
3
4
 
@@ -105,13 +106,17 @@ export interface BreadcrumbsProps extends Omit<MuiBreadcrumbsProps, 'separator'>
105
106
  * Size of the breadcrumbs
106
107
  * @default 'md'
107
108
  */
108
- size?: 'sm' | 'md' | 'lg';
109
+ size?: Extract<SizeValue, 'sm' | 'md' | 'lg'>;
109
110
 
110
111
  /**
111
112
  * Color scheme for separators and accents
112
113
  * @default 'default'
113
114
  */
114
- color?: 'default' | 'primary' | 'secondary';
115
+ /**
116
+ * `neutral` is what this called `default`: the unaccented state, renamed to
117
+ * the house word rather than kept as a third spelling of the same idea.
118
+ */
119
+ color?: Extract<ColorValue, 'primary' | 'secondary' | 'neutral'>;
115
120
 
116
121
  /**
117
122
  * Elevation level for glass and elevated variants (0-5)
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { MenuProps } from '@mui/material';
2
3
  import type { ReactNode } from 'react';
3
4
 
@@ -40,7 +41,7 @@ export interface ContextMenuItem {
40
41
  /**
41
42
  * Color variant for the item
42
43
  */
43
- color?: 'default' | 'primary' | 'secondary' | 'error' | 'warning' | 'info' | 'success';
44
+ color?: ColorValue;
44
45
 
45
46
  /**
46
47
  * Whether the item is dangerous/destructive
@@ -82,7 +83,7 @@ export interface ContextMenuProps extends Omit<MenuProps, 'open' | 'anchorEl' |
82
83
  /**
83
84
  * Size of the menu items
84
85
  */
85
- size?: 'sm' | 'md' | 'lg';
86
+ size?: Extract<SizeValue, 'sm' | 'md' | 'lg'>;
86
87
 
87
88
  /**
88
89
  * Custom className for the trigger element
@@ -189,6 +189,7 @@ const renderLeafMenuItem = (
189
189
  onClick={!item.disabled ? () => handleItemClick(item) : undefined} // ← change
190
190
  color={item.color}
191
191
  showIconSpace={showIconSpace && !hasIcon}
192
+ data-testid={item.dataTestId}
192
193
  >
193
194
  {hasIcon && (
194
195
  <ListItemIcon sx={{ minWidth: size === 'sm' ? 32 : 40 }}>{item.icon}</ListItemIcon>
@@ -1,3 +1,4 @@
1
+ import type { ColorValue, SizeValue } from '../../../tokens/scales';
1
2
  import type { MenuProps } from '@mui/material';
2
3
  import type { ReactNode } from 'react';
3
4
 
@@ -55,7 +56,16 @@ export interface DropdownMenuItem {
55
56
  /**
56
57
  * Color variant for the item
57
58
  */
58
- color?: 'default' | 'primary' | 'secondary' | 'error' | 'warning' | 'info' | 'success';
59
+ color?: ColorValue;
60
+
61
+ /**
62
+ * Test ID for the rendered item.
63
+ *
64
+ * Needed by any surface where an action MOVES into this menu when the row
65
+ * runs out of room: the action's id has to survive the move, or a suite that
66
+ * drives it by id passes on a wide screen and fails on a narrow one.
67
+ */
68
+ dataTestId?: string;
59
69
  }
60
70
 
61
71
  export interface DropdownMenuProps extends Omit<MenuProps, 'open' | 'variant'> {
@@ -92,7 +102,7 @@ export interface DropdownMenuProps extends Omit<MenuProps, 'open' | 'variant'> {
92
102
  /**
93
103
  * Size of the menu items
94
104
  */
95
- size?: 'sm' | 'md' | 'lg';
105
+ size?: Extract<SizeValue, 'sm' | 'md' | 'lg'>;
96
106
 
97
107
  /**
98
108
  * Maximum height of the menu