@recursica/mui-adapter 0.4.0 → 0.6.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 (177) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/mui-adapter.cjs +74 -1
  3. package/dist/mui-adapter.cjs.map +1 -1
  4. package/dist/mui-adapter.css +1 -1
  5. package/dist/mui-adapter.js +6651 -201
  6. package/dist/mui-adapter.js.map +1 -1
  7. package/dist/src/components/Accordion/Accordion.d.ts +63 -2
  8. package/dist/src/components/AssistiveElement/AssistiveElement.d.ts +9 -2
  9. package/dist/src/components/Autocomplete/Autocomplete.d.ts +17 -0
  10. package/dist/src/components/Autocomplete/index.d.ts +1 -0
  11. package/dist/src/components/Avatar/Avatar.d.ts +14 -2
  12. package/dist/src/components/Badge/Badge.d.ts +13 -3
  13. package/dist/src/components/Breadcrumb/Breadcrumb.d.ts +10 -3
  14. package/dist/src/components/Button/Button.d.ts +1 -1
  15. package/dist/src/components/Card/Card.d.ts +40 -3
  16. package/dist/src/components/Checkbox/Checkbox.d.ts +15 -2
  17. package/dist/src/components/Checkbox/CheckboxGroup.d.ts +16 -0
  18. package/dist/src/components/Checkbox/index.d.ts +5 -1
  19. package/dist/src/components/Chip/Chip.d.ts +18 -2
  20. package/dist/src/components/Dropdown/Dropdown.d.ts +23 -3
  21. package/dist/src/components/FormControlLayout/FormControlLayout.d.ts +10 -2
  22. package/dist/src/components/FormControlWrapper/FormControlWrapper.d.ts +24 -2
  23. package/dist/src/components/HoverCard/HoverCard.d.ts +55 -3
  24. package/dist/src/components/Label/Label.d.ts +13 -2
  25. package/dist/src/components/Link/Link.d.ts +1 -1
  26. package/dist/src/components/Menu/Menu.d.ts +99 -3
  27. package/dist/src/components/Modal/Modal.d.ts +36 -2
  28. package/dist/src/components/NumberInput/NumberInput.d.ts +14 -2
  29. package/dist/src/components/Pagination/Pagination.d.ts +44 -2
  30. package/dist/src/components/Pagination/Pagination.icons.d.ts +8 -0
  31. package/dist/src/components/Panel/Panel.d.ts +65 -3
  32. package/dist/src/components/Radio/Radio.d.ts +13 -3
  33. package/dist/src/components/Radio/RadioGroup.d.ts +13 -0
  34. package/dist/src/components/ReadOnlyField/ReadOnlyBooleanField.d.ts +5 -0
  35. package/dist/src/components/ReadOnlyField/ReadOnlyField.d.ts +7 -2
  36. package/dist/src/components/ReadOnlyField/ReadOnlySwitchField.d.ts +5 -0
  37. package/dist/src/components/ReadOnlyField/ReadOnlyTextField.d.ts +8 -0
  38. package/dist/src/components/ReadOnlyField/WithReadOnlyWrapper.d.ts +28 -0
  39. package/dist/src/components/ReadOnlyField/index.d.ts +1 -0
  40. package/dist/src/components/SegmentedControl/SegmentedControl.d.ts +31 -3
  41. package/dist/src/components/Slider/Slider.d.ts +28 -2
  42. package/dist/src/components/Stepper/Stepper.d.ts +21 -2
  43. package/dist/src/components/Switch/Switch.d.ts +10 -3
  44. package/dist/src/components/Switch/SwitchGroup.d.ts +13 -0
  45. package/dist/src/components/Tabs/Tabs.d.ts +35 -3
  46. package/dist/src/components/Text/Text.d.ts +1 -1
  47. package/dist/src/components/TextArea/TextArea.d.ts +18 -2
  48. package/dist/src/components/TextField/TextField.d.ts +16 -2
  49. package/dist/src/components/Timeline/Timeline.d.ts +14 -2
  50. package/dist/src/components/Timeline/TimelineItem.d.ts +29 -0
  51. package/dist/src/components/Title/Title.d.ts +1 -1
  52. package/dist/src/components/Toast/Toast.d.ts +25 -2
  53. package/dist/src/components/Tooltip/Tooltip.d.ts +42 -3
  54. package/dist/src/components/Typography/Typography.d.ts +1 -1
  55. package/dist/src/components/index.d.ts +1 -0
  56. package/package.json +12 -2
  57. package/src/GlobalExemptions.modules.css +13 -0
  58. package/src/components/Accordion/Accordion.module.css +295 -0
  59. package/src/components/Accordion/Accordion.stories.tsx +149 -21
  60. package/src/components/Accordion/Accordion.tsx +264 -4
  61. package/src/components/AssistiveElement/AssistiveElement.module.css +111 -0
  62. package/src/components/AssistiveElement/AssistiveElement.stories.tsx +76 -19
  63. package/src/components/AssistiveElement/AssistiveElement.tsx +85 -4
  64. package/src/components/Autocomplete/Autocomplete.module.css +325 -0
  65. package/src/components/Autocomplete/Autocomplete.stories.tsx +196 -0
  66. package/src/components/Autocomplete/Autocomplete.tsx +201 -0
  67. package/src/components/Autocomplete/index.ts +1 -0
  68. package/src/components/Avatar/Avatar.module.css +344 -0
  69. package/src/components/Avatar/Avatar.stories.tsx +94 -22
  70. package/src/components/Avatar/Avatar.tsx +110 -5
  71. package/src/components/Badge/Badge.module.css +127 -0
  72. package/src/components/Badge/Badge.stories.tsx +65 -22
  73. package/src/components/Badge/Badge.tsx +70 -5
  74. package/src/components/Breadcrumb/Breadcrumb.module.css +26 -0
  75. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +57 -22
  76. package/src/components/Breadcrumb/Breadcrumb.tsx +62 -5
  77. package/src/components/Button/Button.module.css +113 -20
  78. package/src/components/Button/Button.stories.tsx +3 -0
  79. package/src/components/Button/Button.tsx +10 -3
  80. package/src/components/Card/Card.module.css +118 -0
  81. package/src/components/Card/Card.stories.tsx +117 -19
  82. package/src/components/Card/Card.tsx +179 -4
  83. package/src/components/Checkbox/Checkbox.module.css +232 -0
  84. package/src/components/Checkbox/Checkbox.stories.tsx +81 -19
  85. package/src/components/Checkbox/Checkbox.tsx +146 -4
  86. package/src/components/Checkbox/CheckboxGroup.tsx +117 -0
  87. package/src/components/Checkbox/index.ts +6 -1
  88. package/src/components/Chip/Chip.module.css +236 -0
  89. package/src/components/Chip/Chip.stories.tsx +101 -21
  90. package/src/components/Chip/Chip.tsx +138 -5
  91. package/src/components/DatePicker/DatePicker.module.css +42 -0
  92. package/src/components/DatePicker/DatePicker.tsx +1 -0
  93. package/src/components/Dropdown/Dropdown.module.css +296 -0
  94. package/src/components/Dropdown/Dropdown.stories.tsx +80 -21
  95. package/src/components/Dropdown/Dropdown.tsx +182 -5
  96. package/src/components/FileInput/FileInput.module.css +47 -0
  97. package/src/components/FileInput/FileInput.tsx +1 -0
  98. package/src/components/FileUpload/FileUpload.module.css +40 -0
  99. package/src/components/FileUpload/FileUpload.tsx +1 -0
  100. package/src/components/FormControlLayout/FormControlLayout.module.css +92 -0
  101. package/src/components/FormControlLayout/FormControlLayout.stories.tsx +74 -19
  102. package/src/components/FormControlLayout/FormControlLayout.tsx +58 -4
  103. package/src/components/FormControlWrapper/FormControlWrapper.module.css +96 -0
  104. package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +122 -19
  105. package/src/components/FormControlWrapper/FormControlWrapper.tsx +145 -6
  106. package/src/components/HoverCard/HoverCard.module.css +91 -0
  107. package/src/components/HoverCard/HoverCard.stories.tsx +158 -21
  108. package/src/components/HoverCard/HoverCard.tsx +150 -4
  109. package/src/components/Label/Label.module.css +136 -0
  110. package/src/components/Label/Label.stories.tsx +98 -17
  111. package/src/components/Label/Label.tsx +88 -4
  112. package/src/components/Link/Link.module.css +8 -0
  113. package/src/components/Menu/Menu.module.css +287 -0
  114. package/src/components/Menu/Menu.stories.tsx +307 -21
  115. package/src/components/Menu/Menu.tsx +318 -4
  116. package/src/components/Modal/Modal.module.css +172 -0
  117. package/src/components/Modal/Modal.stories.tsx +66 -22
  118. package/src/components/Modal/Modal.tsx +216 -3
  119. package/src/components/NumberInput/NumberInput.module.css +281 -0
  120. package/src/components/NumberInput/NumberInput.stories.tsx +83 -20
  121. package/src/components/NumberInput/NumberInput.tsx +148 -5
  122. package/src/components/Pagination/Pagination.icons.tsx +66 -0
  123. package/src/components/Pagination/Pagination.module.css +307 -0
  124. package/src/components/Pagination/Pagination.stories.tsx +42 -21
  125. package/src/components/Pagination/Pagination.tsx +193 -4
  126. package/src/components/Panel/Panel.module.css +206 -0
  127. package/src/components/Panel/Panel.stories.tsx +214 -22
  128. package/src/components/Panel/Panel.tsx +153 -4
  129. package/src/components/Radio/Radio.module.css +220 -0
  130. package/src/components/Radio/Radio.stories.tsx +77 -19
  131. package/src/components/Radio/Radio.tsx +178 -4
  132. package/src/components/Radio/RadioGroup.tsx +111 -0
  133. package/src/components/ReadOnlyField/ReadOnlyBooleanField.tsx +21 -0
  134. package/src/components/ReadOnlyField/ReadOnlyField.module.css +54 -0
  135. package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +175 -16
  136. package/src/components/ReadOnlyField/ReadOnlyField.tsx +109 -4
  137. package/src/components/ReadOnlyField/ReadOnlySwitchField.tsx +21 -0
  138. package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +48 -0
  139. package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +93 -0
  140. package/src/components/ReadOnlyField/index.ts +1 -0
  141. package/src/components/SegmentedControl/SegmentedControl.module.css +203 -0
  142. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +102 -20
  143. package/src/components/SegmentedControl/SegmentedControl.tsx +110 -5
  144. package/src/components/Slider/Slider.module.css +542 -0
  145. package/src/components/Slider/Slider.stories.tsx +157 -19
  146. package/src/components/Slider/Slider.tsx +282 -4
  147. package/src/components/Stepper/Stepper.module.css +410 -0
  148. package/src/components/Stepper/Stepper.stories.tsx +132 -19
  149. package/src/components/Stepper/Stepper.tsx +145 -5
  150. package/src/components/Switch/Switch.module.css +238 -0
  151. package/src/components/Switch/Switch.stories.tsx +98 -19
  152. package/src/components/Switch/Switch.tsx +153 -5
  153. package/src/components/Switch/SwitchGroup.tsx +111 -0
  154. package/src/components/Tabs/Tabs.module.css +422 -0
  155. package/src/components/Tabs/Tabs.stories.tsx +138 -19
  156. package/src/components/Tabs/Tabs.tsx +103 -5
  157. package/src/components/TextArea/TextArea.module.css +160 -0
  158. package/src/components/TextArea/TextArea.stories.tsx +80 -21
  159. package/src/components/TextArea/TextArea.tsx +156 -5
  160. package/src/components/TextField/TextField.module.css +266 -0
  161. package/src/components/TextField/TextField.stories.tsx +168 -15
  162. package/src/components/TextField/TextField.tsx +171 -5
  163. package/src/components/TimePicker/TimePicker.module.css +41 -0
  164. package/src/components/TimePicker/TimePicker.tsx +1 -0
  165. package/src/components/Timeline/Timeline.module.css +367 -0
  166. package/src/components/Timeline/Timeline.stories.tsx +114 -21
  167. package/src/components/Timeline/Timeline.tsx +80 -4
  168. package/src/components/Timeline/TimelineItem.tsx +101 -0
  169. package/src/components/Toast/Toast.module.css +170 -0
  170. package/src/components/Toast/Toast.stories.tsx +54 -22
  171. package/src/components/Toast/Toast.tsx +90 -4
  172. package/src/components/Tooltip/Tooltip.module.css +90 -0
  173. package/src/components/Tooltip/Tooltip.stories.tsx +152 -22
  174. package/src/components/Tooltip/Tooltip.tsx +114 -4
  175. package/src/components/TransferList/TransferList.module.css +38 -0
  176. package/src/components/TransferList/TransferList.tsx +1 -0
  177. package/src/components/index.ts +1 -0
@@ -0,0 +1,136 @@
1
+ .root {
2
+ /* Prevent default MUI absolute positioning logic */
3
+ position: relative;
4
+ transform: none;
5
+ pointer-events: auto;
6
+ white-space: normal;
7
+
8
+ /* Reset MUI structural overrides */
9
+ margin: 0;
10
+ padding: 0;
11
+ display: flex;
12
+ width: 100%;
13
+
14
+ /* Recursica Font Map */
15
+ font-family: var(
16
+ --recursica_ui-kit_components_label_properties_label-text_font-family
17
+ );
18
+ font-size: var(
19
+ --recursica_ui-kit_components_label_properties_label-text_font-size
20
+ );
21
+ font-style: var(
22
+ --recursica_ui-kit_components_label_properties_label-text_font-style
23
+ );
24
+ font-weight: var(
25
+ --recursica_ui-kit_components_label_properties_label-text_font-weight
26
+ );
27
+ letter-spacing: var(
28
+ --recursica_ui-kit_components_label_properties_label-text_letter-spacing
29
+ );
30
+ line-height: var(
31
+ --recursica_ui-kit_components_label_properties_label-text_line-height
32
+ );
33
+ text-decoration: var(
34
+ --recursica_ui-kit_components_label_properties_label-text_text-decoration
35
+ );
36
+ text-transform: var(
37
+ --recursica_ui-kit_components_label_properties_label-text_text-transform
38
+ );
39
+
40
+ color: var(--recursica_ui-kit_components_label_properties_colors_text);
41
+ }
42
+
43
+ .innerLayout {
44
+ display: flex;
45
+ align-items: center;
46
+ gap: var(
47
+ --recursica_ui-kit_components_label_properties_label-optional-text-gap
48
+ );
49
+ width: 100%;
50
+ }
51
+
52
+ .text {
53
+ /* Natively intercepts MUI asterisk rendering securely wrapping inline with typography */
54
+ display: inline;
55
+ }
56
+
57
+ .required {
58
+ /* Override the `.MuiInputLabel-asterisk` natively */
59
+ color: var(--recursica_ui-kit_components_label_properties_colors_asterisk);
60
+ margin-left: var(
61
+ --recursica_ui-kit_components_label_properties_required-indicator-gap
62
+ );
63
+ }
64
+
65
+ /* MUI propagates .Mui-error to the label automatically on FormControl error.
66
+ We explicitly override this bleed to prevent the main label text from turning red,
67
+ while allowing the asterisk to take the error color! */
68
+ .root:global(.Mui-error) {
69
+ color: var(--recursica_ui-kit_components_label_properties_colors_text);
70
+ }
71
+ .root:global(.Mui-error) .required {
72
+ color: var(
73
+ --recursica_ui-kit_components_assistive-element_variants_types_error_properties_colors_text-color
74
+ );
75
+ }
76
+
77
+ .endNodes {
78
+ display: flex;
79
+ align-items: center;
80
+ gap: var(
81
+ --recursica_ui-kit_components_label_properties_label-optional-text-gap
82
+ );
83
+ }
84
+
85
+ .optionalText {
86
+ color: inherit;
87
+ font-family: var(
88
+ --recursica_ui-kit_components_label_properties_optional-text_font-family
89
+ );
90
+ font-size: var(
91
+ --recursica_ui-kit_components_label_properties_optional-text_font-size
92
+ );
93
+ font-style: var(
94
+ --recursica_ui-kit_components_label_properties_optional-text_font-style
95
+ );
96
+ font-weight: var(
97
+ --recursica_ui-kit_components_label_properties_optional-text_font-weight
98
+ );
99
+ letter-spacing: var(
100
+ --recursica_ui-kit_components_label_properties_optional-text_letter-spacing
101
+ );
102
+ line-height: var(
103
+ --recursica_ui-kit_components_label_properties_optional-text_line-height
104
+ );
105
+ text-decoration: var(
106
+ --recursica_ui-kit_components_label_properties_optional-text_text-decoration
107
+ );
108
+ text-transform: var(
109
+ --recursica_ui-kit_components_label_properties_optional-text_text-transform
110
+ );
111
+ }
112
+
113
+ .actionArea {
114
+ display: flex;
115
+ align-items: center;
116
+ }
117
+
118
+ .editIcon {
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ cursor: pointer;
123
+ background: none;
124
+ border: none;
125
+ padding: 0;
126
+
127
+ width: 16px;
128
+ height: 16px;
129
+ color: inherit;
130
+ }
131
+
132
+ .editIcon :global(svg) {
133
+ width: 100%;
134
+ height: 100%;
135
+ stroke-width: 2px;
136
+ }
@@ -1,35 +1,116 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import React from "react";
1
3
  import type { Meta, StoryObj } from "@storybook/react";
2
4
  import { Label } from "./Label";
3
- import { ComingSoon } from "@recursica/storybook-template";
5
+ import { TextField } from "../TextField/TextField";
6
+ import { formControlArgTypes } from "../../../.storybook/commonArgTypes";
4
7
 
5
- const meta: Meta<typeof Label> = {
6
- title: "UI-Kit/🚧 Label",
8
+ type LabelStoryProps = React.ComponentProps<typeof Label>;
9
+
10
+ const meta: Meta<LabelStoryProps> = {
11
+ title: "UI-Kit/Label",
7
12
  component: Label,
8
13
  tags: ["autodocs"],
9
14
  parameters: {
15
+ docs: {
16
+ description: {
17
+ component:
18
+ "The `Label` component is a strict Recursica-styled wrapper around MUI's native `InputLabel`. It serves as the primary compositional primitive for all form fields, preserving MUI's accessibility associations and context while strictly enforcing the Recursica atomic design system.\n\n### Usage with Form Inputs\nWhen working with form structures, render this `Label` component directly above your inputs or supply it to a component's overriding properties. The component automatically maps structural layout dimensions, dynamic alignment (`left` vs `right`), custom indicator gaps, and integrates a customized `optionalText` and `withEditIcon` flow that safely bypasses MUI's native required asterisk mechanisms.",
19
+ },
20
+ },
10
21
  controls: {
11
22
  include: [
12
- "layer",
13
- "withLayer",
23
+ "labelSize",
24
+ "labelAlignment",
25
+ "required",
26
+ "labelOptionalText",
27
+ "labelWithEditIcon",
14
28
  "children",
15
- "component",
16
- "variant",
17
- "size",
18
- "icon",
19
- "disabled",
20
- "href",
21
- "onClick",
22
- "onChange",
23
- "value",
24
- "checked",
25
29
  ],
26
30
  },
27
31
  },
32
+ argTypes: {
33
+ ...formControlArgTypes,
34
+ },
28
35
  };
29
36
 
30
37
  export default meta;
31
- type Story = StoryObj<typeof Label>;
38
+
39
+ type Story = StoryObj<LabelStoryProps>;
40
+
41
+ // Utility mapping to pipe raw Label args structurally into TextField accurately
42
+ const renderWithTextField = ({ children, ...args }: any) => (
43
+ <TextField
44
+ label={children as React.ReactNode}
45
+ placeholder="Form Control primitive mapped..."
46
+ {...(args as any)}
47
+ />
48
+ );
32
49
 
33
50
  export const Default: Story = {
34
- render: () => <ComingSoon componentName="Label" />,
51
+ args: {
52
+ children: "Dynamic Label (Controls)",
53
+ labelSize: "default",
54
+ labelAlignment: "left",
55
+ required: false,
56
+ labelOptionalText: "",
57
+ labelWithEditIcon: false,
58
+ },
59
+ render: renderWithTextField,
60
+ };
61
+
62
+ export const StackedDefault: Story = {
63
+ args: {
64
+ children: "Email Address",
65
+ },
66
+ render: renderWithTextField,
67
+ };
68
+
69
+ export const StackedRequired: Story = {
70
+ args: {
71
+ children: "Primary Network Node",
72
+ required: true,
73
+ },
74
+ render: renderWithTextField,
75
+ };
76
+
77
+ export const StackedWithEditIcon: Story = {
78
+ args: {
79
+ children: "Environment Variables",
80
+ labelWithEditIcon: true,
81
+ },
82
+ render: renderWithTextField,
83
+ };
84
+
85
+ export const SideBySideDefault: Story = {
86
+ args: {
87
+ children: "Status",
88
+ labelSize: "default",
89
+ },
90
+ render: renderWithTextField,
91
+ };
92
+
93
+ export const RequiredSuppressesOptionalText: Story = {
94
+ args: {
95
+ children: "Full Name",
96
+ required: true,
97
+ labelOptionalText: "This should not render",
98
+ },
99
+ render: renderWithTextField,
100
+ };
101
+
102
+ export const BooleanOptionalText: Story = {
103
+ args: {
104
+ children: "Middle Initial",
105
+ labelOptionalText: true,
106
+ },
107
+ render: renderWithTextField,
108
+ };
109
+
110
+ export const WithEditIcon: Story = {
111
+ args: {
112
+ children: "Shipping Address",
113
+ labelWithEditIcon: true,
114
+ },
115
+ render: renderWithTextField,
35
116
  };
@@ -1,7 +1,91 @@
1
1
  import React from "react";
2
+ import { InputLabel, type InputLabelProps } from "@mui/material";
3
+ import { filterStylingProps } from "../../utils/filterStylingProps";
4
+ import styles from "./Label.module.css";
2
5
 
3
- export type LabelProps = React.HTMLAttributes<HTMLDivElement>;
6
+ export interface LabelProps extends InputLabelProps {
7
+ overStyled?: boolean;
8
+ /** Explicit optional text to render safely mapping alongside the label. Hidden natively if 'required' is flagged true. */
9
+ labelOptionalText?: React.ReactNode | true;
10
+ /** Triggers the inline edit action icon native layout hook beside the label element. */
11
+ labelWithEditIcon?: boolean;
12
+ /** Fires specifically on icon click natively. */
13
+ onLabelEditClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
14
+ /** Replaces the right side optional text block natively with any custom React node (e.g. actions, toggles). */
15
+ labelActionArea?: React.ReactNode;
16
+ }
4
17
 
5
- export const Label: React.FC<LabelProps> = (props) => {
6
- return <div {...props}>Label</div>;
7
- };
18
+ export const Label = React.forwardRef<HTMLLabelElement, LabelProps>(
19
+ function Label(props, ref) {
20
+ const {
21
+ overStyled = false,
22
+ required = false,
23
+ labelOptionalText = "",
24
+ labelWithEditIcon = false,
25
+ onLabelEditClick,
26
+ labelActionArea,
27
+ children,
28
+ className,
29
+ ...rest
30
+ } = props;
31
+
32
+ const sanitizedProps = filterStylingProps(rest, overStyled);
33
+
34
+ const PenIcon = () => (
35
+ <svg
36
+ xmlns="http://www.w3.org/2000/svg"
37
+ width="24"
38
+ height="24"
39
+ viewBox="0 0 24 24"
40
+ fill="none"
41
+ stroke="currentColor"
42
+ strokeWidth="2"
43
+ strokeLinecap="round"
44
+ strokeLinejoin="round"
45
+ >
46
+ <path d="M12 20h9"></path>
47
+ <path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"></path>
48
+ </svg>
49
+ );
50
+
51
+ // Bypassing MUI's floating functionality by forcing shrink=true to static inline positioning.
52
+ return (
53
+ <InputLabel
54
+ ref={ref}
55
+ shrink={true}
56
+ className={className ? `${styles.root} ${className}` : styles.root}
57
+ {...(sanitizedProps as InputLabelProps)}
58
+ >
59
+ <div className={styles.innerLayout}>
60
+ <span className={styles.textWrapper}>
61
+ <span className={styles.text}>{children}</span>
62
+ {required && <span className={styles.required}> *</span>}
63
+ </span>
64
+
65
+ <div className={styles.endNodes}>
66
+ {labelActionArea && (
67
+ <span className={styles.actionArea}>{labelActionArea}</span>
68
+ )}
69
+ {!required && labelOptionalText && !labelActionArea && (
70
+ <span className={styles.optionalText}>
71
+ {labelOptionalText === true ? "Optional" : labelOptionalText}
72
+ </span>
73
+ )}
74
+ {labelWithEditIcon && (
75
+ <button
76
+ type="button"
77
+ className={styles.editIcon}
78
+ onClick={onLabelEditClick}
79
+ aria-label="Edit label"
80
+ >
81
+ <PenIcon />
82
+ </button>
83
+ )}
84
+ </div>
85
+ </div>
86
+ </InputLabel>
87
+ );
88
+ },
89
+ );
90
+
91
+ Label.displayName = "Label";
@@ -131,3 +131,11 @@ HARDCODED VALUES:
131
131
  /* HARDCODE: allows text truncation if bounded */
132
132
  min-width: 0;
133
133
  }
134
+
135
+ /* EXEMPTIONS:
136
+ text_text-transform across multiple link states (default, hover, visited, visited-hover) is ignored
137
+ because links naturally inherit casing directly from text children rather than requiring custom CSS transforms. */
138
+ /* recursica-ignore: --recursica_ui-kit_components_link_variants_states_default_properties_text_text-transform */
139
+ /* recursica-ignore: --recursica_ui-kit_components_link_variants_states_hover_properties_text_text-transform */
140
+ /* recursica-ignore: --recursica_ui-kit_components_link_variants_states_visited_properties_text_text-transform */
141
+ /* recursica-ignore: --recursica_ui-kit_components_link_variants_states_visited-hover_properties_text_text-transform */
@@ -0,0 +1,287 @@
1
+ /* EXEMPTIONS:
2
+ - colors_selected-item_supporting-text-color is ignored because selected menu items do not render
3
+ supporting secondary text, making selected state overrides for supporting text colors obsolete. */
4
+ /* recursica-ignore: --recursica_ui-kit_components_menu-item_properties_colors_selected-item_supporting-text-color */
5
+
6
+ /* HARDCODED VALUES:
7
+ - border-style: solid. Structural rendering rule for the dropdown border (Mantine uses Paper which may not set border natively).
8
+ - opacity: 0.5 on disabled items. Recursica has no dedicated disabled-opacity token for menu items.
9
+ - NOTE: overflow is intentionally NOT set on .dropdown. Mantine renders sub-menu dropdowns
10
+ inside the parent dropdown DOM tree using Floating UI absolute positioning. Setting
11
+ overflow: hidden clips sub-menus; overflow-y: auto causes unwanted scrollbars.
12
+ - All structural layout (flex, cursor, pointer-events on disabled) is deferred to Mantine's
13
+ native behavior. We only override visual design tokens (colors, typography, spacing, borders).
14
+ */
15
+
16
+ /* ======================================
17
+ DROPDOWN CONTAINER
18
+ ====================================== */
19
+
20
+ .dropdown {
21
+ background-color: var(
22
+ --recursica_ui-kit_components_menu_properties_colors_background
23
+ );
24
+ border-style: solid; /* HARDCODE: Mantine Paper does not set border-style natively */
25
+ border-width: var(--recursica_ui-kit_components_menu_properties_border-size);
26
+ border-color: var(
27
+ --recursica_ui-kit_components_menu_properties_colors_border-color
28
+ );
29
+ border-radius: var(
30
+ --recursica_ui-kit_components_menu_properties_border-radius
31
+ );
32
+ box-shadow: var(--recursica_ui-kit_components_menu_properties_elevation);
33
+
34
+ min-width: var(--recursica_ui-kit_components_menu_properties_min-width);
35
+ max-height: var(--recursica_ui-kit_components_menu_properties_max-height);
36
+ max-width: var(--recursica_ui-kit_components_menu_properties_max-width);
37
+
38
+ /* HARDCODE: Figma UI Kit does not export padding tokens for the Menu container itself.
39
+ If added in the future, it would be mapped here. */
40
+ padding: 8px;
41
+ }
42
+
43
+ /* ======================================
44
+ MENU ITEM
45
+ ====================================== */
46
+
47
+ .item {
48
+ position: relative;
49
+
50
+ /* Geometry */
51
+ padding: var(
52
+ --recursica_ui-kit_components_menu-item_properties_vertical-padding
53
+ )
54
+ var(--recursica_ui-kit_components_menu-item_properties_horizontal-padding);
55
+ border-radius: var(
56
+ --recursica_ui-kit_components_menu-item_properties_border-radius
57
+ );
58
+
59
+ /* Typography */
60
+ font-family: var(
61
+ --recursica_ui-kit_components_menu-item_properties_text_font-family
62
+ );
63
+ font-size: var(
64
+ --recursica_ui-kit_components_menu-item_properties_text_font-size
65
+ );
66
+ font-style: var(
67
+ --recursica_ui-kit_components_menu-item_properties_text_font-style
68
+ );
69
+ font-weight: var(
70
+ --recursica_ui-kit_components_menu-item_properties_text_font-weight
71
+ );
72
+ letter-spacing: var(
73
+ --recursica_ui-kit_components_menu-item_properties_text_letter-spacing
74
+ );
75
+ line-height: var(
76
+ --recursica_ui-kit_components_menu-item_properties_text_line-height
77
+ );
78
+ text-decoration: var(
79
+ --recursica_ui-kit_components_menu-item_properties_text_text-decoration
80
+ );
81
+ text-transform: var(
82
+ --recursica_ui-kit_components_menu-item_properties_text_text-transform
83
+ );
84
+
85
+ /* Default State: Unselected */
86
+ background-color: var(
87
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_background
88
+ );
89
+ color: var(
90
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_text
91
+ );
92
+ opacity: 1;
93
+ }
94
+
95
+ /* Override Mantine's native hover background to use our overlay technique */
96
+ .item:hover {
97
+ background-color: var(
98
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_background
99
+ );
100
+ }
101
+
102
+ /* Hover overlay using ::after pseudo-element (same technique as Accordion) */
103
+ .item::after {
104
+ content: "";
105
+ position: absolute;
106
+ inset: 0;
107
+ border-radius: inherit;
108
+ z-index: 0;
109
+ pointer-events: none;
110
+ background-color: var(
111
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_hover-color
112
+ );
113
+ opacity: 0;
114
+ transition: opacity 150ms ease;
115
+ }
116
+
117
+ .item:hover:not([data-disabled])::after {
118
+ opacity: var(
119
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_hover-opacity
120
+ );
121
+ }
122
+
123
+ /* Selected item state */
124
+ .item[data-selected] {
125
+ background-color: var(
126
+ --recursica_ui-kit_components_menu-item_properties_colors_selected-item_background
127
+ );
128
+ color: var(
129
+ --recursica_ui-kit_components_menu-item_properties_colors_selected-item_text
130
+ );
131
+ opacity: 1;
132
+ }
133
+
134
+ .item[data-selected]::after {
135
+ background-color: var(
136
+ --recursica_ui-kit_components_menu-item_properties_colors_selected-item_hover-color
137
+ );
138
+ }
139
+
140
+ /* Hovered item state (keyboard navigation) */
141
+ .item[data-hovered] {
142
+ background-color: var(
143
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_background
144
+ );
145
+ }
146
+ .item[data-hovered]::after {
147
+ opacity: var(
148
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_hover-opacity
149
+ );
150
+ }
151
+
152
+ .item[data-hovered][data-selected]::after {
153
+ opacity: var(
154
+ --recursica_ui-kit_components_menu-item_properties_colors_selected-item_hover-opacity
155
+ );
156
+ }
157
+
158
+ /* Disabled item */
159
+ .item[data-disabled] {
160
+ opacity: var(
161
+ --recursica_ui-kit_components_menu-item_properties_disabled-opacity
162
+ );
163
+ }
164
+
165
+ /* ======================================
166
+ ITEM LABEL
167
+ ====================================== */
168
+
169
+ .itemLabel {
170
+ position: relative;
171
+ z-index: 1;
172
+ color: inherit;
173
+ }
174
+
175
+ /* ======================================
176
+ ITEM SECTION (LEFT / RIGHT ICONS)
177
+ ====================================== */
178
+
179
+ .itemSection {
180
+ position: relative;
181
+ z-index: 1;
182
+ }
183
+
184
+ .itemSection[data-position="left"] {
185
+ width: var(
186
+ --recursica_ui-kit_components_menu-item_properties_icon-leading-size
187
+ );
188
+ height: var(
189
+ --recursica_ui-kit_components_menu-item_properties_icon-leading-size
190
+ );
191
+ margin-right: var(
192
+ --recursica_ui-kit_components_menu-item_properties_icon-text-gap
193
+ );
194
+ color: var(
195
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_leading-icon-color
196
+ );
197
+ }
198
+
199
+ .itemSection[data-position="right"] {
200
+ width: var(
201
+ --recursica_ui-kit_components_menu-item_properties_icon-trailing-size
202
+ );
203
+ height: var(
204
+ --recursica_ui-kit_components_menu-item_properties_icon-trailing-size
205
+ );
206
+ margin-left: var(--recursica_ui-kit_components_menu-item_properties_text-gap);
207
+ color: var(
208
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_trailing-icon-color
209
+ );
210
+ }
211
+
212
+ .item[data-selected] .itemSection[data-position="left"] {
213
+ color: var(
214
+ --recursica_ui-kit_components_menu-item_properties_colors_selected-item_leading-icon-color
215
+ );
216
+ }
217
+
218
+ .item[data-selected] .itemSection[data-position="right"] {
219
+ color: var(
220
+ --recursica_ui-kit_components_menu-item_properties_colors_selected-item_trailing-icon-color
221
+ );
222
+ }
223
+
224
+ /* ======================================
225
+ DIVIDER
226
+ ====================================== */
227
+
228
+ .divider {
229
+ height: var(--recursica_ui-kit_components_menu_properties_divider-height);
230
+ background-color: var(
231
+ --recursica_ui-kit_components_menu_properties_colors_divider-color
232
+ );
233
+ opacity: var(--recursica_ui-kit_components_menu_properties_divider-opacity);
234
+ margin: 8px 0;
235
+ }
236
+
237
+ /* ======================================
238
+ SECTION LABEL
239
+ ====================================== */
240
+
241
+ .label {
242
+ padding: var(
243
+ --recursica_ui-kit_components_menu-item_properties_vertical-padding
244
+ )
245
+ var(--recursica_ui-kit_components_menu-item_properties_horizontal-padding);
246
+
247
+ /* Supporting Text Typography */
248
+ font-family: var(
249
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_font-family
250
+ );
251
+ font-size: var(
252
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_font-size
253
+ );
254
+ font-style: var(
255
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_font-style
256
+ );
257
+ font-weight: var(
258
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_font-weight
259
+ );
260
+ letter-spacing: var(
261
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_letter-spacing
262
+ );
263
+ line-height: var(
264
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_line-height
265
+ );
266
+ text-decoration: var(
267
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_text-decoration
268
+ );
269
+ text-transform: var(
270
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_text-transform
271
+ );
272
+
273
+ color: var(
274
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_supporting-text-color
275
+ );
276
+ opacity: 0.7;
277
+ }
278
+
279
+ /* ======================================
280
+ SUB-MENU CHEVRON
281
+ ====================================== */
282
+
283
+ .chevron {
284
+ position: relative;
285
+ z-index: 1;
286
+ color: inherit;
287
+ }