@recursica/mantine-adapter 0.55.1 → 0.55.2
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 +16 -0
- package/dist/index.d.ts +21 -0
- 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 +905 -873
- package/dist/mantine-adapter.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Accordion/Accordion.stories.tsx +0 -24
- package/src/components/AssistiveElement/AssistiveElement.stories.tsx +3 -9
- package/src/components/Avatar/Avatar.stories.tsx +0 -15
- package/src/components/Breadcrumb/BREADCRUMB_IMPLEMENTATION_NOTES.md +33 -0
- package/src/components/Breadcrumb/Breadcrumb.module.css +20 -0
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +55 -5
- package/src/components/Breadcrumb/Breadcrumb.tsx +17 -3
- package/src/components/Breadcrumb/markCurrentPageItem.test.ts +49 -0
- package/src/components/Button/Button.module.css +16 -0
- package/src/components/Button/Button.tsx +14 -1
- package/src/components/Button/IMPLEMENTATION_NOTES.md +31 -5
- package/src/components/DatePicker/DATEPICKER_IMPLEMENTATION_NOTES.md +2 -1
- package/src/components/DatePicker/DatePicker.tsx +22 -8
- package/src/components/Grid/GRID_IMPLEMENTATION_NOTES.md +9 -0
- package/src/components/Grid/Grid.stories.tsx +24 -0
- package/src/components/Link/IMPLEMENTATION_NOTES.md +1 -1
- package/src/components/Link/Link.module.css +20 -0
- package/src/components/NumberInput/NUMBER_INPUT_IMPLEMENTATION_NOTES.md +6 -0
- package/src/components/NumberInput/NumberInput.module.css +11 -0
- package/src/components/Stepper/IMPLEMENTATION_NOTES.md +28 -0
- package/src/components/Stepper/Stepper.module.css +6 -6
- package/src/components/Tabs/IMPLEMENTATION_NOTES.md +27 -0
- package/src/components/Tabs/Tabs.module.css +30 -9
- package/src/components/TimePicker/TIMEPICKER_IMPLEMENTATION_NOTES.md +31 -0
- package/src/components/TimePicker/TimePicker.module.css +30 -3
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Stepper Implementation Notes
|
|
2
|
+
|
|
3
|
+
## Completed/current label & description colors never applied (source-of-truth audit, 2026-08-30)
|
|
4
|
+
|
|
5
|
+
**Bug:** `.step[data-progress="completed"]`, `.step[data-progress="progress"]`, and
|
|
6
|
+
`.step[data-progress="pending"]` selectors in `Stepper.module.css` checked `data-progress` for
|
|
7
|
+
literal string values (`"completed"`/`"progress"`/`"pending"`) that Mantine's `Stepper.Step` never
|
|
8
|
+
sets. Mantine actually stamps two independent boolean-presence attributes on the step root:
|
|
9
|
+
`data-completed` (present, value `"true"`, when the step index is before `active`) and
|
|
10
|
+
`data-progress` (present, value `"true"`, only on the active step); neither attribute exists at
|
|
11
|
+
all on upcoming steps. Since `[data-progress="completed"]` and `[data-progress="pending"]` never
|
|
12
|
+
match anything real, every step's label and description silently fell through to Mantine's own
|
|
13
|
+
unstyled defaults instead of any Recursica token — for description text specifically, that meant
|
|
14
|
+
Mantine's native muted/dimmed gray (`rgb(134, 142, 150)`, not any `--recursica_*` variable)
|
|
15
|
+
appeared on _every_ step regardless of state, including completed/current steps where the design
|
|
16
|
+
tokens (`..._completed-description-color`/`..._current-description-color`) both resolve to the
|
|
17
|
+
same near-black `layer-0_elements_text_color` as the label. This was visually indistinguishable
|
|
18
|
+
for labels (Mantine's own default text color happens to look close to black too) but clearly
|
|
19
|
+
visible for descriptions, and was mistaken for a mui-adapter bug (mui's class-based `.Mui-active`/
|
|
20
|
+
`.Mui-completed` selectors were already correctly reading these tokens, so mui rendered
|
|
21
|
+
completed/current descriptions in the token's actual dark color while mantine — the presumed
|
|
22
|
+
source of truth — rendered them in this incidental gray).
|
|
23
|
+
|
|
24
|
+
**Fix:** Match the same working pattern already used one selector up for `.stepIcon` (`.stepIcon
|
|
25
|
+
[data-completed]` / `.stepIcon[data-progress]`, which check attribute _presence_, not a value) —
|
|
26
|
+
changed the `.step` label/description rules to `[data-completed]` / `[data-progress]` /
|
|
27
|
+
`:not([data-completed]):not([data-progress])`. No `mui-adapter` change was needed for this: its
|
|
28
|
+
class-based state selectors were already correct against the design tokens.
|
|
@@ -298,13 +298,13 @@
|
|
|
298
298
|
height: var(--stepper-svg-size);
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
.root .step[data-
|
|
301
|
+
.root .step[data-completed] .stepLabel {
|
|
302
302
|
color: var(
|
|
303
303
|
--recursica_ui-kit_components_stepper_properties_colors_completed-label-color
|
|
304
304
|
);
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
-
.root .step[data-
|
|
307
|
+
.root .step[data-completed] .stepDescription {
|
|
308
308
|
color: var(
|
|
309
309
|
--recursica_ui-kit_components_stepper_properties_colors_completed-description-color
|
|
310
310
|
);
|
|
@@ -323,26 +323,26 @@
|
|
|
323
323
|
);
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
-
.root .step[data-progress
|
|
326
|
+
.root .step[data-progress] .stepLabel {
|
|
327
327
|
color: var(
|
|
328
328
|
--recursica_ui-kit_components_stepper_properties_colors_current-label-color
|
|
329
329
|
);
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
-
.root .step[data-progress
|
|
332
|
+
.root .step[data-progress] .stepDescription {
|
|
333
333
|
color: var(
|
|
334
334
|
--recursica_ui-kit_components_stepper_properties_colors_current-description-color
|
|
335
335
|
);
|
|
336
336
|
}
|
|
337
337
|
|
|
338
338
|
/* Upcoming State (Pending Labels) */
|
|
339
|
-
.root .step[data-progress
|
|
339
|
+
.root .step:not([data-completed]):not([data-progress]) .stepLabel {
|
|
340
340
|
color: var(
|
|
341
341
|
--recursica_ui-kit_components_stepper_properties_colors_upcoming-label-color
|
|
342
342
|
);
|
|
343
343
|
}
|
|
344
344
|
|
|
345
|
-
.root .step[data-progress
|
|
345
|
+
.root .step:not([data-completed]):not([data-progress]) .stepDescription {
|
|
346
346
|
color: var(
|
|
347
347
|
--recursica_ui-kit_components_stepper_properties_colors_upcoming-description-color
|
|
348
348
|
);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Tabs Implementation Notes
|
|
2
|
+
|
|
3
|
+
## `inverted` never actually moved the tab list below the content (2026-08-30, source-of-truth audit)
|
|
4
|
+
|
|
5
|
+
**Reported symptom:** in the `Inverted` story, content should render above the tab list (tabs
|
|
6
|
+
below), with padding between them — the padding looked missing "when content is on top".
|
|
7
|
+
|
|
8
|
+
**What was actually happening:** `inverted` is a real, native `@mantine/core` `Tabs` prop
|
|
9
|
+
(confirmed by reading `@mantine/core`'s own `Tabs.cjs`/`Tabs.css`) — this adapter doesn't even
|
|
10
|
+
reference it directly, it flows straight through `...rest` to `<MantineTabs>`. But Mantine's own
|
|
11
|
+
`inverted` support only flips the active-indicator line and border-radius direction (top vs
|
|
12
|
+
bottom) via `data-inverted` CSS selectors; it does not reposition `.list` below `.panel`. The
|
|
13
|
+
story always renders `<Tabs.List>` before the `<Tabs.Panel>`s in JSX regardless of `inverted`, so
|
|
14
|
+
"padding missing when content is on top" wasn't reproducible as such: content was never on top to
|
|
15
|
+
begin with, before this fix.
|
|
16
|
+
|
|
17
|
+
**Fix:** Mantine renders `Tabs.List`/`Tabs.Panel` as flat siblings directly under `.root` despite
|
|
18
|
+
the nested JSX (confirmed via live DOM dump) — so making `.root[data-orientation="horizontal"]`
|
|
19
|
+
a flex column and giving `.list` `order: 1` only when `[data-inverted]` reorders them visually
|
|
20
|
+
with zero DOM changes, no compound-component internals to touch. Scoped to horizontal only —
|
|
21
|
+
vertical's "instead of left" flip isn't exercised by any story. Also introduced a shared
|
|
22
|
+
`--tabs-content-gap` custom property per variant (previously each variant inlined its own long
|
|
23
|
+
token reference directly into `.list`'s `margin-bottom`) so the same gap can be redirected:
|
|
24
|
+
`margin-bottom: 0; margin-top: var(--tabs-content-gap);` when inverted, since the gap now needs
|
|
25
|
+
to land above the now-trailing tab list instead of below it. Verified live against mui-adapter's
|
|
26
|
+
identical fix (see its own `Tabs/IMPLEMENTATION_NOTES.md`) — pixel-equivalent stacking order and
|
|
27
|
+
gap; no regression on Default/Outline/Pills/Vertical stories.
|
|
@@ -21,6 +21,24 @@
|
|
|
21
21
|
.panel (content)
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
/* `inverted` (RecursicaTabsProps): "tabs list at the bottom ... instead of top". Mantine's own
|
|
25
|
+
Tabs only reuses `data-inverted` to flip indicator-line/border-radius direction (see
|
|
26
|
+
@mantine/core's Tabs.css) — it does NOT move `.list` below `.panel`, since both are plain
|
|
27
|
+
block-level children stacking in DOM order. `.list`/`.panel` here are direct siblings under
|
|
28
|
+
this same `.root` (Mantine renders Tabs.List/Tabs.Panel flat, despite the nested JSX), so a
|
|
29
|
+
flex column + `order` on `.list` alone reorders them visually with no DOM change. Scoped to
|
|
30
|
+
horizontal only — vertical's "instead of left" flip isn't exercised by any story yet.
|
|
31
|
+
See IMPLEMENTATION_NOTES.md. */
|
|
32
|
+
.root[data-orientation="horizontal"] {
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
}
|
|
36
|
+
.root[data-orientation="horizontal"][data-inverted] .list {
|
|
37
|
+
order: 1;
|
|
38
|
+
margin-bottom: 0;
|
|
39
|
+
margin-top: var(--tabs-content-gap);
|
|
40
|
+
}
|
|
41
|
+
|
|
24
42
|
/* ---------------------------------
|
|
25
43
|
VARIANTS
|
|
26
44
|
Sizing, geometry, colors, and typography are all scoped per style (default/outline/pills) in
|
|
@@ -72,13 +90,14 @@
|
|
|
72
90
|
--tabs-space-between-tabs: var(
|
|
73
91
|
--recursica_ui-kit_components_tabs_variants_styles_default_variants_orientation_horizontal_properties_space-between-tabs
|
|
74
92
|
);
|
|
93
|
+
--tabs-content-gap: var(
|
|
94
|
+
--recursica_ui-kit_components_tabs_variants_styles_default_variants_orientation_horizontal_properties_tabs-content-gap
|
|
95
|
+
);
|
|
75
96
|
}
|
|
76
97
|
.root[data-variant="default"][data-orientation="horizontal"] .list {
|
|
77
98
|
gap: var(--tabs-space-between-tabs);
|
|
78
99
|
width: 100%;
|
|
79
|
-
margin-bottom: var(
|
|
80
|
-
--recursica_ui-kit_components_tabs_variants_styles_default_variants_orientation_horizontal_properties_tabs-content-gap
|
|
81
|
-
);
|
|
100
|
+
margin-bottom: var(--tabs-content-gap);
|
|
82
101
|
}
|
|
83
102
|
|
|
84
103
|
.root[data-variant="default"][data-orientation="vertical"] {
|
|
@@ -141,13 +160,14 @@
|
|
|
141
160
|
--tabs-space-between-tabs: var(
|
|
142
161
|
--recursica_ui-kit_components_tabs_variants_styles_outline_variants_orientation_horizontal_properties_space-between-tabs
|
|
143
162
|
);
|
|
163
|
+
--tabs-content-gap: var(
|
|
164
|
+
--recursica_ui-kit_components_tabs_variants_styles_outline_variants_orientation_horizontal_properties_tabs-content-gap
|
|
165
|
+
);
|
|
144
166
|
}
|
|
145
167
|
.root[data-variant="outline"][data-orientation="horizontal"] .list {
|
|
146
168
|
gap: var(--tabs-space-between-tabs);
|
|
147
169
|
width: 100%;
|
|
148
|
-
margin-bottom: var(
|
|
149
|
-
--recursica_ui-kit_components_tabs_variants_styles_outline_variants_orientation_horizontal_properties_tabs-content-gap
|
|
150
|
-
);
|
|
170
|
+
margin-bottom: var(--tabs-content-gap);
|
|
151
171
|
}
|
|
152
172
|
|
|
153
173
|
.root[data-variant="outline"][data-orientation="vertical"] {
|
|
@@ -204,13 +224,14 @@
|
|
|
204
224
|
--tabs-space-between-tabs: var(
|
|
205
225
|
--recursica_ui-kit_components_tabs_variants_styles_pills_variants_orientation_horizontal_properties_space-between-tabs
|
|
206
226
|
);
|
|
227
|
+
--tabs-content-gap: var(
|
|
228
|
+
--recursica_ui-kit_components_tabs_variants_styles_pills_variants_orientation_horizontal_properties_tabs-content-gap
|
|
229
|
+
);
|
|
207
230
|
}
|
|
208
231
|
.root[data-variant="pills"][data-orientation="horizontal"] .list {
|
|
209
232
|
gap: var(--tabs-space-between-tabs);
|
|
210
233
|
width: 100%;
|
|
211
|
-
margin-bottom: var(
|
|
212
|
-
--recursica_ui-kit_components_tabs_variants_styles_pills_variants_orientation_horizontal_properties_tabs-content-gap
|
|
213
|
-
);
|
|
234
|
+
margin-bottom: var(--tabs-content-gap);
|
|
214
235
|
}
|
|
215
236
|
|
|
216
237
|
.root[data-variant="pills"][data-orientation="vertical"] {
|
|
@@ -82,6 +82,37 @@ Added `leftSection` (`RecursicaTimePickerProps`), matching `TextField`/`AutoComp
|
|
|
82
82
|
|
|
83
83
|
Mantine's `TimePicker` already accepts `leftSection` (inherited from `@mantine/core`'s `__InputProps` via `InputBase`, which it renders through internally with `component: "div"` — confirmed by reading `TimePicker.mjs`/`Input.mjs` directly) — it was already passing through unstyled before this change (not blocked by `filterStylingProps`), just never mapped to a `classNames.section`/CSS, so an icon would render with no size or color. Added `section: styles.section` to the `classNames` map and the token-driven `.section`/`.section svg` rules (icon-size, icon-color, disabled/error icon-color) to actually style it.
|
|
84
84
|
|
|
85
|
+
## Leading icon overlapped the field text (bug fix, Matt Massey, 2026-08-30)
|
|
86
|
+
|
|
87
|
+
Follow-up to the section above, found during a mantine-vs-mui source-of-truth comparison: `.section`
|
|
88
|
+
(the leading icon) is absolutely positioned — Mantine's own default for `Input.Section`, same as
|
|
89
|
+
`Dropdown`/`AutoComplete`'s equivalent — so it never occupies real flex-flow space. `.timeWrapper`'s
|
|
90
|
+
own `gap` (added in the round above, intended to space the icon from the field) has **no effect** on
|
|
91
|
+
it for exactly that reason: `gap` only spaces in-flow flex siblings, and an absolutely-positioned
|
|
92
|
+
child isn't one. Nothing else reserved room for the icon either, so `.fieldsGroup`'s hour/minute/
|
|
93
|
+
second inputs rendered right where `.timeWrapper`'s own base `padding-left` put them — directly
|
|
94
|
+
underneath the icon (visually, the icon and the leading "-- : --" overlapped).
|
|
95
|
+
|
|
96
|
+
Separately, `.section[data-position="left"]` had no explicit `left`/`padding-left` of its own,
|
|
97
|
+
so it fell back to Mantine's un-tokenized default: centered in a fixed-width box flush against the
|
|
98
|
+
border, not inset by `horizontal-padding` the way `Dropdown`/`AutoComplete`'s own left sections are.
|
|
99
|
+
|
|
100
|
+
**Fix** (mirrors `Dropdown.module.css`'s established pattern exactly):
|
|
101
|
+
|
|
102
|
+
- `.section[data-position="left"] { position: absolute; left: 0; padding-left: horizontal-padding; }`
|
|
103
|
+
— explicit instead of relying on Mantine's un-tokenized default.
|
|
104
|
+
- `.timeWrapper[data-with-left-section] .fieldsGroup { padding-left: calc(icon-size + icon-text-gap); }`
|
|
105
|
+
— reserves the room the (now out-of-flow) icon needs, on top of `.timeWrapper`'s own existing
|
|
106
|
+
base `padding-left` (which already covers the initial `horizontal-padding` inset).
|
|
107
|
+
|
|
108
|
+
**Why mui-adapter, once it fixes its own "icon too far right" bug for the same story, should match
|
|
109
|
+
this corrected rendering and not the previous (overlapping) one**: the previous rendering was a
|
|
110
|
+
straightforward layout bug, not an intentional design — an icon and adjacent text overlapping is
|
|
111
|
+
never a valid state for any other component in either adapter (`Dropdown`, `AutoComplete`,
|
|
112
|
+
`TextField`, `DatePicker` all reserve real space for a leading icon before rendering the field's
|
|
113
|
+
own text/placeholder). This fix brings `TimePicker` in line with that same, already-established
|
|
114
|
+
convention.
|
|
115
|
+
|
|
85
116
|
## Visual review round 5 (Matt Massey, 2026-08-08)
|
|
86
117
|
|
|
87
118
|
- **AM/PM error-state border wasn't changing**: `BareDropdown` set `data-error`/`data-disabled` via Mantine's `wrapperProps` — which targets the _outer_ `Input.Wrapper` (the label/description/error stacking element), a different, ancestor element from the "wrapper" styles-api slot that actually carries `styles.root`'s border. `Dropdown.module.css`'s `.root[data-error]`/`[data-disabled]` rules never matched as a result. This is the exact same "two different things both called 'wrapper'" trap as the earlier `style` vs `styles.wrapper` bug. Fixed by using `attributes={{ wrapper: {...} }}` instead — the styles-api hook that actually targets the same slot as `classNames.wrapper`. **This is a shared, pre-existing bug** — the real `Dropdown.tsx` had the identical mistake, so its error/disabled states never applied a border color either; fixed there too (low-risk, purely-additive, same reasoning as the `data-selected` fix above).
|
|
@@ -51,8 +51,10 @@
|
|
|
51
51
|
.timeWrapper {
|
|
52
52
|
display: flex;
|
|
53
53
|
align-items: center;
|
|
54
|
-
/*
|
|
55
|
-
|
|
54
|
+
/* This `gap` is a no-op: the leading-icon `.section` is absolutely positioned (Mantine's own
|
|
55
|
+
default for Input.Section, same as Dropdown/AutoComplete), so it never participates in flex
|
|
56
|
+
gap spacing as a normal flow sibling — see `.fieldsGroup` below for the fix that actually
|
|
57
|
+
reserves room for it. Left in place only because it's harmless with a single in-flow child. */
|
|
56
58
|
gap: var(--recursica_ui-kit_components_time-picker_properties_icon-text-gap);
|
|
57
59
|
position: relative;
|
|
58
60
|
box-sizing: border-box;
|
|
@@ -127,12 +129,24 @@
|
|
|
127
129
|
}
|
|
128
130
|
|
|
129
131
|
/* Leading icon (leftSection). Only one icon-color token exists for time-picker (unlike
|
|
130
|
-
text-field's separate leading/trailing) — this field has no right-side icon slot.
|
|
132
|
+
text-field's separate leading/trailing) — this field has no right-side icon slot.
|
|
133
|
+
Positioned explicitly (left:0 + padding-left) rather than left on Mantine's own absolute-
|
|
134
|
+
positioning default alone (bug fix, see `.fieldsGroup` below): Mantine centers it in a
|
|
135
|
+
fixed-width box flush against the border with no Recursica padding token applied at all,
|
|
136
|
+
same technique Dropdown/AutoComplete's own `.section[data-position="left"]` already use. */
|
|
131
137
|
.section {
|
|
132
138
|
display: flex;
|
|
133
139
|
align-items: center;
|
|
134
140
|
}
|
|
135
141
|
|
|
142
|
+
.section[data-position="left"] {
|
|
143
|
+
position: absolute;
|
|
144
|
+
left: 0;
|
|
145
|
+
padding-left: var(
|
|
146
|
+
--recursica_ui-kit_components_time-picker_properties_horizontal-padding
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
136
150
|
.section :global(svg) {
|
|
137
151
|
width: var(--recursica_ui-kit_components_time-picker_properties_icon-size);
|
|
138
152
|
height: var(--recursica_ui-kit_components_time-picker_properties_icon-size);
|
|
@@ -141,6 +155,19 @@
|
|
|
141
155
|
);
|
|
142
156
|
}
|
|
143
157
|
|
|
158
|
+
/* Reserves room for the (absolutely positioned, see `.section` above) leading icon in the actual
|
|
159
|
+
text flow — without this, `.fieldsGroup`'s hour/minute/second inputs start right where
|
|
160
|
+
`.timeWrapper`'s own base `padding-left` (horizontal-padding) puts them, which is directly
|
|
161
|
+
underneath the icon (bug: the icon and the field's leading ":" visibly overlapped). Only the
|
|
162
|
+
icon-size/icon-text-gap on top of that base padding is needed here, since `.timeWrapper`'s own
|
|
163
|
+
padding-left already reserves the horizontal-padding portion. */
|
|
164
|
+
.timeWrapper[data-with-left-section] .fieldsGroup {
|
|
165
|
+
padding-left: calc(
|
|
166
|
+
var(--recursica_ui-kit_components_time-picker_properties_icon-size) +
|
|
167
|
+
var(--recursica_ui-kit_components_time-picker_properties_icon-text-gap)
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
144
171
|
/* SpinInput renders a real <input placeholder="--">, one per hour/minute/second segment. */
|
|
145
172
|
.timeField::placeholder {
|
|
146
173
|
opacity: var(
|