@recursica/mantine-adapter 0.11.0 → 0.13.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.
@@ -2,6 +2,7 @@ import React, { forwardRef } from "react";
2
2
  import {
3
3
  Button as MantineButton,
4
4
  type ButtonProps as MantineButtonProps,
5
+ createPolymorphicComponent,
5
6
  } from "@mantine/core";
6
7
  import {
7
8
  filterStylingProps,
@@ -26,97 +27,108 @@ function hasVisibleChildren(children: React.ReactNode): boolean {
26
27
  return true;
27
28
  }
28
29
 
29
- export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
30
- function Button(
31
- {
32
- variant = "solid",
33
- size = "default",
34
- icon,
35
- children,
36
- overStyled = false,
37
- ...rest
38
- },
39
- ref,
40
- ) {
41
- const mapVariant = {
42
- solid: "filled",
43
- outline: "outline",
44
- text: "subtle",
45
- } as const;
30
+ const _Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
31
+ {
32
+ variant = "solid",
33
+ size = "default",
34
+ icon,
35
+ children,
36
+ overStyled = false,
37
+ ...rest
38
+ },
39
+ ref,
40
+ ) {
41
+ const mapVariant = {
42
+ solid: "filled",
43
+ outline: "outline",
44
+ text: "subtle",
45
+ } as const;
46
46
 
47
- const mapSize = {
48
- default: "md",
49
- small: "sm",
50
- } as const;
47
+ const mapSize = {
48
+ default: "md",
49
+ small: "sm",
50
+ } as const;
51
51
 
52
- const sanitizedProps = filterStylingProps(rest, overStyled);
53
- const restRecord = sanitizedProps as Record<string, unknown>;
52
+ const sanitizedProps = filterStylingProps(rest, overStyled);
53
+ const restRecord = sanitizedProps as Record<string, unknown>;
54
54
 
55
- // Explicitly delete blocked semantic expansion dimension props
56
- delete restRecord["fullWidth"];
55
+ // Explicitly delete blocked semantic expansion dimension props
56
+ delete restRecord["fullWidth"];
57
57
 
58
- const hasLeftSection = !!icon || !!restRecord["leftSection"];
59
- const hasRightSection = !!restRecord["rightSection"];
60
- const isIconOnly =
61
- (hasLeftSection || hasRightSection) && !hasVisibleChildren(children);
58
+ const hasLeftSection = !!icon || !!restRecord["leftSection"];
59
+ const hasRightSection = !!restRecord["rightSection"];
60
+ const isIconOnly =
61
+ (hasLeftSection || hasRightSection) && !hasVisibleChildren(children);
62
62
 
63
- if (
64
- typeof process !== "undefined" &&
65
- process.env.NODE_ENV !== "production" &&
66
- isIconOnly &&
67
- !restRecord["aria-label"]
68
- ) {
69
- console.warn(
70
- '[Recursica Button] Icon-only buttons must provide an accessible name. Pass aria-label (e.g. aria-label="Submit").',
71
- );
72
- }
63
+ if (
64
+ typeof process !== "undefined" &&
65
+ process.env.NODE_ENV !== "production" &&
66
+ isIconOnly &&
67
+ !restRecord["aria-label"]
68
+ ) {
69
+ console.warn(
70
+ '[Recursica Button] Icon-only buttons must provide an accessible name. Pass aria-label (e.g. aria-label="Submit").',
71
+ );
72
+ }
73
73
 
74
- const mergedClassNames: Partial<Record<string, string>> = {
75
- root: styles.root,
76
- section: styles.section,
77
- label: styles.label,
78
- };
74
+ const mergedClassNames: Partial<Record<string, string>> = {
75
+ root: styles.root,
76
+ section: styles.section,
77
+ label: styles.label,
78
+ };
79
79
 
80
- const classNamesProp = restRecord.classNames;
81
- if (
82
- classNamesProp &&
83
- typeof classNamesProp === "object" &&
84
- !Array.isArray(classNamesProp)
85
- ) {
86
- const o = classNamesProp as Partial<Record<string, string>>;
87
- mergedClassNames.root = o.root ? `${styles.root} ${o.root}` : styles.root;
88
- mergedClassNames.section = o.section ?? styles.section;
89
- mergedClassNames.label = o.label ?? styles.label;
90
- }
80
+ const classNamesProp = restRecord.classNames;
81
+ if (
82
+ classNamesProp &&
83
+ typeof classNamesProp === "object" &&
84
+ !Array.isArray(classNamesProp)
85
+ ) {
86
+ const o = classNamesProp as Partial<Record<string, string>>;
87
+ mergedClassNames.root = o.root ? `${styles.root} ${o.root}` : styles.root;
88
+ mergedClassNames.section = o.section ?? styles.section;
89
+ mergedClassNames.label = o.label ?? styles.label;
90
+ }
91
91
 
92
- const classNameProp = restRecord.className as string | undefined;
93
- const finalClass = classNameProp
94
- ? `${styles.root} ${classNameProp}`
95
- : styles.root;
92
+ const classNameProp = restRecord.className as string | undefined;
93
+ const finalClass = classNameProp
94
+ ? `${styles.root} ${classNameProp}`
95
+ : styles.root;
96
96
 
97
- return (
98
- <MantineButton
99
- ref={ref}
100
- className={finalClass}
101
- classNames={mergedClassNames}
102
- variant={mapVariant[variant]}
103
- size={mapSize[size]}
104
- leftSection={
105
- icon != null ? (
106
- <span className={styles.iconWrapper} aria-hidden>
107
- {icon}
108
- </span>
109
- ) : undefined
110
- }
111
- data-variant={variant}
112
- data-size={size}
113
- {...(isIconOnly ? { "data-icon-only": "" } : {})}
114
- {...sanitizedProps}
115
- >
116
- <span className={styles.labelText}>{children}</span>
117
- </MantineButton>
118
- );
119
- },
120
- );
97
+ return (
98
+ <MantineButton
99
+ ref={ref}
100
+ className={finalClass}
101
+ classNames={mergedClassNames}
102
+ variant={mapVariant[variant]}
103
+ size={mapSize[size]}
104
+ leftSection={
105
+ icon != null ? (
106
+ <span className={styles.iconWrapper} aria-hidden>
107
+ {icon}
108
+ </span>
109
+ ) : undefined
110
+ }
111
+ data-variant={variant}
112
+ data-size={size}
113
+ {...(isIconOnly ? { "data-icon-only": "" } : {})}
114
+ {...sanitizedProps}
115
+ >
116
+ <span className={styles.labelText}>{children}</span>
117
+ </MantineButton>
118
+ );
119
+ });
120
+ _Button.displayName = "Button";
121
121
 
122
- Button.displayName = "Button";
122
+ /**
123
+ * Recursica Button component wrapping Mantine's Button.
124
+ *
125
+ * Supports polymorphism via the `component` prop or `renderRoot` for custom element rendering.
126
+ * @example
127
+ * ```tsx
128
+ * <Button component="a" href="/dashboard">Navigate</Button>
129
+ * <Button renderRoot={(props) => <Link to="/home" {...props} />}>Home</Button>
130
+ * ```
131
+ */
132
+ export const Button = createPolymorphicComponent<"button", ButtonProps>(
133
+ _Button,
134
+ );
@@ -3,6 +3,7 @@ import {
3
3
  Card as MantineCard,
4
4
  type CardProps as MantineCardProps,
5
5
  type CardSectionProps as MantineCardSectionProps,
6
+ createPolymorphicComponent,
6
7
  } from "@mantine/core";
7
8
  import {
8
9
  filterStylingProps,
@@ -162,15 +163,34 @@ export const CardContent = forwardRef<HTMLDivElement, CardContentProps>(
162
163
  CardContent.displayName = "CardContent";
163
164
 
164
165
  // ==== DOT NOTATION EXPORT ====
165
- type CardComponent = typeof CardBase & {
166
+
167
+ /**
168
+ * Recursica Card component wrapping Mantine's Card (Paper).
169
+ *
170
+ * Supports polymorphism via the `component` prop or `renderRoot` for custom element rendering.
171
+ * Use dot-notation sub-components for structured card layouts.
172
+ */
173
+ const PolymorphicCard = createPolymorphicComponent<
174
+ "div",
175
+ CardProps,
176
+ {
177
+ Section: typeof CardSection;
178
+ Header: typeof CardHeader;
179
+ Footer: typeof CardFooter;
180
+ Content: typeof CardContent;
181
+ }
182
+ >(CardBase);
183
+
184
+ // Attach static components for dot-notation access
185
+ const _card = PolymorphicCard as Record<string, unknown>;
186
+ _card.Section = CardSection;
187
+ _card.Header = CardHeader;
188
+ _card.Footer = CardFooter;
189
+ _card.Content = CardContent;
190
+
191
+ export const Card = PolymorphicCard as typeof PolymorphicCard & {
166
192
  Section: typeof CardSection;
167
193
  Header: typeof CardHeader;
168
194
  Footer: typeof CardFooter;
169
195
  Content: typeof CardContent;
170
196
  };
171
-
172
- export const Card = CardBase as CardComponent;
173
- Card.Section = CardSection;
174
- Card.Header = CardHeader;
175
- Card.Footer = CardFooter;
176
- Card.Content = CardContent;
@@ -2,6 +2,7 @@ import React, { forwardRef } from "react";
2
2
  import {
3
3
  Flex as MantineFlex,
4
4
  type FlexProps as MantineFlexProps,
5
+ createPolymorphicComponent,
5
6
  } from "@mantine/core";
6
7
  import {
7
8
  filterStylingProps,
@@ -27,7 +28,7 @@ export type FlexProps = RecursicaOverStyled<
27
28
  MantineFlexProps & RecursicaFlexProps
28
29
  >;
29
30
 
30
- export const Flex = forwardRef<HTMLDivElement, FlexProps>(function Flex(
31
+ const _Flex = forwardRef<HTMLDivElement, FlexProps>(function Flex(
31
32
  { children, overStyled = false, gap = "rec-default", ...rest },
32
33
  ref,
33
34
  ) {
@@ -64,5 +65,16 @@ export const Flex = forwardRef<HTMLDivElement, FlexProps>(function Flex(
64
65
  </MantineFlex>
65
66
  );
66
67
  });
68
+ _Flex.displayName = "Flex";
67
69
 
68
- Flex.displayName = "Flex";
70
+ /**
71
+ * Recursica Flex layout wrapper.
72
+ *
73
+ * Supports polymorphism via the `component` prop or `renderRoot` for custom element rendering.
74
+ * @example
75
+ * ```tsx
76
+ * <Flex component="nav">...</Flex>
77
+ * <Flex component="section">...</Flex>
78
+ * ```
79
+ */
80
+ export const Flex = createPolymorphicComponent<"div", FlexProps>(_Flex);
@@ -0,0 +1,78 @@
1
+ # Menu – Implementation Notes
2
+
3
+ Decisions and design tweaks strictly tailored for the UI Kit's Menu wrapped against `@mantine/core`. This is a living document that tracks _why_ specific logic decisions exist.
4
+
5
+ ---
6
+
7
+ ## 1. Composable API Preservation (1:1 Mapping)
8
+
9
+ **Decision:** We maintain the exact library composition API structure (`<Menu>`, `<Menu.Target>`, `<Menu.Dropdown>`, `<Menu.Item>`, `<Menu.Divider>`, `<Menu.Label>`, `<Menu.Sub>`, `<Menu.Sub.Target>`, `<Menu.Sub.Item>`, `<Menu.Sub.Dropdown>`) as a 1:1 React component mapping.
10
+
11
+ **Implementation:** Mantine's Menu internally manages WAI-ARIA role assignments (`role="menu"`, `role="menuitem"`, `aria-haspopup`, `aria-expanded`, `aria-controls`), keyboard navigation (arrow keys, Enter, Escape), and focus trapping natively across its composable hierarchy. By preserving the exact sub-component tree, Recursica safely adopts all of these accessibility behaviors without reimplementation.
12
+
13
+ ---
14
+
15
+ ## 2. Hover State Overlay Technique
16
+
17
+ **Decision:** We nullify Mantine's native hover background on `Menu.Item` and exclusively utilize Recursica's hover structure via a `::after` pseudo-element overlay.
18
+
19
+ **Implementation:** The `.item::after` pseudo-object dynamically pulls `hover-color` & `hover-opacity` bindings from the Recursica token system. Mantine natively changes `background-color` on item hover which would override our token-driven colors. We enforce `background-color` to remain the unselected-item background on hover, then layer our pseudo-overlay on top. This is the same technique used in the Accordion component.
20
+
21
+ ---
22
+
23
+ ## 3. Selected vs Unselected Item States
24
+
25
+ **Decision:** Menu items map to Recursica's `selected-item` and `unselected-item` color token groups.
26
+
27
+ **Implementation:** The CSS module defaults all items to `unselected-item_*` tokens (background, text, opacity). Items with `[data-selected]` switch to `selected-item_*` tokens. This mapping is natively driven by Mantine's internal state tracking without React state hooks.
28
+
29
+ ---
30
+
31
+ ## 4. `color` Prop Stripping
32
+
33
+ **Decision:** Mantine's `color` prop on `Menu.Item` (used for semantics like "danger/red") is explicitly stripped in strict mode.
34
+
35
+ **Implementation:** The `color` prop is deleted from the sanitized props when `overStyled` is `false`. This enforces strict design token adherence — all item colors come from the CSS module referencing Recursica variables. Developers requiring custom color semantics must either:
36
+
37
+ 1. Use `overStyled={true}` as an explicit escape hatch
38
+ 2. Contribute a proper Recursica variant to the token system
39
+
40
+ **Rationale:** The Recursica token set does not currently include danger-specific or semantic-color variants for menu items. Allowing arbitrary `color` values would break design system consistency.
41
+
42
+ ---
43
+
44
+ ## 5. Menu.Target Pass-Through
45
+
46
+ **Decision:** `Menu.Target` is a transparent pass-through with no styling applied.
47
+
48
+ **Implementation:** The target wrapper exists solely to manage Mantine's ref forwarding and event binding for the trigger element. No `filterStylingProps` or CSS module classes are applied — the trigger's appearance is entirely controlled by whatever component the integrator places inside it (e.g., `<Button>`).
49
+
50
+ ---
51
+
52
+ ## 6. Sub-Menu Support
53
+
54
+ **Decision:** We wrap the full Mantine sub-menu hierarchy (`Menu.Sub`, `Menu.Sub.Target`, `Menu.Sub.Item`, `Menu.Sub.Dropdown`).
55
+
56
+ **Implementation:** Sub-menu components inherit the same CSS module classes as their top-level counterparts since the Recursica token set does not distinguish sub-menu-specific styling. `Menu.Sub.Item` also strips the `color` prop in strict mode, consistent with `Menu.Item`. The sub-menu dropdown portal inherits the same `classNames` from the root Menu's `classNames` mapping.
57
+
58
+ ---
59
+
60
+ ## 7. Dropdown Container Padding
61
+
62
+ **Decision:** The dropdown container uses `divider-item-gap` as its internal padding.
63
+
64
+ **Implementation:** This ensures consistent spacing between the dropdown border and its content items. The gap token (`4px` by default) creates a subtle inset that visually separates items from the container edge, matching the Figma design specifications.
65
+
66
+ ---
67
+
68
+ ## 8. Minimal CSS Override Philosophy
69
+
70
+ **Decision:** The CSS module only overrides visual design tokens (colors, typography, spacing, borders, shadows). All structural layout properties (flex, cursor, pointer-events, box-sizing, etc.) are deferred to Mantine's native behavior.
71
+
72
+ **Implementation:** Unlike form-field components (e.g., Dropdown/TextField) which require deep structural overrides to strip Mantine's macro wrappers, the Menu is an overlay component where Mantine's native layout is already correct. We avoid setting:
73
+
74
+ - `overflow` on the dropdown (Mantine renders sub-menu dropdowns inside the parent DOM tree using Floating UI absolute positioning — setting overflow clips them)
75
+ - `display`, `align-items`, `width`, `cursor` on items (Mantine's button-based items already handle this)
76
+ - `pointer-events` on disabled items (Mantine handles disabled natively)
77
+
78
+ **Rationale:** Early iterations included aggressive structural resets (like `overflow: hidden`, `box-sizing: border-box`, `margin: 0`) cargo-culted from the Dropdown component. These caused sub-menus to render clipped inside the parent dropdown with scrollbars. The lesson: default to Mantine's native behavior and only override what the Recursica token system explicitly needs to control.
@@ -0,0 +1,244 @@
1
+ /* HARDCODED VALUES:
2
+ - border-style: solid. Structural rendering rule for the dropdown border (Mantine uses Paper which may not set border natively).
3
+ - opacity: 0.5 on disabled items. Recursica has no dedicated disabled-opacity token for menu items.
4
+ - NOTE: overflow is intentionally NOT set on .dropdown. Mantine renders sub-menu dropdowns
5
+ inside the parent dropdown DOM tree using Floating UI absolute positioning. Setting
6
+ overflow: hidden clips sub-menus; overflow-y: auto causes unwanted scrollbars.
7
+ - All structural layout (flex, cursor, pointer-events on disabled) is deferred to Mantine's
8
+ native behavior. We only override visual design tokens (colors, typography, spacing, borders).
9
+ */
10
+
11
+ /* ======================================
12
+ DROPDOWN CONTAINER
13
+ ====================================== */
14
+
15
+ .dropdown {
16
+ background-color: var(
17
+ --recursica_ui-kit_components_menu_properties_colors_background
18
+ );
19
+ border-style: solid; /* HARDCODE: Mantine Paper does not set border-style natively */
20
+ border-width: var(--recursica_ui-kit_components_menu_properties_border-size);
21
+ border-color: var(
22
+ --recursica_ui-kit_components_menu_properties_colors_border-color
23
+ );
24
+ border-radius: var(
25
+ --recursica_ui-kit_components_menu_properties_border-radius
26
+ );
27
+ box-shadow: var(--recursica_ui-kit_components_menu_properties_elevation);
28
+
29
+ min-width: var(--recursica_ui-kit_components_menu_properties_min-width);
30
+ max-width: var(--recursica_ui-kit_components_menu_properties_max-width);
31
+
32
+ padding: var(
33
+ --recursica_ui-kit_components_menu-item_properties_divider-item-gap
34
+ );
35
+ }
36
+
37
+ /* ======================================
38
+ MENU ITEM
39
+ ====================================== */
40
+
41
+ .item {
42
+ position: relative;
43
+
44
+ /* Geometry */
45
+ padding: var(
46
+ --recursica_ui-kit_components_menu-item_properties_vertical-padding
47
+ )
48
+ var(--recursica_ui-kit_components_menu-item_properties_horizontal-padding);
49
+ border-radius: var(
50
+ --recursica_ui-kit_components_menu-item_properties_border-radius
51
+ );
52
+
53
+ /* Typography */
54
+ font-family: var(
55
+ --recursica_ui-kit_components_menu-item_properties_text_font-family
56
+ );
57
+ font-size: var(
58
+ --recursica_ui-kit_components_menu-item_properties_text_font-size
59
+ );
60
+ font-style: var(
61
+ --recursica_ui-kit_components_menu-item_properties_text_font-style
62
+ );
63
+ font-weight: var(
64
+ --recursica_ui-kit_components_menu-item_properties_text_font-weight
65
+ );
66
+ letter-spacing: var(
67
+ --recursica_ui-kit_components_menu-item_properties_text_letter-spacing
68
+ );
69
+ line-height: var(
70
+ --recursica_ui-kit_components_menu-item_properties_text_line-height
71
+ );
72
+ text-decoration: var(
73
+ --recursica_ui-kit_components_menu-item_properties_text_text-decoration
74
+ );
75
+ text-transform: var(
76
+ --recursica_ui-kit_components_menu-item_properties_text_text-transform
77
+ );
78
+
79
+ /* Default State: Unselected */
80
+ background-color: var(
81
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_background
82
+ );
83
+ color: var(
84
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_text
85
+ );
86
+ opacity: var(
87
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_opacity
88
+ );
89
+ }
90
+
91
+ /* Override Mantine's native hover background to use our overlay technique */
92
+ .item:hover {
93
+ background-color: var(
94
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_background
95
+ );
96
+ }
97
+
98
+ /* Hover overlay using ::after pseudo-element (same technique as Accordion) */
99
+ .item::after {
100
+ content: "";
101
+ position: absolute;
102
+ inset: 0;
103
+ border-radius: inherit;
104
+ z-index: 0;
105
+ pointer-events: none;
106
+ background-color: var(
107
+ --recursica_ui-kit_components_menu-item_properties_hover-color
108
+ );
109
+ opacity: 0;
110
+ transition: opacity 150ms ease;
111
+ }
112
+
113
+ .item:hover:not([data-disabled])::after {
114
+ opacity: var(
115
+ --recursica_ui-kit_components_menu-item_properties_hover-opacity,
116
+ 0.1
117
+ );
118
+ }
119
+
120
+ /* Selected item state */
121
+ .item[data-selected] {
122
+ background-color: var(
123
+ --recursica_ui-kit_components_menu-item_properties_colors_selected-item_background
124
+ );
125
+ color: var(
126
+ --recursica_ui-kit_components_menu-item_properties_colors_selected-item_text
127
+ );
128
+ opacity: var(
129
+ --recursica_ui-kit_components_menu-item_properties_colors_selected-item_opacity
130
+ );
131
+ }
132
+
133
+ /* Hovered item state (keyboard navigation) */
134
+ .item[data-hovered] {
135
+ background-color: var(
136
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_background
137
+ );
138
+ }
139
+ .item[data-hovered]::after {
140
+ opacity: var(
141
+ --recursica_ui-kit_components_menu-item_properties_hover-opacity,
142
+ 0.1
143
+ );
144
+ }
145
+
146
+ /* Disabled item */
147
+ .item[data-disabled] {
148
+ /* HARDCODE: 0.5 opacity fallback; no dedicated disabled-opacity token for menu items */
149
+ opacity: 0.5;
150
+ }
151
+
152
+ /* ======================================
153
+ ITEM LABEL
154
+ ====================================== */
155
+
156
+ .itemLabel {
157
+ position: relative;
158
+ z-index: 1;
159
+ color: inherit;
160
+ }
161
+
162
+ /* ======================================
163
+ ITEM SECTION (LEFT / RIGHT ICONS)
164
+ ====================================== */
165
+
166
+ .itemSection {
167
+ position: relative;
168
+ z-index: 1;
169
+ color: inherit;
170
+ }
171
+
172
+ /* ======================================
173
+ DIVIDER
174
+ ====================================== */
175
+
176
+ .divider {
177
+ height: var(
178
+ --recursica_ui-kit_components_menu-item_properties_divider-height
179
+ );
180
+ background-color: var(
181
+ --recursica_ui-kit_components_menu-item_properties_colors_divider-color
182
+ );
183
+ opacity: var(
184
+ --recursica_ui-kit_components_menu-item_properties_divider-opacity
185
+ );
186
+ margin: var(
187
+ --recursica_ui-kit_components_menu-item_properties_divider-item-gap
188
+ )
189
+ 0;
190
+ }
191
+
192
+ /* ======================================
193
+ SECTION LABEL
194
+ ====================================== */
195
+
196
+ .label {
197
+ padding: var(
198
+ --recursica_ui-kit_components_menu-item_properties_vertical-padding
199
+ )
200
+ var(--recursica_ui-kit_components_menu-item_properties_horizontal-padding);
201
+
202
+ /* Supporting Text Typography */
203
+ font-family: var(
204
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_font-family
205
+ );
206
+ font-size: var(
207
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_font-size
208
+ );
209
+ font-style: var(
210
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_font-style
211
+ );
212
+ font-weight: var(
213
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_font-weight
214
+ );
215
+ letter-spacing: var(
216
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_letter-spacing
217
+ );
218
+ line-height: var(
219
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_line-height
220
+ );
221
+ text-decoration: var(
222
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_text-decoration
223
+ );
224
+ text-transform: var(
225
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_text-transform
226
+ );
227
+
228
+ color: var(
229
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_supporting-text-color
230
+ );
231
+ opacity: var(
232
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_supporting-text-opacity
233
+ );
234
+ }
235
+
236
+ /* ======================================
237
+ SUB-MENU CHEVRON
238
+ ====================================== */
239
+
240
+ .chevron {
241
+ position: relative;
242
+ z-index: 1;
243
+ color: inherit;
244
+ }