@recursica/mantine-adapter 0.36.1 → 0.38.1
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/dist/index.d.ts +2892 -2
- 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/package.json +1 -1
- 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
- package/dist/src/OverStyling.d.ts +0 -1
- package/dist/src/Version.d.ts +0 -1
- package/dist/src/components/Accordion/Accordion.d.ts +0 -21
- package/dist/src/components/Accordion/index.d.ts +0 -1
- package/dist/src/components/AssistiveElement/AssistiveElement.d.ts +0 -5
- package/dist/src/components/AutoComplete/AutoComplete.d.ts +0 -11
- package/dist/src/components/Avatar/Avatar.d.ts +0 -18
- package/dist/src/components/Avatar/index.d.ts +0 -1
- package/dist/src/components/Badge/Badge.d.ts +0 -18
- package/dist/src/components/Breadcrumb/Breadcrumb.d.ts +0 -5
- package/dist/src/components/Button/Button.d.ts +0 -30
- package/dist/src/components/Button/index.d.ts +0 -1
- package/dist/src/components/Card/Card.d.ts +0 -59
- package/dist/src/components/Checkbox/Checkbox.d.ts +0 -13
- package/dist/src/components/Checkbox/CheckboxGroup.d.ts +0 -9
- package/dist/src/components/Chip/Chip.d.ts +0 -6
- package/dist/src/components/Container/Container.d.ts +0 -23
- package/dist/src/components/DatePicker/DatePicker.d.ts +0 -9
- package/dist/src/components/Dropdown/Dropdown.d.ts +0 -9
- package/dist/src/components/FileInput/FileInput.d.ts +0 -3
- package/dist/src/components/FileUpload/FileUpload.d.ts +0 -3
- package/dist/src/components/Flex/Flex.d.ts +0 -52
- package/dist/src/components/FormControlLayout/FormControlLayout.d.ts +0 -16
- package/dist/src/components/FormControlWrapper/FormControlWrapper.d.ts +0 -7
- package/dist/src/components/Grid/Grid.d.ts +0 -91
- package/dist/src/components/Group/Group.d.ts +0 -23
- package/dist/src/components/HoverCard/HoverCard.d.ts +0 -45
- package/dist/src/components/Label/Label.d.ts +0 -6
- package/dist/src/components/Label/index.d.ts +0 -1
- package/dist/src/components/Link/Link.d.ts +0 -23
- package/dist/src/components/Link/index.d.ts +0 -1
- package/dist/src/components/Loader/Loader.d.ts +0 -5
- package/dist/src/components/Menu/Menu.d.ts +0 -116
- package/dist/src/components/Modal/Modal.d.ts +0 -54
- package/dist/src/components/Modal/index.d.ts +0 -1
- package/dist/src/components/NumberInput/NumberInput.d.ts +0 -9
- package/dist/src/components/Pagination/Pagination.d.ts +0 -69
- package/dist/src/components/Pagination/Pagination.icons.d.ts +0 -8
- package/dist/src/components/Pagination/index.d.ts +0 -1
- package/dist/src/components/Panel/Panel.d.ts +0 -74
- package/dist/src/components/Popover/Popover.d.ts +0 -47
- package/dist/src/components/Popover/index.d.ts +0 -1
- package/dist/src/components/Radio/Radio.d.ts +0 -13
- package/dist/src/components/Radio/RadioGroup.d.ts +0 -9
- package/dist/src/components/ReadOnlyField/ReadOnlyBooleanField.d.ts +0 -5
- package/dist/src/components/ReadOnlyField/ReadOnlyField.d.ts +0 -12
- package/dist/src/components/ReadOnlyField/ReadOnlySwitchField.d.ts +0 -5
- package/dist/src/components/ReadOnlyField/ReadOnlyTextField.d.ts +0 -8
- package/dist/src/components/ReadOnlyField/WithReadOnlyWrapper.d.ts +0 -28
- package/dist/src/components/ReadOnlyField/index.d.ts +0 -5
- package/dist/src/components/SegmentedControl/SegmentedControl.d.ts +0 -11
- package/dist/src/components/Slider/Slider.d.ts +0 -15
- package/dist/src/components/Stack/Stack.d.ts +0 -42
- package/dist/src/components/Stepper/Stepper.d.ts +0 -15
- package/dist/src/components/Switch/Switch.d.ts +0 -13
- package/dist/src/components/Switch/SwitchGroup.d.ts +0 -9
- package/dist/src/components/Table/Table.d.ts +0 -33
- package/dist/src/components/Tabs/Tabs.d.ts +0 -19
- package/dist/src/components/Text/Text.d.ts +0 -24
- package/dist/src/components/TextArea/TextArea.d.ts +0 -9
- package/dist/src/components/TextField/TextField.d.ts +0 -9
- package/dist/src/components/TimePicker/TimePicker.d.ts +0 -4
- package/dist/src/components/Timeline/Timeline.d.ts +0 -16
- package/dist/src/components/Timeline/TimelineItem.d.ts +0 -14
- package/dist/src/components/Title/Title.d.ts +0 -8
- package/dist/src/components/Toast/Toast.d.ts +0 -11
- package/dist/src/components/Toast/index.d.ts +0 -1
- package/dist/src/components/Tooltip/Tooltip.d.ts +0 -33
- package/dist/src/components/TransferList/TransferList.d.ts +0 -4
- package/dist/src/components/Tree/Tree.d.ts +0 -13
- package/dist/src/components/Tree/index.d.ts +0 -1
- package/dist/src/components/index.d.ts +0 -52
- package/dist/src/index.d.ts +0 -220
- package/dist/src/types/index.d.ts +0 -6
- package/dist/src/utils/ColorSchemeWrapper.d.ts +0 -3
- package/dist/src/utils/RequireAccessibleLabel.d.ts +0 -1
- package/dist/src/utils/copyToClipboard.d.ts +0 -8
- package/dist/src/utils/filterStylingProps.d.ts +0 -28
- package/dist/src/utils/index.d.ts +0 -1
- package/dist/vite.config.d.ts +0 -2
- package/dist/vitest.workspace.d.ts +0 -2
package/package.json
CHANGED
|
@@ -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.
|
|
@@ -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.
|