@recursica/mantine-adapter 0.36.0 → 0.38.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.
- package/CHANGELOG.md +28 -0
- package/README.md +3 -3
- package/dist/mantine-adapter.cjs +2 -2
- package/dist/mantine-adapter.cjs.map +1 -1
- package/dist/mantine-adapter.css +1 -1
- package/dist/mantine-adapter.js +2352 -2099
- package/dist/mantine-adapter.js.map +1 -1
- package/dist/src/components/Dropdown/BareDropdown.d.ts +19 -0
- package/dist/src/components/TimePicker/TimePicker.d.ts +9 -3
- package/dist/src/components/Tree/Tree.d.ts +5 -0
- package/dist/src/index.d.ts +1 -1
- package/docs/PHILOSOPHY.md +39 -0
- package/package.json +3 -2
- package/src/components/Accordion/USAGE.md +2 -41
- package/src/components/AutoComplete/USAGE.md +2 -18
- package/src/components/Avatar/USAGE.md +0 -27
- package/src/components/Badge/USAGE.md +3 -6
- package/src/components/Breadcrumb/USAGE.md +1 -5
- package/src/components/Button/Button.tsx +5 -0
- package/src/components/Button/IMPLEMENTATION_NOTES.md +8 -0
- package/src/components/Button/USAGE.md +5 -25
- package/src/components/Card/USAGE.md +4 -12
- package/src/components/Checkbox/USAGE.md +4 -20
- package/src/components/Chip/USAGE.md +3 -32
- package/src/components/DatePicker/USAGE.md +2 -12
- package/src/components/Dropdown/BareDropdown.tsx +85 -0
- package/src/components/Dropdown/Dropdown.tsx +12 -3
- package/src/components/Dropdown/USAGE.md +2 -6
- package/src/components/Flex/USAGE.md +1 -1
- package/src/components/FormControlWrapper/USAGE.md +3 -31
- package/src/components/Grid/USAGE.md +1 -1
- package/src/components/Group/USAGE.md +1 -1
- package/src/components/HoverCard/USAGE.md +3 -72
- package/src/components/Label/USAGE.md +8 -48
- package/src/components/Link/USAGE.md +4 -10
- package/src/components/Loader/USAGE.md +4 -23
- package/src/components/Menu/USAGE.md +3 -73
- package/src/components/Modal/USAGE.md +3 -3
- package/src/components/NumberInput/USAGE.md +5 -8
- package/src/components/Pagination/USAGE.md +0 -19
- package/src/components/Panel/USAGE.md +6 -95
- package/src/components/Popover/USAGE.md +6 -66
- package/src/components/ReadOnlyField/USAGE.md +2 -10
- package/src/components/SegmentedControl/USAGE.md +1 -15
- package/src/components/Slider/USAGE.md +1 -45
- package/src/components/Stack/USAGE.md +1 -1
- package/src/components/Switch/USAGE.md +1 -24
- package/src/components/TextArea/USAGE.md +2 -2
- package/src/components/TextField/USAGE.md +1 -17
- package/src/components/TimePicker/TIMEPICKER_IMPLEMENTATION_NOTES.md +72 -0
- package/src/components/TimePicker/TimePicker.module.css +225 -41
- package/src/components/TimePicker/TimePicker.stories.tsx +105 -4
- package/src/components/TimePicker/TimePicker.tsx +287 -7
- package/src/components/TimePicker/USAGE.md +23 -2
- package/src/components/Timeline/USAGE.md +2 -10
- package/src/components/Toast/USAGE.md +3 -33
- package/src/components/Tooltip/USAGE.md +7 -51
- package/src/components/Tree/IMPLEMENTATION_NOTES.md +31 -3
- package/src/components/Tree/Tree.module.css +84 -40
- package/src/components/Tree/Tree.stories.tsx +13 -0
- package/src/components/Tree/Tree.tsx +116 -27
- package/src/components/Tree/USAGE.md +18 -1
- package/src/index.ts +1 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SelectProps as MantineSelectProps } from '@mantine/core';
|
|
2
|
+
import { RecursicaOverStyled } from '../../utils/filterStylingProps';
|
|
3
|
+
/**
|
|
4
|
+
* Bare, unwrapped Select — no `FormControlWrapper`/`WithReadOnlyWrapper`, no label/assistiveText/
|
|
5
|
+
* error/required. Tied to the same `Dropdown.module.css` variables/classes as the public
|
|
6
|
+
* `Dropdown` component, so it looks identical, but is meant to be embedded inside another
|
|
7
|
+
* component that already owns its own `FormControlWrapper` (e.g. `TimePicker`'s AM/PM control) —
|
|
8
|
+
* nesting the full `Dropdown` there would double up `FormControl`/`FormControlLayout` wrapping.
|
|
9
|
+
*
|
|
10
|
+
* Not exported from this folder's `index.ts` — internal use only. Import it directly:
|
|
11
|
+
* `import { BareDropdown } from "../Dropdown/BareDropdown"`.
|
|
12
|
+
*/
|
|
13
|
+
export interface BareDropdownProps extends Omit<MantineSelectProps, "size" | "variant" | "radius" | "wrapperProps" | "label" | "description" | "error"> {
|
|
14
|
+
data: MantineSelectProps["data"];
|
|
15
|
+
/** Applies the error visual state (via `data-error`) — no error message is rendered here. */
|
|
16
|
+
error?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export type BareDropdownComponentProps = RecursicaOverStyled<BareDropdownProps>;
|
|
19
|
+
export declare const BareDropdown: import('react').ForwardRefExoticComponent<BareDropdownComponentProps & import('react').RefAttributes<HTMLInputElement>>;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { TimePickerProps as MantineTimePickerProps } from '@mantine/dates';
|
|
3
|
+
import { InputWrapperProps } from '@mantine/core';
|
|
4
|
+
import { ReadOnlyControlProps, RecursicaTimePickerProps as BaseRecursicaTimePickerProps } from '@recursica/adapter-common';
|
|
5
|
+
import { RecursicaOverStyled } from '../../utils/filterStylingProps';
|
|
6
|
+
import { RecursicaFormControlWrapperProps } from '../FormControlWrapper/FormControlWrapper';
|
|
7
|
+
export interface RecursicaTimePickerProps extends Omit<MantineTimePickerProps, "size" | "variant" | "radius" | "wrapperProps" | "format" | "min" | "max" | "amPmInputLabel" | "amPmLabels" | "amPmSelectProps" | "amPmRef" | "withDropdown" | "presets" | "maxDropdownContentHeight" | "scrollAreaProps" | "reverseTimeControlsList" | "popoverProps">, Pick<InputWrapperProps, "label" | "error" | "required" | "withAsterisk" | "id">, Omit<RecursicaFormControlWrapperProps, "controlMaxWidth" | "controlMinWidth">, ReadOnlyControlProps, BaseRecursicaTimePickerProps {
|
|
8
|
+
}
|
|
9
|
+
export type TimePickerProps = RecursicaOverStyled<RecursicaTimePickerProps>;
|
|
10
|
+
export declare const TimePicker: React.ForwardRefExoticComponent<TimePickerProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -9,5 +9,10 @@ export type TreeProps = RecursicaOverStyled<RecursicaTreeProps & Omit<React.Comp
|
|
|
9
9
|
* Wraps Mantine's `Tree` with a fully custom node renderer so every visual aspect (row box
|
|
10
10
|
* model, selected/unselected colors and typography, indent, item spacing) comes from
|
|
11
11
|
* Recursica's `tree` design tokens rather than Mantine's defaults.
|
|
12
|
+
*
|
|
13
|
+
* **Interaction pattern (fixed, not prop-configurable):** expand/collapse and select are
|
|
14
|
+
* independent — the chevron button toggles a node's subtree only, clicking the rest of a row
|
|
15
|
+
* (or pressing `Enter`/`Space`) selects it only, and `ArrowLeft`/`ArrowRight` toggle expansion
|
|
16
|
+
* only. See `RecursicaTreeProps` for the full breakdown.
|
|
12
17
|
*/
|
|
13
18
|
export declare const Tree: React.ForwardRefExoticComponent<TreeProps & React.RefAttributes<HTMLUListElement>>;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -217,4 +217,4 @@ export declare const Toast: typeof rawComponents.Toast;
|
|
|
217
217
|
export declare const Tooltip: typeof rawComponents.Tooltip;
|
|
218
218
|
export declare const TransferList: typeof rawComponents.TransferList;
|
|
219
219
|
export declare const Tree: typeof rawComponents.Tree;
|
|
220
|
-
export type { RecursicaCheckboxGroupProps, RecursicaDatePickerProps, RecursicaDropdownProps, RecursicaNumberInputProps, RecursicaRadioGroupProps, RecursicaReadOnlyFieldProps, RecursicaReadOnlyTextFieldProps, RecursicaSliderProps, RecursicaSwitchGroupProps, RecursicaTextAreaProps, RecursicaTextFieldProps, } from './components';
|
|
220
|
+
export type { RecursicaCheckboxGroupProps, RecursicaDatePickerProps, RecursicaDropdownProps, RecursicaNumberInputProps, RecursicaRadioGroupProps, RecursicaReadOnlyFieldProps, RecursicaReadOnlyTextFieldProps, RecursicaSliderProps, RecursicaSwitchGroupProps, RecursicaTextAreaProps, RecursicaTextFieldProps, RecursicaTimePickerProps, } from './components';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Recursica Mantine Adapter: Core Philosophy
|
|
2
|
+
|
|
3
|
+
Recursica's component architecture isn't just a wrapper; it's a strict enforcing layer over Mantine's massive API surface. Our primary goal is to ensure consistency, eliminate "design system rot," and provide clear boundaries for application developers using the UI Kit.
|
|
4
|
+
|
|
5
|
+
This document serves as the governing framework for why the `mantine-adapter` components are built the way they are.
|
|
6
|
+
|
|
7
|
+
## 1. Strict Separation of Props (The Unified Recursica Prop Layer)
|
|
8
|
+
|
|
9
|
+
Recursica has a **single universal API surface** internally regardless of whether we use Mantine or another underlying UI library.
|
|
10
|
+
|
|
11
|
+
- We decouple our visual properties natively. Instead of mapping perfectly to Mantine's variants `(solid, outline)`, we intentionally use Recursica's semantic and behavioral structures (e.g., `<Badge variant="alert" />`).
|
|
12
|
+
- We intentionally omit and strip complex underlying parameters if they collide with or circumvent our UI tokens (like stripping `--size` out of Mantine Badge when Recursica enforces a universal single size).
|
|
13
|
+
|
|
14
|
+
## 2. Component Wrappers (Leaving Mantine Alone)
|
|
15
|
+
|
|
16
|
+
We actively avoid mutating or patching Mantine source code or deeply hooking into the Mantine Theme object to apply our token system.
|
|
17
|
+
|
|
18
|
+
- We rely on standard DOM `module.css` bridging with strictly targeted `className`/`classNames` overrides.
|
|
19
|
+
- This creates total decoupled isolation: updating Mantine natively will not fracture our styles, and we avoid dealing with deep Emotion/styled-component theme clashing logic.
|
|
20
|
+
|
|
21
|
+
## 3. The `overStyled` Property
|
|
22
|
+
|
|
23
|
+
Mantine encourages deep styling access by injecting properties like `p` (padding), `bg` (background), `c` (color), or `styles`/`classNames` directly into component tags.
|
|
24
|
+
|
|
25
|
+
- By default, **Recursica components block all arbitrary styling vectors**. `className` maps, system styles, and inline logic are proactively stripped before they hit Mantine using central utility functions.
|
|
26
|
+
- **Why?** To prevent the design system from deteriorating over time as developers write one-off hotfixes into their TSX rendering blocks.
|
|
27
|
+
- **The Caveat:** We allow _external DOM layout positioning props_ (e.g., margin `m`, `mt`, `mb`, etc.) to pass through so developers can still structure components organically within their parent layouts.
|
|
28
|
+
|
|
29
|
+
### Escape Hatches
|
|
30
|
+
|
|
31
|
+
If a developer _strictly must_ heavily alter a component, they are required to explicitly declare `<Component overStyled={true} />`. This immediately raises a visible red flag during code reviews.
|
|
32
|
+
|
|
33
|
+
## 4. Expectations for External Developers (Modifying Recursica)
|
|
34
|
+
|
|
35
|
+
If a developer finds that a component does not fit their needs and styling must be modified, their path of execution should follow these principles sequentially:
|
|
36
|
+
|
|
37
|
+
1. **Leverage Native Mantine First:** If a Recursica component lacks the functionality or styling variant needed for a highly custom edge case (e.g., a massive marketing hero button), do not try to forcibly hack the Recursica component. Instead, import the raw underlying `Button` component directly from `@mantine/core` and style it manually. Use Recursica for standard systematic needs, and native libraries for isolated custom one-offs.
|
|
38
|
+
2. **Accept `overStyled` as Technical Debt:** If you must override the Recursica component immediately but intend to roll it back, use `overStyled={true}`. The expectation is that `overStyled` uses will eventually be replaced once the actual Recursica Figma variants are natively updated to accommodate your usecase, at which point `overStyled={true}` can be safely removed.
|
|
39
|
+
3. **Contribute to the Kit:** Avoid building private custom wrappers around Recursica components. If the system is missing a variant, that is a shared project deficit—raise a concern and have the variant integrated directly into the universal token libraries!
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"url": "git+https://github.com/borderux/recursica.git",
|
|
14
14
|
"directory": "packages/mantine-adapter"
|
|
15
15
|
},
|
|
16
|
-
"version": "0.
|
|
16
|
+
"version": "0.38.0",
|
|
17
17
|
"type": "module",
|
|
18
18
|
"main": "./dist/mantine-adapter.cjs",
|
|
19
19
|
"module": "./dist/mantine-adapter.js",
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
"USAGE.md",
|
|
36
36
|
"ARCHITECTURE.md",
|
|
37
37
|
"SETUP.md",
|
|
38
|
-
"OVERSTYLING.md"
|
|
38
|
+
"OVERSTYLING.md",
|
|
39
|
+
"docs/PHILOSOPHY.md"
|
|
39
40
|
],
|
|
40
41
|
"keywords": [
|
|
41
42
|
"react",
|
|
@@ -46,45 +46,6 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
46
46
|
|
|
47
47
|
## 4. Key Integration Features & Constraints
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
### Composition Patterns
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
**Implementation:** Avoid rigid raw parameter dumps. Mantine dynamically injects explicit `id` logic, keyboard ARIA mapping, and focus tracking correctly across `Control` to `Panel` DOM connections natively. By exposing the hierarchical mapping 1:1, Recursica safely adopts these capabilities. However, to strictly support Recursica's unified prop mapping interface:
|
|
53
|
-
|
|
54
|
-
- **Auto-Construction:** If integrators natively pass `title` and/or `leftIcon` props into `<AccordionItem>`, the component structurally auto-generates the internal `AccordionControl` sub-wrappers mapping the text and SVG natively, whilst treating `children` implicitly as the Panel contents.
|
|
55
|
-
- **Graceful Falldown:** If `title` is heavily omitted, the node immediately falls backward into raw Mantine composability expecting integrators mapped `<Accordion.Control>` entirely manually.
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## 2. Default Configuration Reset (`unstyled`)
|
|
60
|
-
|
|
61
|
-
**Decision:** We strip Mantine's inner styles away completely from Accordion mappings by leveraging React's default `variant="unstyled"`.
|
|
62
|
-
**Implementation:** In `Accordion.tsx`, `<MantineAccordion>` binds `variant="unstyled"`. This effectively deletes Mantine's precomputed padding, borders, and shadow mappings allowing our targeted `classNames` inside `Accordion.module.css` to become the exact source of foundational truth without "fighting" `!important` tags or unpredictable flex-layouts inherited globally.
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## 3. Strict SVG Icons Wrapper (`.iconLeftWrapper`)
|
|
67
|
-
|
|
68
|
-
**Decision:** Identical logic enforced as seen within Buttons: SVG scales dynamically inside `.mantine-leftSection` based on SVGs internal definition boundaries potentially corrupting header gaps.
|
|
69
|
-
**Implementation:** `AccordionControl` captures `<span className={styles.iconLeftWrapper} aria-hidden>` forcing `object-fit: contain` mapped exactly to the `properties_icon-left-size` Recursica dimension token forcing integrator SVG overrides inline perfectly.
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## 4. Transparent Global Hover Fixes
|
|
74
|
-
|
|
75
|
-
**Decision:** We nullify internal Mantine button hover actions and exclusively utilize Recursica's hover structure natively.
|
|
76
|
-
**Implementation:** We construct `.control::after` pseudo-objects dynamically pulling our `hover-color` & `hover-opacity` bindings. Mantine's native action sets `.control:hover { background-color: var(...) }` dynamically causing internal layer overlaps. We enforce `background-color: transparent` strictly overriding it, preserving our pseudo-overlay layer-cascade cleanly.
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## 5. Active Target Hooks (`[data-active]`)
|
|
81
|
-
|
|
82
|
-
**Decision:** Collapsed and expanded state tracking requires separate background maps across `AccordionItem`.
|
|
83
|
-
**Implementation:** Rather than syncing React `useState` hooks matching `Accordion.value`, we defer to Mantine's inherent DOM mapping: `.item[data-active]` implicitly triggers exactly when Mantine registers an expansion state swap changing values down dynamically on the element layer, perfectly binding to `--recursica_..._background-expanded`.
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## 6. Nullifying Isolated State Bounds (`open` boolean)
|
|
88
|
-
|
|
89
|
-
**Decision:** We do not bind isolated `open={true}` state properties natively on individual `<AccordionItem>` configurations.
|
|
90
|
-
**Implementation:** Recursica natively dictates an item-level `open` tracking mapping. However, internally mapping boolean flags structurally across specific tree nodes heavily corrupts Mantine's DOM layout algorithms mapping parent-driven transition listeners. Mantine forces all expanded-height logic to run symmetrically off the `<Accordion value="...">` string matching array to accurately bind ARIA transitions. We explicitly ignore isolated item `<AccordionItem open={...}>` booleans to shield the rendering sequence cleanly.
|
|
51
|
+
`Accordion.Item` supports two ways of providing content: pass `title` (and optionally `leftIcon`) directly on `Accordion.Item` for a simple control/panel pair, with `children` treated as the panel content; or omit `title` and compose manually with `Accordion.Control` and `Accordion.Panel` for full control over the control's contents.
|
|
@@ -45,22 +45,6 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
45
45
|
|
|
46
46
|
## 4. Key Integration Features & Constraints
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
### Known Limitation: Active Option Highlight
|
|
49
49
|
|
|
50
|
-
The
|
|
51
|
-
|
|
52
|
-
## CSS Layout Execution
|
|
53
|
-
|
|
54
|
-
The baseline structure maps identical `HARDCODED VALUES` as standard text inputs (`border-width: 1px`, `display: flex`). The `.root` dynamically overrides the `--input-left-section-size` and `--input-right-section-size` to accurately allocate whitespace for prepended or appended icons natively matching the underlying UI token layout system securely.
|
|
55
|
-
|
|
56
|
-
## Dropdown Styling
|
|
57
|
-
|
|
58
|
-
The Mantine `<Autocomplete>` dropdown menu and options are styled strictly using native UI-Kit variables mapping border radii, shadows, and base colors (`.dropdown` and `.option`).
|
|
59
|
-
|
|
60
|
-
## State Cascade Architecture
|
|
61
|
-
|
|
62
|
-
Focus, errors, and disabled visual states are enforced explicitly via the outer `<FormControlWrapper>` boundary emitting context down structurally (`[data-error]`, `[data-disabled]`) and evaluated efficiently against scoped nested selectors natively inside `AutoComplete.module.css`.
|
|
63
|
-
|
|
64
|
-
## Missing Active Option Color
|
|
65
|
-
|
|
66
|
-
Currently, there is no explicit JSON token for the background color of an active/hovered option in the AutoComplete dropdown. We temporarily map `.option:hover` and `.option[data-combobox-active]` to the `--recursica_ui-kit_components_autocomplete_variants_states_focus_properties_colors_background` variable. Because this variable maps to the base field background, the highlight is currently invisible. This will be updated once the correct token is added to the UI kit.
|
|
50
|
+
The background highlight for a hovered or active option in the dropdown is not currently visible. This will be addressed in a future update.
|
|
@@ -36,30 +36,3 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
36
36
|
> - **Anti-override protection**: Rogues style injections (like inline `style` or arbitrary `className`) are automatically blocked by our prop layer unless `overStyled={true}` is explicitly provided.
|
|
37
37
|
> - **No Direct Layers**: Do not pass a `layer` prop to this component. To place it on a specific visual layer, wrap it in a `<Layer layer={0|1|2|3}>` component natively.
|
|
38
38
|
> - **Variables and Theming**: Styling is entirely determined by local CSS variables defined in `recursica_variables_scoped.css` and mapped in the component's CSS module.
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
## 4. Key Integration Features & Constraints
|
|
43
|
-
|
|
44
|
-
## Architecture Decisions
|
|
45
|
-
|
|
46
|
-
The `Avatar` component is an adapter over Mantine's `Avatar`. To ensure adherence to the `COMPONENT_GUIDE_WALKTHROUGH.md`:
|
|
47
|
-
|
|
48
|
-
- We do not wrap `MantineAvatar` in any custom standard `div` elements, preserving DOM structure.
|
|
49
|
-
- All styles strictly pull from explicit `--recursica_ui-kit_components_avatar_*` CSS tokens.
|
|
50
|
-
|
|
51
|
-
## Structural Workarounds
|
|
52
|
-
|
|
53
|
-
### Implicit `data-style`
|
|
54
|
-
|
|
55
|
-
Mantine's Avatar implicitly renders an image, an icon, or a text node based on the properties passed (`src`, `var`, `children`).
|
|
56
|
-
Recursica Tokens split Avatar styling distinctly across three separate categories: `image`, `icon`, and `text`.
|
|
57
|
-
To correctly map these variables, our React component observes standard prop states and manually injects a `data-style="image|icon|text"` onto the root. The `Avatar.module.css` explicitly gates padding and generic sizing modifiers under these `data-style` attributes.
|
|
58
|
-
|
|
59
|
-
### Flex Layout & Internal Spans
|
|
60
|
-
|
|
61
|
-
Since Avatar children (icons or initials) require robust centering that might differ heavily across Recursica size mappings, all child content defaults to being wrapped in `span` elements (either `.textWrapper` or `.iconWrapper`). These spans enforce 100% height and flex formatting independent of the Mantine container constraints.
|
|
62
|
-
|
|
63
|
-
### CSS Reset Hacks
|
|
64
|
-
|
|
65
|
-
Noticeable `/* HARDCODE: ... */` hacks are deployed within `.root` to completely zero-out Mantine's `--avatar-bg` and internal variables statically since Recursica handles background-colors inherently via the CSS variants cascade.
|
|
@@ -43,16 +43,13 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
43
43
|
|
|
44
44
|
## 4. Key Integration Features & Constraints
|
|
45
45
|
|
|
46
|
-
## 1.
|
|
46
|
+
## 1. Sizing
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
Badge does not currently support a `size` prop; badges render at a single fixed size.
|
|
49
49
|
|
|
50
50
|
## 2. Intent-Based Variants
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
- Default is arbitrarily mapped to `primary-color` as we lack a pure `neutral` schema right now.
|
|
55
|
-
- `variant` mapped to underlying Mantine prop has been hardcoded to `filled`, since the Recursica coloring fully replaces the Mantine DOM.
|
|
52
|
+
Badge exposes a `variant` prop with intent-based values (`alert`, `primary-color`, `success`, `warning`) rather than Mantine's `outline`/`filled`/`light` style options. The default variant is `primary-color`.
|
|
56
53
|
|
|
57
54
|
## 3. The `overStyled` Prop
|
|
58
55
|
|
|
@@ -47,11 +47,7 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
47
47
|
|
|
48
48
|
## Missing Variants and Sizes
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
## Gap Styling
|
|
53
|
-
|
|
54
|
-
We attach `gap` to `.root` directly within `.module.css`. Mantine's inner `separator` divs can natively accept our CSS variables for structural layout.
|
|
50
|
+
Breadcrumb does not currently support `size` or `variant` props.
|
|
55
51
|
|
|
56
52
|
## Composition and Separators
|
|
57
53
|
|
|
@@ -101,6 +101,11 @@ const _Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
|
|
101
101
|
const finalClass = classNameProp
|
|
102
102
|
? `${styles.root} ${classNameProp}`
|
|
103
103
|
: styles.root;
|
|
104
|
+
// className is merged explicitly above — don't let the {...sanitizedProps} spread below
|
|
105
|
+
// silently overwrite finalClass with just the caller's own class (same bug class as
|
|
106
|
+
// mantine-adapter's Dropdown/BareDropdown.tsx had). Masked here today since `classNames.root`
|
|
107
|
+
// (a separate prop, unaffected) also carries styles.root — but a real latent bug regardless.
|
|
108
|
+
delete restRecord["className"];
|
|
104
109
|
|
|
105
110
|
const userLoaderProps = restRecord.loaderProps as
|
|
106
111
|
| Record<string, unknown>
|
|
@@ -59,3 +59,11 @@ Mantine's `.mantine-Button-label` flex centering breaks primitive truncation log
|
|
|
59
59
|
**Decision:** When `loading={true}` is passed to the Button, the component explicitly forces `disabled={true}` natively on the underlying element.
|
|
60
60
|
|
|
61
61
|
**Implementation:** This ensures that loading buttons automatically inherit the brand theme disabled opacities (via the `:disabled` CSS pseudo-class) rather than relying solely on Mantine's native `data-disabled` dataset logic, which may not trigger the strict visual fade required by the Recursica design system.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## `className` overwrite bug (Matt Massey, 2026-08-08)
|
|
66
|
+
|
|
67
|
+
**Bug:** with `overStyled` and a custom `className` (surfaced by Tree embedding a `Button` for its expand chevron — see `Tree/IMPLEMENTATION_NOTES.md`), `finalClass` (`` `${styles.root} ${classNameProp}` ``) was set explicitly on `<MantineButton>`, but `{...sanitizedProps}` was spread _after_ it — and `sanitizedProps` still contained the original, unmodified `className` key, since it had only been _read_, never deleted. The later spread would silently overwrite `finalClass` with just the caller's own class. Same bug class as `Dropdown.tsx`/`BareDropdown.tsx` had.
|
|
68
|
+
|
|
69
|
+
**Why it wasn't visible here:** `classNames={{root: mergedClassNames.root, ...}}` is a _separate_ Mantine prop from the plain `className` string, unaffected by the overwrite, and `mergedClassNames.root` always includes `styles.root` independently — so the root element kept its Recursica styling regardless of the bug. mui-adapter's equivalent `Button.tsx` has no such secondary path (`@mui/material` only has a plain `className`), so the identical mistake there was fully visible (chevron rendered in MUI's own default color). Fixed in both regardless, since this is a real latent bug independent of whether it happens to be masked today.
|
|
@@ -45,37 +45,19 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
45
45
|
|
|
46
46
|
## Icon size: Recursica defines it
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
**Implementation:**
|
|
51
|
-
|
|
52
|
-
- When `icon` is provided, the Button wraps it in a single element with class `iconWrapper` before passing it to Mantine’s `leftSection`.
|
|
53
|
-
- In `Button.module.css`, `.iconWrapper` has explicit `width` and `height` from the Recursica tokens mapping natively based on `data-size`.
|
|
54
|
-
- The rule `.iconWrapper > *` sets `width: 100%`, `height: 100%`, and `object-fit: contain` so whatever the caller passes scales cleanly with the token constraints.
|
|
48
|
+
Icon size is **not** left to the developer. Recursica defines it via the design tokens, so callers cannot pass an arbitrarily sized icon — whatever is passed in `icon` is scaled to fit the token-defined dimensions for the button's size.
|
|
55
49
|
|
|
56
50
|
---
|
|
57
51
|
|
|
58
|
-
## Icon-only buttons: accessibility
|
|
59
|
-
|
|
60
|
-
**Decision:** When the button has an icon and no visible label (icon-only), callers must provide an accessible name, and the button must not show extra space to the right of the icon.
|
|
61
|
-
|
|
62
|
-
**Accessibility:** We document that icon-only buttons must pass `aria-label` (e.g. `aria-label="Submit"`). In development we log a console warning if `icon` is set, `children` is empty, and `aria-label` is missing.
|
|
52
|
+
## Icon-only buttons: accessibility
|
|
63
53
|
|
|
64
|
-
|
|
54
|
+
When the button has an icon and no visible label (icon-only), callers must provide an accessible name via `aria-label` (e.g. `aria-label="Submit"`). In development, a console warning is logged if `icon` is set, `children` is empty, and `aria-label` is missing.
|
|
65
55
|
|
|
66
56
|
---
|
|
67
57
|
|
|
68
58
|
## Label truncation at max-width
|
|
69
59
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
**Implementation:**
|
|
73
|
-
Mantine's `.mantine-Button-label` flex centering breaks primitive truncation logic. To combat this:
|
|
74
|
-
|
|
75
|
-
- **`.root`** has `overflow: hidden`.
|
|
76
|
-
- **`.root > *`** forces `min-width: 0`.
|
|
77
|
-
- The structural children wrap into `<span className={styles.labelText}>`.
|
|
78
|
-
- **`.labelText`** binds `overflow: hidden; text-overflow: ellipsis; white-space: nowrap;` creating flawless string cutoffs strictly at exact UI constraints.
|
|
60
|
+
When the button hits its Recursica max-width (500px), the label truncates with an ellipsis instead of wrapping.
|
|
79
61
|
|
|
80
62
|
---
|
|
81
63
|
|
|
@@ -95,6 +77,4 @@ Mantine's `.mantine-Button-label` flex centering breaks primitive truncation log
|
|
|
95
77
|
|
|
96
78
|
## Loading state enforces disabled state
|
|
97
79
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
**Implementation:** This ensures that loading buttons automatically inherit the brand theme disabled opacities (via the `:disabled` CSS pseudo-class) rather than relying solely on Mantine's native `data-disabled` dataset logic, which may not trigger the strict visual fade required by the Recursica design system.
|
|
80
|
+
When `loading={true}` is passed to the Button, it is also treated as disabled — the button cannot be interacted with while loading.
|
|
@@ -54,18 +54,10 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
54
54
|
|
|
55
55
|
## 4. Key Integration Features & Constraints
|
|
56
56
|
|
|
57
|
-
##
|
|
57
|
+
## Header & Footer Styling
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
`Card.Header` and `Card.Footer` automatically receive their background color and padding from the design system; no manual styling is needed.
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
- `<Card.Footer>` explicitly hooks `--recursica_ui-kit_components_card_properties_footer-background` and corresponding padding variables.
|
|
61
|
+
## Layout Alignment
|
|
63
62
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
## Layout Alignment Exceptions
|
|
67
|
-
|
|
68
|
-
To allow Cards to fit cleanly inside dynamic/flex layouts (like dashboard panels, grid tracks, or sidebar layout segments), the Card wrapper implements a custom gatekeeper bypass for outer styling properties:
|
|
69
|
-
|
|
70
|
-
- Exposes a safe subset of flexbox/dimensions styling properties (`flex`, `flexGrow`, `flexShrink`, `flexBasis`, `grow`, `h`, `height`) on the root `<Card>` component to allow proper sizing alongside layout siblings.
|
|
71
|
-
- Sets `<Card.Content>` to `flex-grow: 1;` by default via CSS modules. Since the root `<Card>` has `display: flex; flex-direction: column;`, this makes the content area expand to fill all vertical space, pushing `<Card.Footer>` to align at the absolute bottom of the bounding box.
|
|
63
|
+
`Card` accepts a safe subset of flexbox/sizing props (`flex`, `flexGrow`, `flexShrink`, `flexBasis`, `grow`, `h`, `height`) so it can participate cleanly in flex or grid layouts (dashboard panels, grid tracks, sidebar segments, etc.). `Card.Content` grows to fill available vertical space, which keeps `Card.Footer` pinned to the bottom of the card.
|
|
@@ -39,26 +39,10 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
39
39
|
|
|
40
40
|
## 4. Key Integration Features & Constraints
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
### Checkbox Alignment with Multi-line Labels
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
Checkbox visually aligns to the first line of a wrapping, multi-line label.
|
|
45
45
|
|
|
46
|
-
### Checkbox
|
|
46
|
+
### Checkbox.Group
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
We mathematically fix this alignment within `Checkbox.module.css` using explicit design variable arithmetic natively.
|
|
51
|
-
\`\`\`css
|
|
52
|
-
margin-top: calc(
|
|
53
|
-
(
|
|
54
|
-
var(--recursica_ui-kit_components_checkbox-item_properties_text_line-height) \*
|
|
55
|
-
var(--recursica_ui-kit_components_checkbox-item_properties_text_font-size) -
|
|
56
|
-
var(--recursica_ui-kit_components_checkbox_properties_size)
|
|
57
|
-
) / 2
|
|
58
|
-
) !important;
|
|
59
|
-
\`\`\`
|
|
60
|
-
This calculation ensures that the optical center of the `.inner` checkmark vector perfectly snaps onto the relative center of the text's line-height, permanently solving pixel-drifts natively!
|
|
61
|
-
|
|
62
|
-
### Checkbox.Group Overrides
|
|
63
|
-
|
|
64
|
-
To decouple `<CheckboxGroup>` away from `<Input.Wrapper>`, we explicitly extract the raw array execution mapped correctly against our identical `RecursicaFormControlWrapperProps` schema structurally!
|
|
48
|
+
`Checkbox.Group` integrates with the same label, description, and error props as other Recursica form components.
|
|
@@ -39,39 +39,10 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
39
39
|
|
|
40
40
|
## 4. Key Integration Features & Constraints
|
|
41
41
|
|
|
42
|
-
## Architecture decisions
|
|
43
|
-
|
|
44
|
-
### Mantine DOM Structure & Label Overrides
|
|
45
|
-
|
|
46
|
-
Mantine's `<Chip>` behaves like an input element (`radio` or `checkbox`). Under the hood, it renders:
|
|
47
|
-
|
|
48
|
-
1. `.mantine-Chip-root` (wrapper)
|
|
49
|
-
2. `input` (hidden visual structure)
|
|
50
|
-
3. `.mantine-Chip-label` (The actual visible button-like pill)
|
|
51
|
-
|
|
52
|
-
Because the `.label` is the primary visual surface and handles Mantine's built-in `:hover` and active states, we direct our Recursica styling natively to `.label`.
|
|
53
|
-
|
|
54
|
-
### Icon and Remove Implementations
|
|
55
|
-
|
|
56
|
-
To achieve this without breaking Mantine's `Chip` input architecture, we wrapped the internal `children` using a standard `span` DOM strategy:
|
|
57
|
-
|
|
58
|
-
```tsx
|
|
59
|
-
<span className={styles.innerWrapper}>
|
|
60
|
-
{icon}
|
|
61
|
-
<span className={styles.children}>{children}</span>
|
|
62
|
-
{onRemove}
|
|
63
|
-
</span>
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
#### Intermediate Children Wrapper Span display fix:
|
|
67
|
-
|
|
68
|
-
Mantine internally wraps the children passed to `Chip` in a default `<span>` which has `display: inline`. This intermediate `span` inherits the `line-height` of the `.label` container, causing the computed height of the Chip to be ~2px taller than expected. To address this, `.label > span:not(.mantineIconWrapper)` is targeted to force `display: inline-flex; align-items: center;` on that intermediate wrapper `span`, allowing it to collapse perfectly to the `16px` height of the `innerWrapper`.
|
|
69
|
-
|
|
70
42
|
### Accessibility of Remove Action
|
|
71
43
|
|
|
72
|
-
|
|
73
|
-
To accommodate this, the visual "close" icon uses a `<span>` element configured with `role="button"` and `tabIndex={0}` to hook into standard keyboard activations without triggering generic nested `<form>` conflicts native to Mantine's baseline constraints.
|
|
44
|
+
The remove/close action is keyboard accessible — it can be activated via keyboard as well as mouse click.
|
|
74
45
|
|
|
75
|
-
###
|
|
46
|
+
### Sizing
|
|
76
47
|
|
|
77
|
-
|
|
48
|
+
Chip does not support a `size` prop; chips render at a fixed size.
|
|
@@ -39,17 +39,7 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
39
39
|
|
|
40
40
|
## 4. Key Integration Features & Constraints
|
|
41
41
|
|
|
42
|
-
## Architecture Overview
|
|
43
|
-
|
|
44
|
-
The `DatePicker` component is a wrapper around the `@mantine/dates` `DatePickerInput` component, implementing the `FormControlWrapper` macro structure for Recursica. This ensures that the component visually and structurally aligns with standard Recursica input primitives.
|
|
45
|
-
|
|
46
42
|
## Structural Constraints
|
|
47
43
|
|
|
48
|
-
1. **
|
|
49
|
-
2. **
|
|
50
|
-
3. **Calendar Portal/Dropdown (Figma Token Issue)**: The Recursica UI Kit's `date-picker` component in Figma fails to export any explicit structural or color properties for the calendar popover itself (e.g. elevation, surface background, selected day colors). To solve this organically within the framework without breaking strict token adherence, we manually override the Mantine `.dropdown` and `.day[data-selected]` classes using `--recursica_ui-kit_components_hover-card-popover` tokens for elevation/padding/surfaces, and `--recursica_ui-kit_components_button_variants_styles_solid` tokens for the selected primary blue day. This guarantees strict visual adherence to the system until explicitly mapped tokens are provided in the UI Kit.
|
|
51
|
-
|
|
52
|
-
## Styling Quirks
|
|
53
|
-
|
|
54
|
-
- The `DatePickerInput` mimics Mantine's `Input` structure natively (`.input`, `.wrapper`, `.section`). We attach our `styles.input` and `styles.root` classes exactly like `TextField`.
|
|
55
|
-
- The global layout margin override (`.layoutOverride`) utilizes `--form-control-margin-bottom` driven by specific stacked/side-by-side design tokens.
|
|
44
|
+
1. **Read-Only Rendering**: When rendered in read-only mode, the selected date is displayed via a plain string conversion of the value. If you need custom date formatting, pass a `readOnlyComponent` prop to control how the value is rendered.
|
|
45
|
+
2. **Calendar Popover Styling**: The calendar popover is not yet fully styled by design tokens.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Select as MantineSelect,
|
|
4
|
+
type SelectProps as MantineSelectProps,
|
|
5
|
+
} from "@mantine/core";
|
|
6
|
+
import {
|
|
7
|
+
filterStylingProps,
|
|
8
|
+
type RecursicaOverStyled,
|
|
9
|
+
} from "../../utils/filterStylingProps";
|
|
10
|
+
import styles from "./Dropdown.module.css";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Bare, unwrapped Select — no `FormControlWrapper`/`WithReadOnlyWrapper`, no label/assistiveText/
|
|
14
|
+
* error/required. Tied to the same `Dropdown.module.css` variables/classes as the public
|
|
15
|
+
* `Dropdown` component, so it looks identical, but is meant to be embedded inside another
|
|
16
|
+
* component that already owns its own `FormControlWrapper` (e.g. `TimePicker`'s AM/PM control) —
|
|
17
|
+
* nesting the full `Dropdown` there would double up `FormControl`/`FormControlLayout` wrapping.
|
|
18
|
+
*
|
|
19
|
+
* Not exported from this folder's `index.ts` — internal use only. Import it directly:
|
|
20
|
+
* `import { BareDropdown } from "../Dropdown/BareDropdown"`.
|
|
21
|
+
*/
|
|
22
|
+
export interface BareDropdownProps
|
|
23
|
+
extends Omit<
|
|
24
|
+
MantineSelectProps,
|
|
25
|
+
| "size"
|
|
26
|
+
| "variant"
|
|
27
|
+
| "radius"
|
|
28
|
+
| "wrapperProps"
|
|
29
|
+
| "label"
|
|
30
|
+
| "description"
|
|
31
|
+
| "error"
|
|
32
|
+
> {
|
|
33
|
+
data: MantineSelectProps["data"];
|
|
34
|
+
/** Applies the error visual state (via `data-error`) — no error message is rendered here. */
|
|
35
|
+
error?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type BareDropdownComponentProps = RecursicaOverStyled<BareDropdownProps>;
|
|
39
|
+
|
|
40
|
+
export const BareDropdown = forwardRef<
|
|
41
|
+
HTMLInputElement,
|
|
42
|
+
BareDropdownComponentProps
|
|
43
|
+
>(function BareDropdown(props, ref) {
|
|
44
|
+
const { overStyled = false, className, disabled, error, ...rest } = props;
|
|
45
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
46
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
47
|
+
|
|
48
|
+
delete restRecord["size"];
|
|
49
|
+
delete restRecord["variant"];
|
|
50
|
+
delete restRecord["radius"];
|
|
51
|
+
|
|
52
|
+
const mergedClassNames: Partial<Record<string, string>> = {
|
|
53
|
+
wrapper: className ? `${styles.root} ${className}` : styles.root,
|
|
54
|
+
input: styles.input,
|
|
55
|
+
section: styles.section,
|
|
56
|
+
dropdown: styles.dropdown,
|
|
57
|
+
option: styles.option,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<MantineSelect
|
|
62
|
+
ref={ref}
|
|
63
|
+
classNames={mergedClassNames}
|
|
64
|
+
disabled={disabled}
|
|
65
|
+
label={undefined}
|
|
66
|
+
description={undefined}
|
|
67
|
+
error={undefined}
|
|
68
|
+
// `wrapperProps` targets Mantine's *outer* `Input.Wrapper` (the label/description/error
|
|
69
|
+
// stacking element) — a different, ancestor element from the "wrapper" styles-api slot that
|
|
70
|
+
// actually carries `styles.root`'s border/background. Dropdown.module.css's error/disabled
|
|
71
|
+
// rules (`.root[data-error]`/`[data-disabled]`) need the attribute on that inner element, so
|
|
72
|
+
// `attributes.wrapper` (which targets the same slot as `classNames.wrapper`/`styles.wrapper`)
|
|
73
|
+
// is the correct hook here, not `wrapperProps`. See TIMEPICKER_IMPLEMENTATION_NOTES.md.
|
|
74
|
+
attributes={{
|
|
75
|
+
wrapper: {
|
|
76
|
+
"data-disabled": disabled ? "true" : undefined,
|
|
77
|
+
"data-error": error ? "true" : undefined,
|
|
78
|
+
},
|
|
79
|
+
}}
|
|
80
|
+
{...(sanitizedProps as unknown as MantineSelectProps)}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
BareDropdown.displayName = "BareDropdown";
|
|
@@ -156,9 +156,18 @@ export const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
|
|
|
156
156
|
error={undefined}
|
|
157
157
|
required={undefined}
|
|
158
158
|
withAsterisk={undefined}
|
|
159
|
-
wrapperProps
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
// `wrapperProps` targets Mantine's *outer* `Input.Wrapper` (the label/description/error
|
|
160
|
+
// stacking element) — a different, ancestor element from the "wrapper" styles-api slot
|
|
161
|
+
// that actually carries `styles.root`'s border/background. Dropdown.module.css's error/
|
|
162
|
+
// disabled rules (`.root[data-error]`/`[data-disabled]`) need the attribute on that
|
|
163
|
+
// inner element, so `attributes.wrapper` (which targets the same slot as
|
|
164
|
+
// `classNames.wrapper`) is the correct hook — `wrapperProps` here meant the error state
|
|
165
|
+
// never actually applied a border color.
|
|
166
|
+
attributes={{
|
|
167
|
+
wrapper: {
|
|
168
|
+
"data-disabled": disabled ? "true" : undefined,
|
|
169
|
+
"data-error": error ? "true" : undefined,
|
|
170
|
+
},
|
|
162
171
|
}}
|
|
163
172
|
{...(sanitizedProps as unknown as MantineSelectProps)}
|
|
164
173
|
/>
|
|
@@ -42,10 +42,6 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
42
42
|
|
|
43
43
|
---
|
|
44
44
|
|
|
45
|
-
## 4.
|
|
45
|
+
## 4. Notes
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
1. **Naked Primitive Mapping:** Mantine's `Select` natively executes macro-label generation. To decouple it, we explicitly disable internal labels (`label={undefined}`) and inject it purely inside our generic `FormControlWrapper`.
|
|
50
|
-
2. **Strict Dropdown Design Tokens:** The adapter implements strictly sandboxed styling utilizing only `--recursica_ui-kit_components_dropdown_...` variables. It explicitly does NOT inherit general `text-field` tokens despite geometric similarities, ensuring dropdown menus can be themed independently.
|
|
51
|
-
3. **Dropdown Appendages:** To correctly map Mantine's detached Popover `.dropdown` and list `.option` items, we targeted focus and geometric bindings appending standard padding structures matched to the dropdown height overrides dynamically into our `Dropdown.module.css`.
|
|
47
|
+
- `Dropdown` is styled independently from `TextField`; even though they look similar, they are themed using separate design tokens.
|
|
@@ -45,4 +45,4 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
45
45
|
## 4. Key Integration Features & Constraints
|
|
46
46
|
|
|
47
47
|
The `Flex` component is a generic unopinionated flex layout wrapper mapped directly to Mantine's `Flex`.
|
|
48
|
-
|
|
48
|
+
All spacing props (`gap`, `align`, `justify`, `direction`, `wrap`) pass through as normal, with `rec-` dimension tokens mapped transparently to standard gap values.
|