@recursica/mantine-adapter 0.32.0 → 0.34.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 +12 -0
- package/OVERSTYLING.md +56 -0
- package/USAGE.md +6 -4
- package/dist/mantine-adapter.cjs +2 -2
- package/dist/mantine-adapter.cjs.map +1 -1
- package/dist/mantine-adapter.js +1765 -1445
- package/dist/mantine-adapter.js.map +1 -1
- package/dist/src/components/Modal/Modal.d.ts +21 -8
- package/dist/src/components/Pagination/Pagination.d.ts +45 -25
- package/dist/src/components/Panel/Panel.d.ts +22 -8
- package/dist/src/components/Stepper/Stepper.d.ts +4 -2
- package/dist/src/components/Table/Table.d.ts +25 -9
- package/dist/src/components/Tooltip/Tooltip.d.ts +4 -2
- package/llms.txt +57 -2
- package/package.json +3 -2
- package/src/OverStyling.tsx +10 -226
- package/src/components/Accordion/USAGE.md +90 -0
- package/src/components/AssistiveElement/USAGE.md +36 -0
- package/src/components/AutoComplete/USAGE.md +66 -0
- package/src/components/Avatar/USAGE.md +65 -0
- package/src/components/Badge/USAGE.md +59 -0
- package/src/components/Breadcrumb/USAGE.md +59 -0
- package/src/components/Button/USAGE.md +100 -0
- package/src/components/Card/USAGE.md +71 -0
- package/src/components/Checkbox/USAGE.md +64 -0
- package/src/components/Chip/USAGE.md +77 -0
- package/src/components/Container/USAGE.md +47 -0
- package/src/components/DatePicker/USAGE.md +55 -0
- package/src/components/Dropdown/USAGE.md +51 -0
- package/src/components/FileInput/USAGE.md +36 -0
- package/src/components/FileUpload/USAGE.md +41 -0
- package/src/components/Flex/USAGE.md +48 -0
- package/src/components/FormControlLayout/USAGE.md +40 -0
- package/src/components/FormControlWrapper/USAGE.md +75 -0
- package/src/components/Group/USAGE.md +48 -0
- package/src/components/HoverCard/USAGE.md +121 -0
- package/src/components/Label/USAGE.md +87 -0
- package/src/components/Link/USAGE.md +69 -0
- package/src/components/Loader/USAGE.md +63 -0
- package/src/components/Menu/USAGE.md +124 -0
- package/src/components/Modal/Modal.tsx +129 -23
- package/src/components/Modal/USAGE.md +58 -0
- package/src/components/NumberInput/USAGE.md +55 -0
- package/src/components/Pagination/Pagination.tsx +73 -17
- package/src/components/Pagination/USAGE.md +55 -0
- package/src/components/Panel/Panel.tsx +134 -14
- package/src/components/Panel/USAGE.md +145 -0
- package/src/components/Popover/USAGE.md +121 -0
- package/src/components/Radio/USAGE.md +36 -0
- package/src/components/ReadOnlyField/USAGE.md +52 -0
- package/src/components/SegmentedControl/USAGE.md +56 -0
- package/src/components/Slider/USAGE.md +86 -0
- package/src/components/Stack/USAGE.md +48 -0
- package/src/components/Stepper/Stepper.tsx +20 -2
- package/src/components/Stepper/USAGE.md +41 -0
- package/src/components/Switch/USAGE.md +65 -0
- package/src/components/Table/Table.tsx +153 -16
- package/src/components/Table/USAGE.md +41 -0
- package/src/components/Tabs/USAGE.md +45 -0
- package/src/components/Text/USAGE.md +40 -0
- package/src/components/TextArea/USAGE.md +48 -0
- package/src/components/TextField/USAGE.md +60 -0
- package/src/components/TimePicker/USAGE.md +36 -0
- package/src/components/Timeline/USAGE.md +57 -0
- package/src/components/Title/USAGE.md +36 -0
- package/src/components/Toast/USAGE.md +80 -0
- package/src/components/Tooltip/Tooltip.tsx +26 -2
- package/src/components/Tooltip/USAGE.md +124 -0
- package/src/components/TransferList/USAGE.md +46 -0
- package/src/components/Tree/USAGE.md +46 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Label - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Label` component in your projects using `@recursica/mantine-adapter`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Label } from "@recursica/mantine-adapter";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Label } from "@recursica/mantine-adapter";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return <Label required>Field Label</Label>;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 3. Design System Integration
|
|
29
|
+
|
|
30
|
+
All Recursica components in the `@recursica/mantine-adapter` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
31
|
+
|
|
32
|
+
> [!IMPORTANT]
|
|
33
|
+
>
|
|
34
|
+
> - **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.
|
|
35
|
+
> - **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.
|
|
36
|
+
> - **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.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 4. Key Integration Features & Constraints
|
|
41
|
+
|
|
42
|
+
## Architecture Overview
|
|
43
|
+
|
|
44
|
+
The `Label` component is fundamentally built as a strict, localized wrapper around Mantine's native `Input.Label`. The core goal is to preserve context, ref-forwarding, and native accessibility links, while completely overriding visual behaviors via Recursica design variables in scoped CSS.
|
|
45
|
+
|
|
46
|
+
## Key Design Decisions
|
|
47
|
+
|
|
48
|
+
### **Layout Architecture**
|
|
49
|
+
|
|
50
|
+
- Because Recursica dictates complex alignments between primary label text, asterisks, edit icons, and optional strings, Mantine's rigid form label flow could not be used out-of-the-box.
|
|
51
|
+
- Implemented `display: flex; flex-wrap: wrap;` directly on `.root`.
|
|
52
|
+
- Injected strict integer-based flex `order` properties (e.g. `order: 1` for text, `order: 2` for `required`, `order: 5` for `optionalText`) to physically decouple DOM rendering from markup flow.
|
|
53
|
+
- Because `optionalText` often acts as secondary contextual detail, it forces `flex-basis: 100%`, securely wrapping to a secondary line underneath the primary label properties and transforming the horizontal gap spacing seamlessly into a `margin-top` vector.
|
|
54
|
+
|
|
55
|
+
### **Optional Text & Required Mutually Exclusive Parsing**
|
|
56
|
+
|
|
57
|
+
- By design standards, a component cannot logically be both "Required" and mapped as "Optional".
|
|
58
|
+
- To bulletproof implementations natively, the adapter forcibly suppresses rendering of the `resolvedOptionalText` strings if the parent wrapper invokes `required={true}`.
|
|
59
|
+
- `optionalText` can operate as dynamic data or specifically as a boolean `true`, which forces the adapter to natively render the formal `(Optional)` string map.
|
|
60
|
+
|
|
61
|
+
### **The "Edit Icon" Replacer Logic**
|
|
62
|
+
|
|
63
|
+
- Passing `withEditIcon={true}` evaluates it as fundamentally mutually exclusive to the standard required indicator asterisk.
|
|
64
|
+
- `required={required && !withEditIcon}` is passed to the underlying Mantine structure so the native `*` is entirely suppressed.
|
|
65
|
+
- Added localized styling via `data-replaces-asterisk={required ? "true" : undefined}` onto the `.editIconWrapper` element. If an editable instance is simultaneously designated as required, the edit icon functionally assumes the indicator role natively, overriding its default icon metrics explicitly to match `--recursica_ui-kit_components_label_properties_colors_asterisk`.
|
|
66
|
+
|
|
67
|
+
### **Bypassing `Input.Wrapper` Integrations**
|
|
68
|
+
|
|
69
|
+
- By decoupling from Mantine's standard `Input.Wrapper`, the `Label` component is exclusively mapped manually through `FormControlWrapper`. This grants us exact visual sync regarding where the label renders based on `formLayout="stacked"` or `formLayout="side-by-side"`, without fighting internal Mantine positional hooks that assume vertical stacking by default.
|
|
70
|
+
|
|
71
|
+
### **Label Size Container Constraints**
|
|
72
|
+
|
|
73
|
+
- The `labelSize` parameter (mapping values like `"small"`) internally **does not scale typographic font metrics**. Instead, it dynamically defines the explicit horizontal bounding width limit of the block container itself.
|
|
74
|
+
- **Architectural Rule:** `labelSize` modifications are strictly designed to execute exclusively when `formLayout="side-by-side"` is active. It acts as an optical grid threshold ensuring left-aligned string wrappers constrain correctly uniformly down a column without bleeding into the physical input arrays alongside them.
|
|
75
|
+
|
|
76
|
+
## Outstanding Technical Debt / Issues
|
|
77
|
+
|
|
78
|
+
### **Description Property Omission**
|
|
79
|
+
|
|
80
|
+
- **Issue:** Currently, the adapter `Label` does not natively parse or support a structured `description` node directly attached beneath it.
|
|
81
|
+
- **Context:** Standard forms often attach subtext beneath inputs, but mapping a description purely within the `<Label>` (distinct from an overall form-control description) is omitted structurally until subsequent UI Kit requirements mandate dedicated `description` styles locally on the label component itself.
|
|
82
|
+
|
|
83
|
+
### **Global Interactive Hover Mappings**
|
|
84
|
+
|
|
85
|
+
- **Issue:** Currently, the `editIconWrapper` lacks a dedicated hover background layer.
|
|
86
|
+
- **Context:** While the global theme abstracts interactive hover environments deeply using layered variable syntax (e.g., `--recursica_brand_layer_1_elements_interactive_hover-color`), Recursica's token generation framework natively fails to expose a universally generic placeholder token (e.g., `--recursica_elements_interactive_hover-color`) which downstream wrappers can map their `<Layer>` injections directly into safely.
|
|
87
|
+
- **Resolution Path:** We are explicitly ignoring the `.editIconWrapper:hover` background color assignment until the raw Figma token exports directly scaffold a generic token placeholder that we can interface cleanly with across arbitrary `<Layer>` contexts, avoiding manually mapping statically hardcoded depths (`layer-0`, `layer-1`).
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Link - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Link` component in your projects using `@recursica/mantine-adapter`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Link } from "@recursica/mantine-adapter";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Link } from "@recursica/mantine-adapter";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Link href="/dashboard" variant="inline">
|
|
24
|
+
Go to Dashboard
|
|
25
|
+
</Link>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 3. Design System Integration
|
|
33
|
+
|
|
34
|
+
All Recursica components in the `@recursica/mantine-adapter` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
35
|
+
|
|
36
|
+
> [!IMPORTANT]
|
|
37
|
+
>
|
|
38
|
+
> - **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.
|
|
39
|
+
> - **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.
|
|
40
|
+
> - **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.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 4. Key Integration Features & Constraints
|
|
45
|
+
|
|
46
|
+
## Missing States in Design Tokens
|
|
47
|
+
|
|
48
|
+
Currently, the design tokens (`recursica_variables_scoped.css`) only provide states for:
|
|
49
|
+
|
|
50
|
+
- `default`
|
|
51
|
+
- `hover`
|
|
52
|
+
- `visited`
|
|
53
|
+
- `visited-hover`
|
|
54
|
+
|
|
55
|
+
There are no tokens for the `active` or `focus` states. If these are needed, they must be added to the Figma variables and exported via the token pipeline. The component relies on the browser's default focus outline for accessibility unless overriden by a global reset.
|
|
56
|
+
|
|
57
|
+
## Overriding Mantine's underline Prop
|
|
58
|
+
|
|
59
|
+
Mantine's `Anchor` component uses `underline="hover"` by default. Because our design system specifies exact `text-decoration` styles via CSS tokens, we explicitly pass `underline="never"` to the underlying Mantine component. This prevents Mantine from injecting its own text-decoration inline or via generic classnames, ensuring our scoped CSS remains the single source of truth.
|
|
60
|
+
|
|
61
|
+
## Base Layout
|
|
62
|
+
|
|
63
|
+
Mantine's `Anchor` renders an inline element by default and does not natively support `leftSection` like the `Button` component. To support an optional `icon` alongside the text, we enforce a baseline layout of `display: inline-flex` and `align-items: center` in `Link.module.css`.
|
|
64
|
+
|
|
65
|
+
When an icon is present, the component conditionally passes a `data-has-icon` attribute to the root element. The CSS module uses this attribute to apply the `icon-text-gap` token via the CSS `gap` property.
|
|
66
|
+
|
|
67
|
+
## Inner Wrappers
|
|
68
|
+
|
|
69
|
+
The icon and children are wrapped in internal `<span>` tags (`.iconWrapper` and `.labelText` respectively). This follows the component development guide for structural robustness, allowing us to enforce specific sizing on the icon and intrinsic text truncation behavior if the link is placed in a bounded container.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Loader - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Loader` component in your projects using `@recursica/mantine-adapter`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Loader } from "@recursica/mantine-adapter";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Loader } from "@recursica/mantine-adapter";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return <Loader size="md" />;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 3. Design System Integration
|
|
29
|
+
|
|
30
|
+
All Recursica components in the `@recursica/mantine-adapter` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
31
|
+
|
|
32
|
+
> [!IMPORTANT]
|
|
33
|
+
>
|
|
34
|
+
> - **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.
|
|
35
|
+
> - **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.
|
|
36
|
+
> - **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.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 4. Key Integration Features & Constraints
|
|
41
|
+
|
|
42
|
+
## Architecture & Integration
|
|
43
|
+
|
|
44
|
+
The `Loader` component acts as a strictly tokenized wrapper bridging the Recursica UI-Kit `loader` variables to the generic Mantine `@mantine/core` `Loader` primitive.
|
|
45
|
+
|
|
46
|
+
### Key Decisions:
|
|
47
|
+
|
|
48
|
+
- **Variant Mapping:** Recursica's `variant` directly proxies to Mantine's `type` prop for `"oval" | "bars" | "dots"`.
|
|
49
|
+
- **Property Overrides Disabled:** Natively overriding specific structural variants directly on the JSX interface like `thickness` and `borderRadius` has been intentionally omitted. Component rendering relies entirely on variables exposed by the underlying UI Kit mappings tied to the size prop.
|
|
50
|
+
|
|
51
|
+
### Token Mapping:
|
|
52
|
+
|
|
53
|
+
Sizes are bound through `data-size` attributes (`sm`, `md`, `lg` parsing to target `<div data-size="small">`, etc.).
|
|
54
|
+
|
|
55
|
+
Mantine natively sets sizing dynamically at the component root and parses thickness/variants differently natively (e.g., `oval` styles its geometry strictly via CSS `border`, while `bars` and `dots` utilize specific DOM inner spans `span.dot` / `span.bar`).
|
|
56
|
+
|
|
57
|
+
#### Specific CSS Targeting Hacks Used
|
|
58
|
+
|
|
59
|
+
- `border-width` and `border-radius` structurally style the `thickness` and `border-radius` configuration of the `oval` variant on the `::after` pseudo-element by resolving `--recursica_ui-kit_components_loader_variants_sizes_..._properties_thickness` and `_border-radius`.
|
|
60
|
+
|
|
61
|
+
### Unsupported Properties
|
|
62
|
+
|
|
63
|
+
- **xs and xl Sizing:** These sizes are explicitly unsupported in the Recursica standard logic (as surfaced in `filterStylingProps` and UI Kit mappings). Attempting to use them will safely default back or fallthrough statically unless defined later. See `COMPONENT_ISSUES.md`.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Menu - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Menu` component in your projects using `@recursica/mantine-adapter`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Menu } from "@recursica/mantine-adapter";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Menu } from "@recursica/mantine-adapter";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Menu>
|
|
24
|
+
<Menu.Target>
|
|
25
|
+
<Button>Toggle Menu</Button>
|
|
26
|
+
</Menu.Target>
|
|
27
|
+
<Menu.Dropdown>
|
|
28
|
+
<Menu.Item>Profile</Menu.Item>
|
|
29
|
+
<Menu.Item>Settings</Menu.Item>
|
|
30
|
+
<Menu.Item color="red">Logout</Menu.Item>
|
|
31
|
+
</Menu.Dropdown>
|
|
32
|
+
</Menu>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 3. Design System Integration
|
|
40
|
+
|
|
41
|
+
All Recursica components in the `@recursica/mantine-adapter` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
42
|
+
|
|
43
|
+
> [!IMPORTANT]
|
|
44
|
+
>
|
|
45
|
+
> - **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.
|
|
46
|
+
> - **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.
|
|
47
|
+
> - **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.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 4. Key Integration Features & Constraints
|
|
52
|
+
|
|
53
|
+
## 1. Composable API Preservation (1:1 Mapping)
|
|
54
|
+
|
|
55
|
+
**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.
|
|
56
|
+
|
|
57
|
+
**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.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 2. Hover State Overlay Technique
|
|
62
|
+
|
|
63
|
+
**Decision:** We nullify Mantine's native hover background on `Menu.Item` and exclusively utilize Recursica's hover structure via a `::after` pseudo-element overlay.
|
|
64
|
+
|
|
65
|
+
**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.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 3. Selected vs Unselected Item States
|
|
70
|
+
|
|
71
|
+
**Decision:** Menu items map to Recursica's `selected-item` and `unselected-item` color token groups.
|
|
72
|
+
|
|
73
|
+
**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.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 4. `color` Prop Stripping
|
|
78
|
+
|
|
79
|
+
**Decision:** Mantine's `color` prop on `Menu.Item` (used for semantics like "danger/red") is explicitly stripped in strict mode.
|
|
80
|
+
|
|
81
|
+
**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:
|
|
82
|
+
|
|
83
|
+
1. Use `overStyled={true}` as an explicit escape hatch
|
|
84
|
+
2. Contribute a proper Recursica variant to the token system
|
|
85
|
+
|
|
86
|
+
**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.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 5. Menu.Target Pass-Through
|
|
91
|
+
|
|
92
|
+
**Decision:** `Menu.Target` is a transparent pass-through with no styling applied.
|
|
93
|
+
|
|
94
|
+
**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>`).
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 6. Sub-Menu Support
|
|
99
|
+
|
|
100
|
+
**Decision:** We wrap the full Mantine sub-menu hierarchy (`Menu.Sub`, `Menu.Sub.Target`, `Menu.Sub.Item`, `Menu.Sub.Dropdown`).
|
|
101
|
+
|
|
102
|
+
**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.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 7. Dropdown Container Padding
|
|
107
|
+
|
|
108
|
+
**Decision:** The dropdown container uses `divider-item-gap` as its internal padding.
|
|
109
|
+
|
|
110
|
+
**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.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 8. Minimal CSS Override Philosophy
|
|
115
|
+
|
|
116
|
+
**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.
|
|
117
|
+
|
|
118
|
+
**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:
|
|
119
|
+
|
|
120
|
+
- `overflow` on the dropdown (Mantine renders sub-menu dropdowns inside the parent DOM tree using Floating UI absolute positioning — setting overflow clips them)
|
|
121
|
+
- `display`, `align-items`, `width`, `cursor` on items (Mantine's button-based items already handle this)
|
|
122
|
+
- `pointer-events` on disabled items (Mantine handles disabled natively)
|
|
123
|
+
|
|
124
|
+
**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.
|
|
@@ -2,6 +2,12 @@ import React from "react";
|
|
|
2
2
|
import {
|
|
3
3
|
Modal as MantineModal,
|
|
4
4
|
type ModalProps as MantineModalProps,
|
|
5
|
+
type ModalRootProps as MantineModalRootProps,
|
|
6
|
+
type ModalOverlayProps as MantineModalOverlayProps,
|
|
7
|
+
type ModalContentProps as MantineModalContentProps,
|
|
8
|
+
type ModalHeaderProps as MantineModalHeaderProps,
|
|
9
|
+
type ModalTitleProps as MantineModalTitleProps,
|
|
10
|
+
type ModalCloseButtonProps as MantineModalCloseButtonProps,
|
|
5
11
|
} from "@mantine/core";
|
|
6
12
|
import {
|
|
7
13
|
filterStylingProps,
|
|
@@ -114,18 +120,22 @@ ModalInner.displayName = "Modal";
|
|
|
114
120
|
* > primary action button MUST be the right-most element, with the secondary
|
|
115
121
|
* > (outline variant) action placed immediately to the left of it.
|
|
116
122
|
*/
|
|
117
|
-
|
|
118
|
-
HTMLDivElement,
|
|
123
|
+
export type ModalFooterProps = RecursicaOverStyled<
|
|
119
124
|
React.ComponentPropsWithoutRef<"div">
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
125
|
+
>;
|
|
126
|
+
|
|
127
|
+
const ModalFooter = React.forwardRef<HTMLDivElement, ModalFooterProps>(
|
|
128
|
+
function ModalFooter({ overStyled = false, className, ...rest }, ref) {
|
|
129
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
130
|
+
return (
|
|
131
|
+
<div
|
|
132
|
+
ref={ref}
|
|
133
|
+
className={`${styles.footer} ${className || ""}`}
|
|
134
|
+
{...sanitizedProps}
|
|
135
|
+
/>
|
|
136
|
+
);
|
|
137
|
+
},
|
|
138
|
+
);
|
|
129
139
|
ModalFooter.displayName = "Modal.Footer";
|
|
130
140
|
|
|
131
141
|
const ModalBody = React.forwardRef<
|
|
@@ -197,16 +207,112 @@ const ModalBody = React.forwardRef<
|
|
|
197
207
|
});
|
|
198
208
|
ModalBody.displayName = "Modal.Body";
|
|
199
209
|
|
|
210
|
+
// ============================================================
|
|
211
|
+
// MODAL SUB-COMPONENTS (wrapped so overStyled/filterStylingProps applies)
|
|
212
|
+
// ============================================================
|
|
213
|
+
|
|
214
|
+
export type ModalRootProps = RecursicaOverStyled<MantineModalRootProps>;
|
|
215
|
+
|
|
216
|
+
const ModalRoot = React.forwardRef<HTMLDivElement, ModalRootProps>(
|
|
217
|
+
function ModalRoot({ overStyled = false, ...rest }, ref) {
|
|
218
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
219
|
+
return (
|
|
220
|
+
<MantineModal.Root
|
|
221
|
+
ref={ref}
|
|
222
|
+
{...(sanitizedProps as unknown as MantineModalRootProps)}
|
|
223
|
+
/>
|
|
224
|
+
);
|
|
225
|
+
},
|
|
226
|
+
);
|
|
227
|
+
ModalRoot.displayName = "Modal.Root";
|
|
228
|
+
|
|
229
|
+
export type ModalOverlayProps = RecursicaOverStyled<MantineModalOverlayProps>;
|
|
230
|
+
|
|
231
|
+
const ModalOverlay = React.forwardRef<HTMLDivElement, ModalOverlayProps>(
|
|
232
|
+
function ModalOverlay({ overStyled = false, ...rest }, ref) {
|
|
233
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
234
|
+
return (
|
|
235
|
+
<MantineModal.Overlay
|
|
236
|
+
ref={ref}
|
|
237
|
+
{...(sanitizedProps as unknown as MantineModalOverlayProps)}
|
|
238
|
+
/>
|
|
239
|
+
);
|
|
240
|
+
},
|
|
241
|
+
);
|
|
242
|
+
ModalOverlay.displayName = "Modal.Overlay";
|
|
243
|
+
|
|
244
|
+
export type ModalContentProps = RecursicaOverStyled<MantineModalContentProps>;
|
|
245
|
+
|
|
246
|
+
const ModalContent = React.forwardRef<HTMLDivElement, ModalContentProps>(
|
|
247
|
+
function ModalContent({ overStyled = false, ...rest }, ref) {
|
|
248
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
249
|
+
return (
|
|
250
|
+
<MantineModal.Content
|
|
251
|
+
ref={ref}
|
|
252
|
+
{...(sanitizedProps as unknown as MantineModalContentProps)}
|
|
253
|
+
/>
|
|
254
|
+
);
|
|
255
|
+
},
|
|
256
|
+
);
|
|
257
|
+
ModalContent.displayName = "Modal.Content";
|
|
258
|
+
|
|
259
|
+
export type ModalHeaderProps = RecursicaOverStyled<MantineModalHeaderProps>;
|
|
260
|
+
|
|
261
|
+
const ModalHeader = React.forwardRef<HTMLElement, ModalHeaderProps>(
|
|
262
|
+
function ModalHeader({ overStyled = false, ...rest }, ref) {
|
|
263
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
264
|
+
return (
|
|
265
|
+
<MantineModal.Header
|
|
266
|
+
ref={ref}
|
|
267
|
+
{...(sanitizedProps as unknown as MantineModalHeaderProps)}
|
|
268
|
+
/>
|
|
269
|
+
);
|
|
270
|
+
},
|
|
271
|
+
);
|
|
272
|
+
ModalHeader.displayName = "Modal.Header";
|
|
273
|
+
|
|
274
|
+
export type ModalTitleProps = RecursicaOverStyled<MantineModalTitleProps>;
|
|
275
|
+
|
|
276
|
+
const ModalTitle = React.forwardRef<HTMLHeadingElement, ModalTitleProps>(
|
|
277
|
+
function ModalTitle({ overStyled = false, ...rest }, ref) {
|
|
278
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
279
|
+
return (
|
|
280
|
+
<MantineModal.Title
|
|
281
|
+
ref={ref}
|
|
282
|
+
{...(sanitizedProps as unknown as MantineModalTitleProps)}
|
|
283
|
+
/>
|
|
284
|
+
);
|
|
285
|
+
},
|
|
286
|
+
);
|
|
287
|
+
ModalTitle.displayName = "Modal.Title";
|
|
288
|
+
|
|
289
|
+
export type ModalCloseButtonProps =
|
|
290
|
+
RecursicaOverStyled<MantineModalCloseButtonProps>;
|
|
291
|
+
|
|
292
|
+
const ModalCloseButton = React.forwardRef<
|
|
293
|
+
HTMLButtonElement,
|
|
294
|
+
ModalCloseButtonProps
|
|
295
|
+
>(function ModalCloseButton({ overStyled = false, ...rest }, ref) {
|
|
296
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
297
|
+
return (
|
|
298
|
+
<MantineModal.CloseButton
|
|
299
|
+
ref={ref}
|
|
300
|
+
{...(sanitizedProps as unknown as MantineModalCloseButtonProps)}
|
|
301
|
+
/>
|
|
302
|
+
);
|
|
303
|
+
});
|
|
304
|
+
ModalCloseButton.displayName = "Modal.CloseButton";
|
|
305
|
+
|
|
200
306
|
interface ModalComponent
|
|
201
307
|
extends React.ForwardRefExoticComponent<
|
|
202
308
|
ModalProps & React.RefAttributes<HTMLDivElement>
|
|
203
309
|
> {
|
|
204
|
-
Root: typeof
|
|
205
|
-
Overlay: typeof
|
|
206
|
-
Content: typeof
|
|
207
|
-
Header: typeof
|
|
208
|
-
Title: typeof
|
|
209
|
-
CloseButton: typeof
|
|
310
|
+
Root: typeof ModalRoot;
|
|
311
|
+
Overlay: typeof ModalOverlay;
|
|
312
|
+
Content: typeof ModalContent;
|
|
313
|
+
Header: typeof ModalHeader;
|
|
314
|
+
Title: typeof ModalTitle;
|
|
315
|
+
CloseButton: typeof ModalCloseButton;
|
|
210
316
|
Body: typeof ModalBody;
|
|
211
317
|
Footer: typeof ModalFooter;
|
|
212
318
|
}
|
|
@@ -214,11 +320,11 @@ interface ModalComponent
|
|
|
214
320
|
export const Modal = ModalInner as ModalComponent & {
|
|
215
321
|
Footer: typeof ModalFooter;
|
|
216
322
|
};
|
|
217
|
-
Modal.Root =
|
|
218
|
-
Modal.Overlay =
|
|
219
|
-
Modal.Content =
|
|
220
|
-
Modal.Header =
|
|
221
|
-
Modal.Title =
|
|
222
|
-
Modal.CloseButton =
|
|
323
|
+
Modal.Root = ModalRoot;
|
|
324
|
+
Modal.Overlay = ModalOverlay;
|
|
325
|
+
Modal.Content = ModalContent;
|
|
326
|
+
Modal.Header = ModalHeader;
|
|
327
|
+
Modal.Title = ModalTitle;
|
|
328
|
+
Modal.CloseButton = ModalCloseButton;
|
|
223
329
|
Modal.Body = ModalBody;
|
|
224
330
|
Modal.Footer = ModalFooter;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Modal - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Modal` component in your projects using `@recursica/mantine-adapter`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Modal } from "@recursica/mantine-adapter";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Modal } from "@recursica/mantine-adapter";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Modal opened={isOpen} onClose={close} title="Modal Title">
|
|
24
|
+
<Text>This is a styled Modal wrapping the native primitive.</Text>
|
|
25
|
+
</Modal>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 3. Design System Integration
|
|
33
|
+
|
|
34
|
+
All Recursica components in the `@recursica/mantine-adapter` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
35
|
+
|
|
36
|
+
> [!IMPORTANT]
|
|
37
|
+
>
|
|
38
|
+
> - **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.
|
|
39
|
+
> - **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.
|
|
40
|
+
> - **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.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 4. Key Integration Features & Constraints
|
|
45
|
+
|
|
46
|
+
## Architecture
|
|
47
|
+
|
|
48
|
+
The `Modal` component strictly wraps Mantine's `<Modal>` primitive. We strip Mantine's abstract native styling props (`size`, `radius`, `shadow`) via the `overStyled` interface and strictly inject CSS variable definitions onto the internal node abstractions (`.content`, `.header`, `.body`, `.title`).
|
|
49
|
+
|
|
50
|
+
## Limitations & Structural Decisions
|
|
51
|
+
|
|
52
|
+
### 1. Stripped `size` Prop
|
|
53
|
+
|
|
54
|
+
Mantine natively exposes an abstract `size` prop (`"sm" | "md" | "lg" | "xl"`) that scales the Modal geometry. The Recursica UI Kit explicitly dictates strict geometric bounding boxes: `max-width: 960px` and `min-width: 304px`. To enforce absolute parity with the design system, the `size` prop has been intentionally omitted from the component's interface. The width of the Modal will scale fluidly strictly between these Figma-driven pixel limits.
|
|
55
|
+
|
|
56
|
+
### 2. Scroll Dividers behavior
|
|
57
|
+
|
|
58
|
+
Mantine internally handles scroll state natively, dynamically showing/hiding a divider line when content overflows in `.body`. This logic is tightly coupled to React DOM measurements internally. Our component inherits this dynamic behavior rather than statically rendering a permanent divider, matching Mantine's robust overflow UX. However, we aggressively override the generated `border-bottom` via CSS modules to ensure that when it _does_ appear, it correctly utilizes the `--recursica_ui-kit_components_modal_colors_scroll-divider` variable and `--recursica_ui-kit_components_modal_properties_scroll-divider-thickness` token.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# NumberInput - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `NumberInput` component in your projects using `@recursica/mantine-adapter`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { NumberInput } from "@recursica/mantine-adapter";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { NumberInput } from "@recursica/mantine-adapter";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return <NumberInput label="Quantity" min={1} max={10} defaultValue={1} />;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 3. Design System Integration
|
|
29
|
+
|
|
30
|
+
All Recursica components in the `@recursica/mantine-adapter` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
31
|
+
|
|
32
|
+
> [!IMPORTANT]
|
|
33
|
+
>
|
|
34
|
+
> - **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.
|
|
35
|
+
> - **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.
|
|
36
|
+
> - **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.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 4. Key Integration Features & Constraints
|
|
41
|
+
|
|
42
|
+
## 1. Native Macro Wrapper Bypass
|
|
43
|
+
|
|
44
|
+
**Decision:** The `<NumberInput>` component explicitly bypasses Mantine's native `Input.Wrapper` DOM injections.
|
|
45
|
+
**Implementation:** We pass `label={undefined}`, `description={undefined}`, and `error={undefined}` directly into the primitive `<MantineNumberInput>`. All visual form control geometry is delegated exclusively to our unified `<FormControlWrapper>`, ensuring 100% token adherence for label spacing and assistive text styling without duplicate DOM rendering.
|
|
46
|
+
|
|
47
|
+
## 2. Right Section & Controls Override
|
|
48
|
+
|
|
49
|
+
**Decision:** Passing a `rightSection` element will natively remove the increment/decrement arrow controls.
|
|
50
|
+
**Implementation:** Mantine inherently renders its stepper controls inside the `rightSection` DOM slot. Providing a custom right-aligned icon or text element intentionally overwrites this slot. If a layout strictly requires both a custom right-aligned element and the stepper controls simultaneously, the integrator must manually rebuild the arrows using Mantine's `handlersRef` within a custom right-section wrapper.
|
|
51
|
+
|
|
52
|
+
## 3. Controls Styling
|
|
53
|
+
|
|
54
|
+
**Decision:** The increment/decrement control arrows rely partially on native Mantine CSS inheritance.
|
|
55
|
+
**Implementation:** The current Recursica design system tokens do not provide explicit UI styling parameters (`background`, `border`, `hover` states) for the inner number-input arrows. We have explicitly removed Mantine's default borders to cleanly nest them inside the unified input box, and mapped the icon colors to the generic `trailing-icon` token variable, but further visual configurations currently fall back to Mantine defaults.
|