@recursica/mui-adapter 0.24.0 → 0.26.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 +36 -0
- package/dist/index.d.ts +189 -28
- package/dist/mui-adapter.cjs +85 -85
- package/dist/mui-adapter.cjs.map +1 -1
- package/dist/mui-adapter.css +1 -1
- package/dist/mui-adapter.js +29694 -24393
- package/dist/mui-adapter.js.map +1 -1
- package/llms.txt +1 -0
- package/package.json +1 -1
- package/src/GlobalExemptions.modules.css +0 -6
- package/src/components/Accordion/Accordion.module.css +0 -8
- package/src/components/AssistiveElement/AssistiveElement.tsx +1 -1
- package/src/components/Autocomplete/Autocomplete.module.css +0 -8
- package/src/components/Avatar/Avatar.module.css +0 -8
- package/src/components/Button/BUTTON_IMPLEMENTATION_NOTES.md +12 -0
- package/src/components/Button/Button.module.css +6 -18
- package/src/components/Checkbox/Checkbox.tsx +4 -1
- package/src/components/Chip/Chip.module.css +0 -27
- package/src/components/DatePicker/DATEPICKER_IMPLEMENTATION_NOTES.md +29 -0
- package/src/components/DatePicker/DatePicker.icons.tsx +35 -0
- package/src/components/DatePicker/DatePicker.module.css +451 -42
- package/src/components/DatePicker/DatePicker.stories.tsx +23 -25
- package/src/components/DatePicker/DatePicker.tsx +229 -47
- package/src/components/DatePicker/USAGE.md +14 -1
- package/src/components/Dropdown/Dropdown.module.css +0 -7
- package/src/components/FileInput/FileInput.module.css +0 -21
- package/src/components/FileInput/FileInput.tsx +6 -0
- package/src/components/FileUpload/FileUpload.module.css +0 -11
- package/src/components/HoverCard/HoverCard.module.css +1 -7
- package/src/components/Label/Label.module.css +0 -6
- package/src/components/Link/Link.module.css +0 -13
- package/src/components/Menu/Menu.module.css +0 -5
- package/src/components/Modal/Modal.module.css +0 -11
- package/src/components/NumberInput/NumberInput.module.css +0 -7
- package/src/components/Pagination/Pagination.module.css +0 -81
- package/src/components/Popover/IMPLEMENTATION_NOTES.md +22 -0
- package/src/components/Popover/Popover.module.css +118 -0
- package/src/components/Popover/Popover.stories.tsx +133 -0
- package/src/components/Popover/Popover.tsx +275 -0
- package/src/components/Popover/USAGE.md +69 -0
- package/src/components/Popover/index.ts +1 -0
- package/src/components/SegmentedControl/IMPLEMENTATION_NOTES.md +6 -0
- package/src/components/SegmentedControl/SegmentedControl.module.css +32 -11
- package/src/components/SegmentedControl/SegmentedControl.tsx +18 -4
- package/src/components/Slider/IMPLEMENTATION_NOTES.md +29 -0
- package/src/components/Slider/Slider.module.css +80 -17
- package/src/components/Slider/Slider.stories.tsx +1 -1
- package/src/components/Slider/Slider.tsx +36 -1
- package/src/components/Stepper/IMPLEMENTATION_NOTES.md +54 -0
- package/src/components/Stepper/Stepper.module.css +139 -106
- package/src/components/Stepper/Stepper.tsx +76 -10
- package/src/components/Stepper/USAGE.md +4 -0
- package/src/components/Tabs/IMPLEMENTATION_NOTES.md +12 -0
- package/src/components/Tabs/Tabs.module.css +107 -24
- package/src/components/Tabs/Tabs.tsx +1 -0
- package/src/components/TextArea/TextArea.module.css +20 -11
- package/src/components/TextArea/TextArea.tsx +12 -23
- package/src/components/TextField/TextField.module.css +0 -8
- package/src/components/TimePicker/TimePicker.module.css +0 -16
- package/src/components/Timeline/IMPLEMENTATION_NOTES.md +24 -3
- package/src/components/Timeline/Timeline.module.css +55 -73
- package/src/components/Timeline/Timeline.tsx +23 -27
- package/src/components/Timeline/TimelineItem.tsx +38 -35
- package/src/components/Toast/Toast.module.css +0 -7
- package/src/components/Tooltip/Tooltip.module.css +0 -9
- package/src/components/TransferList/TRANSFERLIST_IMPLEMENTATION_NOTES.md +140 -0
- package/src/components/TransferList/TransferList.module.css +174 -38
- package/src/components/TransferList/TransferList.stories.tsx +110 -6
- package/src/components/TransferList/TransferList.tsx +417 -8
- package/src/components/TransferList/USAGE.md +37 -6
- package/src/components/index.ts +1 -0
- package/src/index.ts +3 -0
|
@@ -1,13 +1,26 @@
|
|
|
1
|
-
/*
|
|
1
|
+
/*
|
|
2
2
|
Recursica Stepper CSS module natively binding to Figma variables.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
|
|
4
|
+
ARCHITECTURE NOTES (see IMPLEMENTATION_NOTES.md for full rationale):
|
|
5
|
+
- Horizontal orientation uses MUI Stepper's own `alternativeLabel` prop (icon on
|
|
6
|
+
top, label centered below, connector absolutely positioned circle-to-circle) —
|
|
7
|
+
this is MUI's real primitive for this exact layout, not a custom column hack.
|
|
8
|
+
- The visible circle/checkmark is rendered by our own `RecursicaStepIcon`
|
|
9
|
+
(`.stepIconCircle` / `.stepCompletedIcon`) instead of MUI's default `StepIcon`,
|
|
10
|
+
which draws its own self-colored (blue) circle+check SVG that never reads
|
|
11
|
+
our tokens.
|
|
12
|
+
- Vertical orientation's connecting line is drawn as a `.stepIcon::after` rail
|
|
13
|
+
(not the `StepConnector` element — see Stepper.tsx) so its length tracks each
|
|
14
|
+
step's actual rendered height, matching mantine's absolutely-positioned
|
|
15
|
+
separator.
|
|
16
|
+
|
|
17
|
+
HARDCODED VALUES:
|
|
18
|
+
- `.stepIconCircle` sets `box-sizing: border-box` so the indicator's border is
|
|
19
|
+
included in `--stepper-indicator-size`, keeping the connector's centering math
|
|
20
|
+
(indicator-size / 2) exact.
|
|
21
|
+
- `--stepper-connector-size` is a local bridge custom property (not a design
|
|
22
|
+
token) used only to let the vertical rail's centering `calc()` reference
|
|
23
|
+
whichever connector-size token is active for the current state.
|
|
11
24
|
*/
|
|
12
25
|
|
|
13
26
|
.root {
|
|
@@ -24,21 +37,12 @@
|
|
|
24
37
|
);
|
|
25
38
|
}
|
|
26
39
|
|
|
27
|
-
.root.horizontal .step {
|
|
28
|
-
flex-direction: column;
|
|
29
|
-
align-items: center;
|
|
30
|
-
gap: var(
|
|
31
|
-
--recursica_ui-kit_components_stepper_variants_orientation_horizontal_properties_indicator-label-gap
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
40
|
.root.horizontal .stepBody {
|
|
36
41
|
width: var(--stepper-max-text-width);
|
|
37
42
|
display: flex;
|
|
38
43
|
flex-direction: column;
|
|
39
44
|
align-items: center;
|
|
40
45
|
justify-content: flex-start;
|
|
41
|
-
margin-left: 0; /* Mantine natively applies a margin-inline-start */
|
|
42
46
|
gap: var(
|
|
43
47
|
--recursica_ui-kit_components_stepper_variants_orientation_horizontal_properties_label-description-gap
|
|
44
48
|
);
|
|
@@ -52,14 +56,41 @@
|
|
|
52
56
|
white-space: normal;
|
|
53
57
|
}
|
|
54
58
|
|
|
59
|
+
.root.horizontal .stepLabel {
|
|
60
|
+
/* Replaces MUI's own hardcoded `margin-top: 16px` (applied via its
|
|
61
|
+
`.Mui-alternativeLabel` state class) with the real indicator-label-gap token. */
|
|
62
|
+
margin-top: var(
|
|
63
|
+
--recursica_ui-kit_components_stepper_variants_orientation_horizontal_properties_indicator-label-gap
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
55
67
|
.root.horizontal .separator {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
68
|
+
/* Root only positions the connector; MUI's own `alternativeLabel` variant
|
|
69
|
+
already sets `position: absolute`. Centering is exact because our custom
|
|
70
|
+
StepIconComponent renders a `--stepper-indicator-size` circle flush at the
|
|
71
|
+
top of `.stepIcon`, centered horizontally within the step. */
|
|
72
|
+
top: calc(var(--stepper-indicator-size) / 2);
|
|
73
|
+
left: -50%;
|
|
74
|
+
right: 50%;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.root.horizontal .separatorLine {
|
|
78
|
+
border-top: none; /* replace MUI's default border-top line with a token-driven bar */
|
|
79
|
+
height: var(
|
|
80
|
+
--recursica_ui-kit_components_stepper_properties_upcoming-connector-size
|
|
60
81
|
);
|
|
61
|
-
|
|
62
|
-
|
|
82
|
+
background-color: var(
|
|
83
|
+
--recursica_ui-kit_components_stepper_properties_colors_upcoming-connector-color
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.root.horizontal .separator:global(.Mui-active) .separatorLine,
|
|
88
|
+
.root.horizontal .separator:global(.Mui-completed) .separatorLine {
|
|
89
|
+
height: var(
|
|
90
|
+
--recursica_ui-kit_components_stepper_properties_completed-connector-size
|
|
91
|
+
);
|
|
92
|
+
background-color: var(
|
|
93
|
+
--recursica_ui-kit_components_stepper_properties_colors_completed-connector-color
|
|
63
94
|
);
|
|
64
95
|
}
|
|
65
96
|
|
|
@@ -68,20 +99,15 @@
|
|
|
68
99
|
--stepper-step-gap: var(
|
|
69
100
|
--recursica_ui-kit_components_stepper_variants_orientation_vertical_properties_step-gap
|
|
70
101
|
);
|
|
71
|
-
--separator-spacing: 0px; /* Force the line to touch the circle */
|
|
72
102
|
--stepper-max-text-width: var(
|
|
73
103
|
--recursica_ui-kit_components_stepper_variants_orientation_vertical_properties_max-text-width
|
|
74
104
|
);
|
|
75
105
|
}
|
|
76
106
|
|
|
77
107
|
.root.vertical .step {
|
|
78
|
-
gap
|
|
79
|
-
|
|
80
|
-
);
|
|
81
|
-
margin-top: 0 !important; /* Remove Mantine's gap */
|
|
82
|
-
padding-bottom: var(
|
|
83
|
-
--stepper-step-gap
|
|
84
|
-
); /* Move gap inside the step so the separator line can stretch through it */
|
|
108
|
+
/* Moves the gap inside the step (instead of a margin between steps) so the
|
|
109
|
+
`.stepIcon::after` rail can extend through it into the next step. */
|
|
110
|
+
padding-bottom: var(--stepper-step-gap);
|
|
85
111
|
}
|
|
86
112
|
|
|
87
113
|
.root.vertical .step:last-of-type {
|
|
@@ -94,6 +120,54 @@
|
|
|
94
120
|
);
|
|
95
121
|
}
|
|
96
122
|
|
|
123
|
+
.root.vertical .stepLabelRoot {
|
|
124
|
+
/* Lets the icon column (`.stepIcon`) stretch to match the label column's
|
|
125
|
+
actual rendered height (multi-line descriptions included), so the
|
|
126
|
+
connecting rail's length always reaches the next step's icon. */
|
|
127
|
+
align-items: stretch;
|
|
128
|
+
/* Replaces MUI's own hardcoded `padding: 8px 0` for vertical orientation —
|
|
129
|
+
without zeroing this, the rail falls 16px short of the next icon (8px
|
|
130
|
+
here + 8px on the next step's own StepLabelRoot). */
|
|
131
|
+
padding: 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.root.vertical .stepIcon {
|
|
135
|
+
height: auto;
|
|
136
|
+
/* Replaces MUI's own hardcoded `padding-right: 8px` on the icon container. */
|
|
137
|
+
padding-right: var(
|
|
138
|
+
--recursica_ui-kit_components_stepper_variants_orientation_vertical_properties_indicator-label-gap
|
|
139
|
+
);
|
|
140
|
+
--stepper-connector-size: var(
|
|
141
|
+
--recursica_ui-kit_components_stepper_properties_upcoming-connector-size
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.root.vertical .step:global(.Mui-completed) .stepIcon {
|
|
146
|
+
--stepper-connector-size: var(
|
|
147
|
+
--recursica_ui-kit_components_stepper_properties_completed-connector-size
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.root.vertical .step:not(:last-of-type) .stepIcon::after {
|
|
152
|
+
content: "";
|
|
153
|
+
position: absolute;
|
|
154
|
+
top: var(--stepper-indicator-size);
|
|
155
|
+
bottom: calc(-1 * var(--stepper-step-gap));
|
|
156
|
+
left: calc(50% - (var(--stepper-connector-size) / 2));
|
|
157
|
+
width: var(--stepper-connector-size);
|
|
158
|
+
background-color: var(
|
|
159
|
+
--recursica_ui-kit_components_stepper_properties_colors_upcoming-connector-color
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.root.vertical
|
|
164
|
+
.step:global(.Mui-completed):not(:last-of-type)
|
|
165
|
+
.stepIcon::after {
|
|
166
|
+
background-color: var(
|
|
167
|
+
--recursica_ui-kit_components_stepper_properties_colors_completed-connector-color
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
97
171
|
/* Sizes */
|
|
98
172
|
.large {
|
|
99
173
|
--stepper-icon-size: var(
|
|
@@ -180,10 +254,6 @@
|
|
|
180
254
|
}
|
|
181
255
|
|
|
182
256
|
/* Core Element Structuring using mapped variables */
|
|
183
|
-
.root .step {
|
|
184
|
-
/* Default to Mantine's native flex behavior (stretch) so the vertical separator spans the full height */
|
|
185
|
-
}
|
|
186
|
-
|
|
187
257
|
.root .stepBody {
|
|
188
258
|
max-width: var(--stepper-max-text-width);
|
|
189
259
|
display: flex;
|
|
@@ -244,11 +314,27 @@
|
|
|
244
314
|
);
|
|
245
315
|
}
|
|
246
316
|
|
|
317
|
+
/* `.stepIcon` (MUI's `iconContainer` slot) is a layout host only — it never
|
|
318
|
+
renders the visible circle itself, so it can stretch (vertical) without
|
|
319
|
+
distorting it. The circle is `.stepIconCircle`, rendered by our own
|
|
320
|
+
`RecursicaStepIcon` (see Stepper.tsx). */
|
|
247
321
|
.root .stepIcon {
|
|
322
|
+
display: flex;
|
|
323
|
+
flex-direction: column;
|
|
324
|
+
align-items: center;
|
|
325
|
+
justify-content: flex-start;
|
|
326
|
+
position: relative;
|
|
327
|
+
width: var(--stepper-indicator-size);
|
|
328
|
+
flex-shrink: 0;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.root .stepIconCircle {
|
|
332
|
+
box-sizing: border-box; /* HARDCODE: keep indicator-size math exact incl. border */
|
|
248
333
|
width: var(--stepper-indicator-size);
|
|
249
334
|
height: var(--stepper-indicator-size);
|
|
250
335
|
min-width: var(--stepper-indicator-size);
|
|
251
336
|
min-height: var(--stepper-indicator-size);
|
|
337
|
+
border-style: solid; /* HARDCODE: plain span has no default border-style */
|
|
252
338
|
border-width: var(--stepper-border-size);
|
|
253
339
|
border-radius: 50%; /* Override Figma token to ensure perfectly circular indicators */
|
|
254
340
|
|
|
@@ -264,7 +350,6 @@
|
|
|
264
350
|
display: flex;
|
|
265
351
|
align-items: center;
|
|
266
352
|
justify-content: center;
|
|
267
|
-
/* Font details are implicitly mapped by sizes, but colors map to states */
|
|
268
353
|
/* Upcoming State (Pending) - Default */
|
|
269
354
|
background-color: var(
|
|
270
355
|
--recursica_ui-kit_components_stepper_properties_colors_upcoming-indicator-background-color
|
|
@@ -278,8 +363,7 @@
|
|
|
278
363
|
}
|
|
279
364
|
|
|
280
365
|
/* Completed State */
|
|
281
|
-
.root .
|
|
282
|
-
.root .stepIcon:has(.Mui-completed) {
|
|
366
|
+
.root .stepIconCircle[data-completed] {
|
|
283
367
|
background-color: var(
|
|
284
368
|
--recursica_ui-kit_components_stepper_properties_colors_completed-indicator-background-color
|
|
285
369
|
);
|
|
@@ -289,32 +373,27 @@
|
|
|
289
373
|
}
|
|
290
374
|
|
|
291
375
|
.root .stepCompletedIcon {
|
|
376
|
+
width: var(--stepper-svg-size);
|
|
377
|
+
height: var(--stepper-svg-size);
|
|
292
378
|
color: var(
|
|
293
379
|
--recursica_ui-kit_components_stepper_properties_colors_completed-indicator-text
|
|
294
380
|
);
|
|
295
381
|
}
|
|
296
382
|
|
|
297
|
-
.root .
|
|
298
|
-
width: var(--stepper-svg-size);
|
|
299
|
-
height: var(--stepper-svg-size);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
.root .stepLabel.Mui-completed {
|
|
383
|
+
.root .stepLabel:global(.Mui-completed) {
|
|
303
384
|
color: var(
|
|
304
385
|
--recursica_ui-kit_components_stepper_properties_colors_completed-label-color
|
|
305
386
|
);
|
|
306
387
|
}
|
|
307
388
|
|
|
308
|
-
.root .
|
|
309
|
-
.root .MuiStepLabel-root.Mui-completed .stepDescription {
|
|
389
|
+
.root .stepBody:has(.stepLabel:global(.Mui-completed)) .stepDescription {
|
|
310
390
|
color: var(
|
|
311
391
|
--recursica_ui-kit_components_stepper_properties_colors_completed-description-color
|
|
312
392
|
);
|
|
313
393
|
}
|
|
314
394
|
|
|
315
395
|
/* Current State (Progressing) */
|
|
316
|
-
.root .
|
|
317
|
-
.root .stepIcon:has(.Mui-active) {
|
|
396
|
+
.root .stepIconCircle[data-active] {
|
|
318
397
|
background-color: var(
|
|
319
398
|
--recursica_ui-kit_components_stepper_properties_colors_current-indicator-background-color
|
|
320
399
|
);
|
|
@@ -326,84 +405,38 @@
|
|
|
326
405
|
);
|
|
327
406
|
}
|
|
328
407
|
|
|
329
|
-
.root .stepLabel.Mui-active {
|
|
408
|
+
.root .stepLabel:global(.Mui-active) {
|
|
330
409
|
color: var(
|
|
331
410
|
--recursica_ui-kit_components_stepper_properties_colors_current-label-color
|
|
332
411
|
);
|
|
333
412
|
}
|
|
334
413
|
|
|
335
|
-
.root .
|
|
336
|
-
.root .MuiStepLabel-root.Mui-active .stepDescription {
|
|
414
|
+
.root .stepBody:has(.stepLabel:global(.Mui-active)) .stepDescription {
|
|
337
415
|
color: var(
|
|
338
416
|
--recursica_ui-kit_components_stepper_properties_colors_current-description-color
|
|
339
417
|
);
|
|
340
418
|
}
|
|
341
419
|
|
|
342
420
|
/* Upcoming State (Pending Labels) */
|
|
343
|
-
.root .stepLabel:not(.Mui-active):not(.Mui-completed) {
|
|
421
|
+
.root .stepLabel:not(:global(.Mui-active)):not(:global(.Mui-completed)) {
|
|
344
422
|
color: var(
|
|
345
423
|
--recursica_ui-kit_components_stepper_properties_colors_upcoming-label-color
|
|
346
424
|
);
|
|
347
425
|
}
|
|
348
426
|
|
|
349
|
-
.root
|
|
427
|
+
.root
|
|
428
|
+
.stepBody:not(:has(.stepLabel:global(.Mui-active))):not(
|
|
429
|
+
:has(.stepLabel:global(.Mui-completed))
|
|
430
|
+
)
|
|
431
|
+
.stepDescription {
|
|
350
432
|
color: var(
|
|
351
433
|
--recursica_ui-kit_components_stepper_properties_colors_upcoming-description-color
|
|
352
434
|
);
|
|
353
435
|
}
|
|
354
436
|
|
|
355
|
-
/*
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
background-color: var(
|
|
359
|
-
--recursica_ui-kit_components_stepper_properties_colors_upcoming-connector-color
|
|
360
|
-
);
|
|
361
|
-
height: var(
|
|
362
|
-
--recursica_ui-kit_components_stepper_properties_upcoming-connector-size
|
|
363
|
-
);
|
|
364
|
-
border: none;
|
|
365
|
-
min-width: 20px;
|
|
366
|
-
flex: 1;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
.root .separator.Mui-active,
|
|
370
|
-
.root .separator.Mui-completed {
|
|
371
|
-
background-color: var(
|
|
372
|
-
--recursica_ui-kit_components_stepper_properties_colors_completed-connector-color
|
|
373
|
-
);
|
|
374
|
-
height: var(
|
|
375
|
-
--recursica_ui-kit_components_stepper_properties_completed-connector-size
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/* Vertical Separator */
|
|
380
|
-
.root .verticalSeparator {
|
|
381
|
-
border-inline-start: var(
|
|
382
|
-
--recursica_ui-kit_components_stepper_properties_upcoming-connector-size
|
|
383
|
-
)
|
|
384
|
-
solid
|
|
385
|
-
var(
|
|
386
|
-
--recursica_ui-kit_components_stepper_properties_colors_upcoming-connector-color
|
|
387
|
-
);
|
|
388
|
-
top: var(
|
|
389
|
-
--stepper-icon-size
|
|
390
|
-
); /* Overrides Mantine's gap math to force the line to touch the icon */
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
.root .verticalSeparator.Mui-active,
|
|
394
|
-
.root .verticalSeparator.Mui-completed {
|
|
395
|
-
border-inline-start: var(
|
|
396
|
-
--recursica_ui-kit_components_stepper_properties_completed-connector-size
|
|
397
|
-
)
|
|
398
|
-
solid
|
|
399
|
-
var(
|
|
400
|
-
--recursica_ui-kit_components_stepper_properties_colors_completed-connector-color
|
|
401
|
-
);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/* Hide Content
|
|
405
|
-
Recursica Steppers are purely navigational/structural. Content should be managed
|
|
406
|
-
by the parent layout outside of the Stepper DOM.
|
|
437
|
+
/* Hide Content
|
|
438
|
+
Recursica Steppers are purely navigational/structural. Content should be managed
|
|
439
|
+
by the parent layout outside of the Stepper DOM.
|
|
407
440
|
*/
|
|
408
441
|
.root .content {
|
|
409
442
|
display: none;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type StepLabelProps as MuiStepLabelProps,
|
|
11
11
|
type StepButtonProps as MuiStepButtonProps,
|
|
12
12
|
type StepConnectorProps as MuiStepConnectorProps,
|
|
13
|
+
type StepIconProps as MuiStepIconProps,
|
|
13
14
|
} from "@mui/material";
|
|
14
15
|
import {
|
|
15
16
|
filterStylingProps,
|
|
@@ -19,6 +20,49 @@ import styles from "./Stepper.module.css";
|
|
|
19
20
|
|
|
20
21
|
import { type RecursicaStepperProps } from "@recursica/adapter-common";
|
|
21
22
|
|
|
23
|
+
// Same inline check glyph used by Checkbox.tsx (fill="currentColor" so the CSS
|
|
24
|
+
// module drives color via `.stepCompletedIcon`).
|
|
25
|
+
function CheckIcon(props: React.ComponentProps<"svg">) {
|
|
26
|
+
return (
|
|
27
|
+
<svg
|
|
28
|
+
viewBox="0 0 10 7"
|
|
29
|
+
fill="none"
|
|
30
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
31
|
+
{...props}
|
|
32
|
+
>
|
|
33
|
+
<path
|
|
34
|
+
d="M4 4.586L1.707 2.293A1 1 0 1 0 .293 3.707l3 3a.997.997 0 0 0 1.414 0l5-5A1 1 0 1 0 8.293.293L4 4.586z"
|
|
35
|
+
fill="currentColor"
|
|
36
|
+
fillRule="evenodd"
|
|
37
|
+
clipRule="evenodd"
|
|
38
|
+
/>
|
|
39
|
+
</svg>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// MUI's default StepIcon draws its own self-contained circle+check SVG
|
|
44
|
+
// (Material's `check_circle` glyph, colored via `theme.palette.primary.main`)
|
|
45
|
+
// whenever `icon` is the auto-injected step number — it never defers to our
|
|
46
|
+
// `.stepIcon` background/border tokens. We render the indicator ourselves so
|
|
47
|
+
// the recursica-token circle (`.stepIconCircle`) is the only circle, and the
|
|
48
|
+
// completed check mark is our own token-colored glyph.
|
|
49
|
+
function RecursicaStepIcon(props: MuiStepIconProps) {
|
|
50
|
+
const { icon, active, completed, error } = props;
|
|
51
|
+
if (typeof icon !== "number" && typeof icon !== "string") {
|
|
52
|
+
return <>{icon}</>;
|
|
53
|
+
}
|
|
54
|
+
return (
|
|
55
|
+
<span
|
|
56
|
+
className={styles.stepIconCircle}
|
|
57
|
+
data-active={active || undefined}
|
|
58
|
+
data-completed={completed || undefined}
|
|
59
|
+
data-error={error || undefined}
|
|
60
|
+
>
|
|
61
|
+
{completed ? <CheckIcon className={styles.stepCompletedIcon} /> : icon}
|
|
62
|
+
</span>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
22
66
|
export interface RecursicaStepperPropsExtended
|
|
23
67
|
extends Omit<Partial<MuiStepperProps>, "size">,
|
|
24
68
|
RecursicaStepperProps {}
|
|
@@ -37,10 +81,11 @@ export const Stepper = forwardRef<HTMLDivElement, StepperProps>(
|
|
|
37
81
|
} = props;
|
|
38
82
|
|
|
39
83
|
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
84
|
+
const isHorizontal = orientation === "horizontal";
|
|
40
85
|
|
|
41
86
|
return (
|
|
42
87
|
<div
|
|
43
|
-
className={`${styles.root} ${
|
|
88
|
+
className={`${styles.root} ${isHorizontal ? styles.horizontal : styles.vertical} ${size === "large" ? styles.large : styles.small} ${className || ""}`}
|
|
44
89
|
style={style as React.CSSProperties}
|
|
45
90
|
data-size={size}
|
|
46
91
|
data-orientation={orientation}
|
|
@@ -50,15 +95,27 @@ export const Stepper = forwardRef<HTMLDivElement, StepperProps>(
|
|
|
50
95
|
ref={ref as any}
|
|
51
96
|
{...(sanitizedProps as MuiStepperProps)}
|
|
52
97
|
orientation={orientation}
|
|
98
|
+
// `alternativeLabel` is MUI's real primitive for "label centered under
|
|
99
|
+
// the icon" (see its own prop doc) — required for the icon/label
|
|
100
|
+
// layout and for the connector's centered absolute positioning.
|
|
101
|
+
alternativeLabel={isHorizontal}
|
|
53
102
|
connector={
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
103
|
+
isHorizontal ? (
|
|
104
|
+
<MuiStepConnector
|
|
105
|
+
classes={{
|
|
106
|
+
root: styles.separator,
|
|
107
|
+
line: styles.separatorLine,
|
|
108
|
+
}}
|
|
109
|
+
/>
|
|
110
|
+
) : (
|
|
111
|
+
// Vertical connecting line is drawn as a `.stepIcon::after` rail
|
|
112
|
+
// (see module CSS) so its length tracks each step's actual
|
|
113
|
+
// rendered height (multi-line descriptions included) the same
|
|
114
|
+
// way mantine's absolutely-positioned separator does — MUI's
|
|
115
|
+
// own vertical `StepConnector` is a fixed-height sibling that
|
|
116
|
+
// can't do that without `StepContent`, which recursica hides.
|
|
117
|
+
<></>
|
|
118
|
+
)
|
|
62
119
|
}
|
|
63
120
|
classes={{
|
|
64
121
|
root: styles.steps,
|
|
@@ -112,16 +169,25 @@ export type StepLabelProps = RecursicaOverStyled<
|
|
|
112
169
|
|
|
113
170
|
export const StepLabel = forwardRef<HTMLDivElement, StepLabelProps>(
|
|
114
171
|
function StepLabel(props, ref) {
|
|
115
|
-
const {
|
|
172
|
+
const {
|
|
173
|
+
overStyled = false,
|
|
174
|
+
className,
|
|
175
|
+
description,
|
|
176
|
+
StepIconComponent,
|
|
177
|
+
...rest
|
|
178
|
+
} = props;
|
|
116
179
|
return (
|
|
117
180
|
<MuiStepLabel
|
|
118
181
|
ref={ref}
|
|
119
182
|
{...(filterStylingProps(rest, overStyled) as MuiStepLabelProps)}
|
|
120
183
|
className={className || ""}
|
|
121
184
|
classes={{
|
|
185
|
+
root: styles.stepLabelRoot,
|
|
122
186
|
label: styles.stepLabel,
|
|
123
187
|
iconContainer: styles.stepIcon,
|
|
188
|
+
labelContainer: styles.stepBody,
|
|
124
189
|
}}
|
|
190
|
+
StepIconComponent={StepIconComponent ?? RecursicaStepIcon}
|
|
125
191
|
optional={
|
|
126
192
|
description ? (
|
|
127
193
|
<div className={styles.stepDescription}>{description}</div>
|
|
@@ -39,3 +39,7 @@ All Recursica components in the `@recursica/mui-adapter` package adhere strictly
|
|
|
39
39
|
> - **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.
|
|
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**: Styling is entirely determined by local CSS variables defined in `recursica_variables_scoped.css` and mapped in the component's CSS module.
|
|
42
|
+
> - **Default step icon**: `StepLabel` renders its own token-driven circle (with a check mark
|
|
43
|
+
> once a step is completed) by default. Pass your own `StepIconComponent` prop to `StepLabel`
|
|
44
|
+
> to override it for a given step, or pass a custom `icon` node (e.g. `<StepLabel icon={<MyIcon />}>`)
|
|
45
|
+
> to render arbitrary content in place of the circle entirely.
|
|
@@ -12,3 +12,15 @@
|
|
|
12
12
|
- **MUI's `TabPanel` defaults to `padding: theme.spacing(3)` (24px)**; Mantine's `Tabs.Panel` has none — the gap is already carried by `.list`'s own margin. Reset to `padding: 0`.
|
|
13
13
|
- **The indicator (`classes.indicator`) is absolutely positioned against `.MuiTabs-root`, not `.list`:** `.list`'s own `margin-bottom` (the tabs-content-gap) collapses into that root's auto height instead of stopping at `.list`'s border edge, so the indicator's default `bottom: 0` lands one content-gap below the baseline. Offset it by the same content-gap token to bring it flush again.
|
|
14
14
|
- **All of the above needed `!important`** to reliably beat MUI's own emotion-injected styles for the same property — plain specificity/cascade order wasn't sufficient in this build.
|
|
15
|
+
|
|
16
|
+
## Follow-up parity fixes (2026-08-18)
|
|
17
|
+
|
|
18
|
+
- **`MuiTouchRipple-root` gets caught by `.root .tab > *`:** that rule exists to lift real content (icon/label) above the hover overlay's `z-index`, but it also matches the ripple span MUI injects into the tab on first click. Forcing that span from its native `position: absolute` to `position: relative` turns it into a real flex item, inserting one extra `--tabs-element-gap` into the tab's flex row and permanently growing the tab's width (it never gets removed from the DOM after the ripple animation ends) — this was the cause of a layout shift where selecting a tab pushed later siblings sideways. Excluded via `:not(:global(.MuiTouchRipple-root))`.
|
|
19
|
+
- **Outline's selected-tab border can't be "erased" with a same-element pseudo-element:** the open edge (0 border-width on the side touching the list's baseline) leaves the list's own `border-bottom`/`border-right` showing through, because that border is a real CSS border appended outside the tab's box, not an inset overlay sharing the tab's own bottom edge (unlike Mantine, where the list-baseline wrapper and the tab share the same reference edge, so the tab's own border naturally paints over it). A `::after` patch on the tab itself can't fix this either: MUI gives `Tab` (`ButtonBase`) `overflow: hidden` natively (to contain the ripple), which clips away anything extending past the tab's own box before it ever reaches the list's border. Fixed by repurposing the indicator element (`classes.indicator`) instead — it already lives in the scroller (a sibling of `.list`, not clipped) and MUI already keeps its position/size in sync with whichever tab is selected, so it just needed restyling into a small opaque patch instead of being `display: none`.
|
|
20
|
+
- **That patch needs a real opaque color, not the tab's own token:** outline's active background-color token is `transparent` by design (it's meant to let the ambient Layer surface show through), so it can't double as the eraser — painting "transparent over transparent" does nothing. Used `--recursica_brand_layer_0_properties_surface` (the default/outermost Layer surface) instead, since that's what a Tabs instance sits on absent an explicit wrapping `<Layer>`. This is an inherent approximation, same category as Mantine's own equivalent trick (which hardcodes `--mantine-color-body`): if a consumer nests outline Tabs inside a `<Layer layer={1|2|3}>`, the patch will mismatch that surface's color. No generic "current ambient layer" token exists in the schema to fix this properly — flagged for whoever owns the token schema.
|
|
21
|
+
- **Vertical `.list` doesn't stretch to the root's full height:** Mantine's vertical `.list` stretches via flex `align-items`, so its `border-right` divider runs the whole rail. MUI's scroller (the `.list`'s parent) is a plain block for vertical, not a flex container, so `.list` sizes to just its stacked tab content and the divider stopped at the last tab. Fixed with an explicit `height: 100%` on `.list` for vertical orientation.
|
|
22
|
+
- **Vertical indicator needs the same content-gap offset as horizontal, rotated 90°:** the list's `margin-right` (vertical's tabs-content-gap) inflates the root's auto width past the list's own border-right edge, same mechanism as the existing horizontal `bottom` offset trick — without a matching `right` offset, the indicator renders content-gap pixels to the right of the divider instead of on it.
|
|
23
|
+
|
|
24
|
+
## Ripple removal (2026-08-19)
|
|
25
|
+
|
|
26
|
+
- **MUI `Tab` shows a click ripple; Mantine's has none.** `Tab` extends `ButtonBase`, which renders a `TouchRipple` on click by default. Fixed by passing `disableRipple` on `MuiTab` in `Tab` (the same official escape hatch already used by `Button`/`Switch`/`Radio`/`Checkbox`). With `disableRipple`, the `MuiTouchRipple-root` span is never rendered at all, which also makes the `.root .tab > *:not(:global(.MuiTouchRipple-root))` layout-shift workaround above moot going forward (left in place defensively).
|