@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
|
@@ -41,35 +41,7 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
-
## 4.
|
|
44
|
+
## 4. Notes
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
The `FormControlWrapper` is the ultimate structural replacement for Mantine's built-in `Input.Wrapper`. By abandoning Mantine's opinionated wrappers entirely across the design system, we centralize all label tracking, error rendering, ARIA generation, and grid layouts natively inside this single component.
|
|
49
|
-
|
|
50
|
-
### 1. Bypassing `Input.Wrapper`
|
|
51
|
-
|
|
52
|
-
Under the hood of Mantine, elements like `TextInput` heavily rely on `Input.Wrapper`. We actively discourage their use. The central tenet of Recursica Forms is to strip the UI primitive back to its "naked" form (e.g. `<Input />`, `<Checkbox />`) and encapsulate it manually inside `<FormControlWrapper>`.
|
|
53
|
-
|
|
54
|
-
- **Why?** It enforces complete layout mastery. It natively enables `formLayout="side-by-side"` and completely disables Mantine's margin collisions without requiring messy CSS hacks.
|
|
55
|
-
|
|
56
|
-
### 2. The `cloneElement` ARIA Map
|
|
57
|
-
|
|
58
|
-
Because we tore out Mantine's `InputContext` provider (which natively glued error strings to `<input>` tags using React Context), we explicitly utilize `React.cloneElement` on the nested children inside this wrapper.
|
|
59
|
-
|
|
60
|
-
- `aria-describedby` and `aria-errormessage` are dynamically generated using `React.useId()` and physically injected back onto the provided child node. Screen readers rely strictly on this mapping to announce the assistive fields correctly.
|
|
61
|
-
|
|
62
|
-
### 3. Strict `AssistiveElement` Coupling
|
|
63
|
-
|
|
64
|
-
We completely abandoned generic `<Input.Description>` tags. The `FormControlWrapper` directly renders `<AssistiveElement>` primitives, parsing them seamlessly mapping them to `"error"` or `"help"` variants automatically depending on the component's internal state machine.
|
|
65
|
-
|
|
66
|
-
### 4. Dynamic Geometric Variable Payloads
|
|
67
|
-
|
|
68
|
-
Because `FormControlWrapper` acts as an agnostic grid box encompassing raw primitives (like `TextField`, `Select`), it initially stretches `100%` across horizontal bounds.
|
|
69
|
-
|
|
70
|
-
- **The Bug:** If a child `TextField` carries its own hardcoded `max-width` token, it stops expanding early, but the wrapper and `<Label>` keep expanding, causing right-aligned labels to aggressively float past the field to the screen's edge dynamically.
|
|
71
|
-
- **The Variable Payload Resolution:** Instead of destroying grids with `width: fit-content` arrays, primitive components are required to pass their local `max-width` tokens UP to the wrapper explicitly via React `style`:
|
|
72
|
-
```tsx
|
|
73
|
-
<FormControlWrapper style={{ "--form-control-max-width": "var(--...)" }}>
|
|
74
|
-
```
|
|
75
|
-
The wrapper natively respects `max-width: var(--form-control-max-width, 100%)`. This structurally unifies the bounding caps so right-aligned labels flawlessly snap tightly to the explicit boundary edge of the specific primitive it is wrapping.
|
|
46
|
+
- `FormControlWrapper` renders the label, error, and help text around the child input; screen-reader associations between the input and its assistive text are handled automatically.
|
|
47
|
+
- The wrapper stretches to fill its container by default. If the wrapped input has its own maximum width, pass a matching `--form-control-max-width` CSS variable via the `style` prop so the label and assistive text align to the same width as the input.
|
|
@@ -36,7 +36,7 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
36
36
|
|
|
37
37
|
> [!IMPORTANT]
|
|
38
38
|
>
|
|
39
|
-
> - **Anti-override protection**: `Grid` is a primitive layout component (see [OVERSTYLING.md](../../../OVERSTYLING.md))
|
|
39
|
+
> - **Anti-override protection**: `Grid` is a primitive layout component (see [OVERSTYLING.md](../../../OVERSTYLING.md)), so standard Mantine layout props pass through freely without needing `overStyled`.
|
|
40
40
|
> - **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.
|
|
41
41
|
> - **Variables and Theming**: Spacing is entirely determined by the `rec-*` token scale, mapped transparently to standard Mantine gutter values.
|
|
42
42
|
|
|
@@ -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 `Group` component is a generic flex layout wrapper mapped directly to Mantine's `Group`.
|
|
48
|
-
|
|
48
|
+
`gap`, `align`, `wrap`, and `justify` all pass through as normal.
|
|
@@ -46,76 +46,7 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
46
46
|
|
|
47
47
|
---
|
|
48
48
|
|
|
49
|
-
## 4.
|
|
49
|
+
## 4. Notes
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
**Decision:** We maintain the exact library composition API structure (`<HoverCard>`, `<HoverCard.Target>`, `<HoverCard.Dropdown>`) as a 1:1 React component mapping.
|
|
54
|
-
|
|
55
|
-
**Implementation:** Mantine's HoverCard internally manages hover detection, open/close delays, Floating UI positioning, and portal rendering. By preserving the exact sub-component tree, Recursica safely inherits all of these behaviors without reimplementation.
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## 2. HoverCard.Target Pass-Through
|
|
60
|
-
|
|
61
|
-
**Decision:** `HoverCard.Target` is a transparent pass-through with no styling applied.
|
|
62
|
-
|
|
63
|
-
**Implementation:** The target wrapper exists solely to manage Mantine's ref forwarding and hover 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>`). This is identical to the `Menu.Target` pattern.
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## 3. Token Namespace: `hover-card-popover`
|
|
68
|
-
|
|
69
|
-
**Decision:** The CSS module exclusively uses variables from the `--recursica_ui-kit_components_hover-card-popover_*` namespace.
|
|
70
|
-
|
|
71
|
-
**Implementation:** The Recursica token system defines a single shared namespace (`hover-card-popover`) for this component covering geometry (border-radius, border-size, padding, min/max-width), typography (content-text\_\*), elevation, and layer-aware colors (background, border-color, content). No tokens from other component namespaces are referenced.
|
|
72
|
-
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
## 4. Hardcoded Values
|
|
76
|
-
|
|
77
|
-
**Decision:** Two hardcoded values exist in the component.
|
|
78
|
-
|
|
79
|
-
### `border-style: solid` (CSS module)
|
|
80
|
-
|
|
81
|
-
Mantine renders the dropdown using its `Paper` component, which does not set `border-style` natively. Without this hardcoded value, the border-width and border-color tokens would have no visible effect. This is the same pattern used in the Menu component's dropdown.
|
|
82
|
-
|
|
83
|
-
### `arrowSize` defaulted to `16` (HoverCard.tsx)
|
|
84
|
-
|
|
85
|
-
Mantine's `arrowSize` prop is a JavaScript number used for inline style calculations: it sets `width`, `height`, and a positioning offset (`-arrowSize/2`) directly on the arrow `<div>` element. These inline styles **cannot** be overridden via CSS without `!important`, and the positioning offset has no CSS equivalent. This means the beak size cannot be fully CSS-driven — it is one of the rare cases where a design token value must be mirrored as a JS prop.
|
|
86
|
-
|
|
87
|
-
The default value `16` matches the Recursica `beak-size` token (`--recursica_ui-kit_components_hover-card-popover_properties_beak-size: 16px`). Developers can override `arrowSize` if needed, but should be aware this is a design system concern. If the token value changes, the default in `HoverCard.tsx` must also be updated.
|
|
88
|
-
|
|
89
|
-
This is documented as an open issue in `docs/COMPONENT_ISSUES.md`.
|
|
90
|
-
|
|
91
|
-
**Note:** Mantine calls this the "arrow"; Recursica calls it the "beak". The Recursica prop `withBeak` (defaulting to `true`) maps to Mantine's `withArrow`. Both `withBeak` and `withArrow` are accepted; `withBeak` takes precedence.
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## 5. Minimal CSS Override Philosophy
|
|
96
|
-
|
|
97
|
-
**Decision:** The CSS module only overrides visual design tokens (colors, typography, spacing, borders, shadows). All structural layout properties are deferred to Mantine's native behavior.
|
|
98
|
-
|
|
99
|
-
**Implementation:** HoverCard is an overlay component where Mantine's native Floating UI positioning and Paper layout are already correct. We avoid setting:
|
|
100
|
-
|
|
101
|
-
- `overflow` on the dropdown (Mantine handles scroll behavior natively)
|
|
102
|
-
- `display`, `position`, `z-index` (Floating UI controls these)
|
|
103
|
-
- `pointer-events` (Mantine manages hover detection across target and dropdown)
|
|
104
|
-
|
|
105
|
-
**Rationale:** The Menu implementation demonstrated that aggressive structural resets (overflow, box-sizing) on overlay components cause layout breakage. Default to Mantine's native behavior and only override what the Recursica token system explicitly needs to control.
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
## 6. ClassNames Merging on Root
|
|
110
|
-
|
|
111
|
-
**Decision:** The root `HoverCard` component binds CSS module classes via `classNames` on the Mantine root, identical to the Menu pattern.
|
|
112
|
-
|
|
113
|
-
**Implementation:** The root component receives `classNames={{ dropdown: styles.dropdown }}` and merges any consumer-provided `classNames` when `overStyled` is true. This ensures our token-driven styles are applied to the dropdown panel without wrapper divs, and the consumer's classes are additive.
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
## 7. Default Position Override
|
|
118
|
-
|
|
119
|
-
**Decision:** Recursica defaults `position` to `"top"`. Mantine defaults to `"bottom"`.
|
|
120
|
-
|
|
121
|
-
**Implementation:** The `position="top"` default is set on the Mantine root element before the prop spread, so developer-provided `position` values still take precedence. This aligns with Recursica's design intent for overlay components to appear above their trigger by default.
|
|
51
|
+
- Mantine calls the pointer indicator the "arrow"; Recursica calls it the "beak". Use the `withBeak` prop (default `true`) to show or hide it; `withArrow` is also accepted for compatibility, with `withBeak` taking precedence.
|
|
52
|
+
- The default `position` is `"top"` (Mantine's default is `"bottom"`); pass your own `position` prop to override it.
|
|
@@ -37,51 +37,11 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
-
## 4.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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`).
|
|
40
|
+
## 4. Behavior Notes
|
|
41
|
+
|
|
42
|
+
- A label cannot be both required and optional: if `required` is `true`, `optionalText` is not rendered.
|
|
43
|
+
- Set `optionalText` to `true` to render the default "(Optional)" text, or pass a custom string for different wording.
|
|
44
|
+
- `withEditIcon` and `required` are mutually exclusive: when both are set, the edit icon is shown in place of the required asterisk.
|
|
45
|
+
- `labelSize` only affects layout when the surrounding form uses `formLayout="side-by-side"`, where it constrains the label's width.
|
|
46
|
+
- `Label` does not currently support a `description` prop.
|
|
47
|
+
- The edit icon does not currently have a distinct hover background.
|
|
@@ -47,16 +47,10 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
47
47
|
|
|
48
48
|
The design tokens (`recursica_variables_scoped.css`) provide the base link styling directly on `--recursica_ui-kit_components_link_properties_*` (no distinct `default` state), plus a `visited` variant that overrides only `colors_text-color`/`colors_icon-color`. There is no per-state token for `hover` anymore (a prior schema version had one); the component currently applies no distinct hover treatment beyond the browser's native `cursor: pointer`. There are no tokens for `active` or `focus` either; the component relies on the browser's default focus outline for accessibility unless overridden by a global reset.
|
|
49
49
|
|
|
50
|
-
##
|
|
50
|
+
## Underline Behavior
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
`Link` does not use Mantine's automatic hover-underline behavior; text decoration is fully controlled by the design system's tokens.
|
|
53
53
|
|
|
54
|
-
##
|
|
54
|
+
## Icon Support
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
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.
|
|
59
|
-
|
|
60
|
-
## Inner Wrappers
|
|
61
|
-
|
|
62
|
-
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.
|
|
56
|
+
When an `icon` is provided, it renders alongside the link text with spacing between them applied automatically via design tokens.
|
|
@@ -37,27 +37,8 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
-
## 4.
|
|
40
|
+
## 4. Notes
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
The `
|
|
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`.
|
|
42
|
+
- `variant` maps to Mantine's loader types: `"oval"`, `"bars"`, or `"dots"`.
|
|
43
|
+
- `thickness` and `border-radius` are not exposed as props; sizing is controlled entirely by the `size` prop.
|
|
44
|
+
- The `xs` and `xl` sizes are not currently supported.
|
|
@@ -48,77 +48,7 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
48
48
|
|
|
49
49
|
---
|
|
50
50
|
|
|
51
|
-
## 4.
|
|
51
|
+
## 4. Notes
|
|
52
52
|
|
|
53
|
-
|
|
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.
|
|
53
|
+
- The full Mantine composition API is supported, including sub-menus: `Menu`, `Menu.Target`, `Menu.Dropdown`, `Menu.Item`, `Menu.Divider`, `Menu.Label`, `Menu.Sub`, `Menu.Sub.Target`, `Menu.Sub.Item`, and `Menu.Sub.Dropdown`.
|
|
54
|
+
- The `color` prop on `Menu.Item` (and `Menu.Sub.Item`) — used by Mantine for semantics like a "danger" item — is ignored unless `overStyled={true}` is set.
|
|
@@ -45,7 +45,7 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
45
45
|
|
|
46
46
|
## Architecture
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
`Modal` wraps Mantine's `<Modal>` component. Native Mantine styling props (`size`, `radius`, `shadow`) are not used — appearance and sizing are fully controlled by the design system tokens instead.
|
|
49
49
|
|
|
50
50
|
## Limitations & Structural Decisions
|
|
51
51
|
|
|
@@ -53,6 +53,6 @@ The `Modal` component strictly wraps Mantine's `<Modal>` primitive. We strip Man
|
|
|
53
53
|
|
|
54
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
55
|
|
|
56
|
-
### 2. Scroll Dividers
|
|
56
|
+
### 2. Scroll Dividers
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
When the modal's content overflows and becomes scrollable, a divider line automatically appears, styled using the design system's scroll-divider color and thickness tokens.
|
|
@@ -39,17 +39,14 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
39
39
|
|
|
40
40
|
## 4. Key Integration Features & Constraints
|
|
41
41
|
|
|
42
|
-
## 1.
|
|
42
|
+
## 1. Label, Description, and Error Rendering
|
|
43
43
|
|
|
44
|
-
|
|
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.
|
|
44
|
+
Label, description, and error text are rendered using Recursica's standard form-control layout rather than Mantine's native label/description/error rendering, so spacing and styling stay consistent with other form fields.
|
|
46
45
|
|
|
47
|
-
## 2. Right Section & Controls
|
|
46
|
+
## 2. Right Section & Controls
|
|
48
47
|
|
|
49
|
-
|
|
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.
|
|
48
|
+
Providing a custom `rightSection` element replaces the built-in increment/decrement controls. To use both together, rebuild the controls manually using Mantine's `handlersRef` API within your custom right section.
|
|
51
49
|
|
|
52
50
|
## 3. Controls Styling
|
|
53
51
|
|
|
54
|
-
|
|
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.
|
|
52
|
+
The increment/decrement control icons currently fall back to Mantine's default styling beyond their color, as design tokens for their background, border, and hover states are not yet defined.
|
|
@@ -34,22 +34,3 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
34
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
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
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 Decision: CSS Inheritance vs. Composition
|
|
43
|
-
|
|
44
|
-
The Figma design tokens for the `Pagination` component dictate that pagination pages perfectly mimic `Button` variants (e.g. `active-pages_style: "solid"`, `inactive-pages_style: "outline"`, `navigation-controls_style: "text"`).
|
|
45
|
-
|
|
46
|
-
As of the `1.2.0` scoped CSS update, the Figma exporter automatically handles these variants. It flattens and aliases the referenced Button properties directly into the `Pagination` component's variable namespace.
|
|
47
|
-
|
|
48
|
-
We opted to use Mantine's native `PaginationControl` components to ensure all DOM structure, focus management, and accessibility attributes are preserved natively without us needing to carefully rebuild `Pagination.Items` mappings.
|
|
49
|
-
|
|
50
|
-
To honor the Figma design intents while using Mantine's raw `<button>` elements:
|
|
51
|
-
|
|
52
|
-
1. We inherit and map all natively scoped `Pagination` variant styles (small typography, outline/solid/text colors, and hover overlays) directly into `.control` and `.control[data-active]` within `Pagination.module.css`. We do not need to manually reference `Button` variables cross-component.
|
|
53
|
-
2. We inject `data-variant="text"` via `getControlProps` onto the navigation buttons so that they inherit the explicitly aliased text style variables (`navigation-controls`) defined by the UI Kit for pagination.
|
|
54
|
-
|
|
55
|
-
This achieves exact optical alignment with the tokens while maintaining Mantine's robust internal event handling for pagination.
|
|
@@ -43,103 +43,14 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
43
43
|
|
|
44
44
|
## 4. Key Integration Features & Constraints
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
### Placement
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
Use the `placement` prop (not `position`) to choose which edge the panel slides in from: `"left"`, `"right"`, `"top"`, or `"bottom"`. It defaults to `"right"`.
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
### Panel.Footer
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
- Overlay/backdrop
|
|
54
|
-
- Portal rendering
|
|
55
|
-
- Focus trapping
|
|
56
|
-
- Scroll locking
|
|
57
|
-
- Close button and title in header
|
|
52
|
+
A `Panel.Footer` sub-component is available for footer content and action buttons.
|
|
58
53
|
|
|
59
|
-
|
|
54
|
+
### Content Overflow
|
|
60
55
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
## 2. Token Namespace: `panel`
|
|
64
|
-
|
|
65
|
-
**Decision:** The CSS module exclusively uses variables from the `--recursica_ui-kit_components_panel_*` namespace.
|
|
66
|
-
|
|
67
|
-
**Implementation:** The Recursica token system defines the `panel` namespace covering:
|
|
68
|
-
|
|
69
|
-
- Geometry: border-radius, border-size, min-width (200px), max-width (960px)
|
|
70
|
-
- Content padding: content-horizontal-padding (xl), content-vertical-padding (lg)
|
|
71
|
-
- Header/Footer padding: header-footer-horizontal-padding (xl), header-footer-vertical-padding (md)
|
|
72
|
-
- Spacing: header-close-gap (md), footer-button-gap (md)
|
|
73
|
-
- Divider: divider-size (1px), divider-color
|
|
74
|
-
- Elevation: elevation-3
|
|
75
|
-
- Colors (layer-aware): background, border-color, content, divider-color, header-footer-background, title
|
|
76
|
-
- Non-CSS: header-style ("h3") — see §7
|
|
77
|
-
|
|
78
|
-
No tokens from other component namespaces are referenced.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## 3. ClassNames Mapping to Drawer
|
|
83
|
-
|
|
84
|
-
**Decision:** Panel maps CSS module classes to Mantine Drawer's stylesNames.
|
|
85
|
-
|
|
86
|
-
**Implementation:** The Drawer stylesNames used are:
|
|
87
|
-
|
|
88
|
-
- `content` — Outer container (background, border, elevation)
|
|
89
|
-
- `header` — Title bar with close button (padding, divider, gap)
|
|
90
|
-
- `title` — Title text color
|
|
91
|
-
- `body` — Scrollable content area (padding)
|
|
92
|
-
|
|
93
|
-
Other stylesNames (`overlay`, `root`, `inner`, `close`) are left to Mantine defaults.
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
## 4. Default Placement Override
|
|
98
|
-
|
|
99
|
-
**Decision:** Use `placement` instead of `position` for configuring slide-out direction, and default it to `"right"`.
|
|
100
|
-
|
|
101
|
-
**Implementation:** The prop was renamed from `position` to `placement` to prevent collision with the CSS `position` keyword, which is strictly blocked by the styling gatekeeper (`BLOCKED_STYLING_KEYS`). This allows configuring the drawer direction natively while maintaining strict design-system boundaries. The `placement="right"` default is mapped internally to Mantine Drawer's `position` prop before any other sanitized props are applied. Right-side panels are the most common pattern for supplementary content, settings, and detail views.
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## 5. Custom Panel.Footer
|
|
106
|
-
|
|
107
|
-
**Decision:** A custom `Panel.Footer` sub-component is provided. Mantine's Drawer does not have a native footer.
|
|
108
|
-
|
|
109
|
-
**Implementation:** `Panel.Footer` is a `<div>` with inline styles referencing Recursica CSS variables for:
|
|
110
|
-
|
|
111
|
-
- `header-footer-background` and `header-footer-padding` tokens
|
|
112
|
-
- Top divider using `divider-size` and `divider-color`
|
|
113
|
-
- `footer-button-gap` for action button spacing
|
|
114
|
-
- `margin-top: auto` to push the footer to the bottom
|
|
115
|
-
|
|
116
|
-
Inline styles are used instead of a CSS module class because the footer is rendered inside the Drawer's `<body>` element, and the CSS variables are applied to the body's parent container. The inline styles ensure the footer correctly references the panel tokens regardless of DOM position.
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
## 6. Hardcoded Values
|
|
121
|
-
|
|
122
|
-
### `border-style: solid` (CSS module, `.content`)
|
|
123
|
-
|
|
124
|
-
Mantine's Drawer content does not set `border-style` natively. Without this, the border-width and border-color tokens have no visible effect. Same pattern as Card, Menu, HoverCard, Tooltip.
|
|
125
|
-
|
|
126
|
-
---
|
|
127
|
-
|
|
128
|
-
## 7. `header-style` Typography Utility Class
|
|
129
|
-
|
|
130
|
-
**Decision:** The `header-style` token exports as the string `"h3"`, so we use the generated global utility class `.recursica_brand_typography_h3`.
|
|
131
|
-
|
|
132
|
-
**Implementation:** The PostCSS compiler generates `.recursica_brand_typography_<typeName>` classes at the bottom of the scoped variables file to apply full typography definitions without assigning variables inline. We apply this to the `.title` class via `composes: recursica_brand_typography_h3 from global;`.
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
## 8. Panel Types: Standard vs Scrollable
|
|
137
|
-
|
|
138
|
-
**Decision:** Both standard and scrollable types are supported natively.
|
|
139
|
-
|
|
140
|
-
**Implementation:** Per the Recursica specification:
|
|
141
|
-
|
|
142
|
-
- **Standard** — All content visible without scrolling. The default behavior when content fits.
|
|
143
|
-
- **Scrollable** — Internal scrollbar enabled when content exceeds the panel height. Header and footer CTAs remain pinned.
|
|
144
|
-
|
|
145
|
-
Mantine's Drawer handles this automatically — the `body` section scrolls when content overflows, while the `header` remains fixed. The `Panel.Footer` uses `margin-top: auto` to stay at the bottom.
|
|
56
|
+
When content exceeds the panel's available height, the body scrolls internally while the header and footer stay fixed in place.
|
|
@@ -48,74 +48,14 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
48
48
|
|
|
49
49
|
## 4. Key Integration Features & Constraints
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
### Composition
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
`Popover`, `Popover.Target`, and `Popover.Dropdown` are used together the same way as in Mantine: `Popover.Target` wraps the trigger element and applies no styling of its own, while `Popover.Dropdown` renders the styled panel content.
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
### Beak (Arrow)
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
## 2. Popover.Target Pass-Through
|
|
60
|
-
|
|
61
|
-
**Decision:** `Popover.Target` is a transparent pass-through with no styling applied.
|
|
62
|
-
|
|
63
|
-
**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>`). This is identical to the `Menu.Target` and `HoverCard.Target` pattern.
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## 3. Token Namespace: `hover-card-popover`
|
|
68
|
-
|
|
69
|
-
**Decision:** The CSS module exclusively uses variables from the `--recursica_ui-kit_components_hover-card-popover_*` namespace.
|
|
70
|
-
|
|
71
|
-
**Implementation:** The Recursica token system defines a single shared namespace (`hover-card-popover`) for this component and HoverCard. It covers geometry (border-radius, border-size, padding, min/max-width), typography (content-text\_\*), elevation, and layer-aware colors (background, border-color, content).
|
|
72
|
-
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
## 4. Hardcoded Values
|
|
76
|
-
|
|
77
|
-
**Decision:** Two hardcoded values exist in the component.
|
|
78
|
-
|
|
79
|
-
### `border-style: solid` (CSS module)
|
|
80
|
-
|
|
81
|
-
Mantine renders the dropdown using its `Paper` component, which does not set `border-style` natively. Without this hardcoded value, the border-width and border-color tokens would have no visible effect. This is the same pattern used in the Menu component's dropdown.
|
|
82
|
-
|
|
83
|
-
### `arrowSize` defaulted to `16` (Popover.tsx)
|
|
84
|
-
|
|
85
|
-
Mantine's `arrowSize` prop is a JavaScript number used for inline style calculations: it sets `width`, `height`, and a positioning offset (`-arrowSize/2`) directly on the arrow `<div>` element. These inline styles **cannot** be overridden via CSS without `!important`, and the positioning offset has no CSS equivalent. This means the beak size cannot be fully CSS-driven — it is one of the rare cases where a design token value must be mirrored as a JS prop.
|
|
86
|
-
|
|
87
|
-
The default value `16` matches the Recursica `beak-size` token (`--recursica_ui-kit_components_hover-card-popover_properties_beak-size: 16px`). Developers can override `arrowSize` if needed, but should be aware this is a design system concern. If the token value changes, the default in `Popover.tsx` must also be updated.
|
|
88
|
-
|
|
89
|
-
This is documented as an open issue in `docs/COMPONENT_ISSUES.md`.
|
|
90
|
-
|
|
91
|
-
**Note:** Mantine calls this the "arrow"; Recursica calls it the "beak". The Recursica prop `withBeak` (defaulting to `true`) maps to Mantine's `withArrow`. Both `withBeak` and `withArrow` are accepted; `withBeak` takes precedence.
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## 5. Minimal CSS Override Philosophy
|
|
96
|
-
|
|
97
|
-
**Decision:** The CSS module only overrides visual design tokens (colors, typography, spacing, borders, shadows). All structural layout properties are deferred to Mantine's native behavior.
|
|
98
|
-
|
|
99
|
-
**Implementation:** Popover is an overlay component where Mantine's native Floating UI positioning and Paper layout are already correct. We avoid setting:
|
|
100
|
-
|
|
101
|
-
- `overflow` on the dropdown (Mantine handles scroll behavior natively)
|
|
102
|
-
- `display`, `position`, `z-index` (Floating UI controls these)
|
|
103
|
-
- `pointer-events` (Mantine manages hover detection across target and dropdown)
|
|
104
|
-
|
|
105
|
-
**Rationale:** Default to Mantine's native behavior and only override what the Recursica token system explicitly needs to control.
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
## 6. ClassNames Merging on Root
|
|
110
|
-
|
|
111
|
-
**Decision:** The root `Popover` component binds CSS module classes via `classNames` on the Mantine root.
|
|
112
|
-
|
|
113
|
-
**Implementation:** The root component receives `classNames={{ dropdown: styles.dropdown, arrow: styles.arrow }}` and merges any consumer-provided `classNames` when `overStyled` is true. This ensures our token-driven styles are applied to the dropdown panel without wrapper divs, and the consumer's classes are additive.
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
## 7. Default Position Override
|
|
57
|
+
The Recursica prop `withBeak` (defaulting to `true`) controls whether the pointer beak is shown, and maps to Mantine's `withArrow`. Both `withBeak` and `withArrow` are accepted; `withBeak` takes precedence. An `arrowSize` prop is also available (default `16`) to size the beak.
|
|
118
58
|
|
|
119
|
-
|
|
59
|
+
### Default Position
|
|
120
60
|
|
|
121
|
-
|
|
61
|
+
Recursica defaults `position` to `"top"` rather than Mantine's `"bottom"`. Pass your own `position` value to override it.
|