@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
|
@@ -2,10 +2,24 @@
|
|
|
2
2
|
Recursica Tabs CSS module natively binding to Figma variables.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
.root
|
|
5
|
+
/* Unlike Mantine's .root (which internally wraps List+Panel and always spans its parent),
|
|
6
|
+
MUI's .root is only the tablist — it sits beside the panel in the consumer's own flex row for
|
|
7
|
+
vertical orientation. Stretching it to 100% width there fights the panel for space and drags
|
|
8
|
+
the border-right rail/indicator away from the tab content, so only horizontal gets full width;
|
|
9
|
+
vertical sizes to its content instead, same as Mantine's vertical .list does. */
|
|
10
|
+
.root[data-orientation="horizontal"] {
|
|
6
11
|
width: 100%;
|
|
7
12
|
}
|
|
8
13
|
|
|
14
|
+
/* Mantine's vertical .list stretches to the root's full height via flex align-items, so a
|
|
15
|
+
border-right divider on it spans the whole rail. MUI's scroller (the .list's parent) is a plain
|
|
16
|
+
block for vertical, not a flex container, so .list sizes to its own content (just the stacked
|
|
17
|
+
tabs) and a divider on it stops short at the last tab instead of running the full height —
|
|
18
|
+
spell the stretch out explicitly instead. */
|
|
19
|
+
.root[data-orientation="vertical"] .list {
|
|
20
|
+
height: 100%;
|
|
21
|
+
}
|
|
22
|
+
|
|
9
23
|
/*
|
|
10
24
|
Mantine Tabs Anatomy:
|
|
11
25
|
.root
|
|
@@ -125,6 +139,15 @@
|
|
|
125
139
|
--tabs-color: var(
|
|
126
140
|
--recursica_ui-kit_components_tabs-item_variants_styles_outline_variants_selection-states_active_properties_colors_border-color
|
|
127
141
|
) !important;
|
|
142
|
+
--tabs-active-bg: var(
|
|
143
|
+
--recursica_ui-kit_components_tabs-item_variants_styles_outline_variants_selection-states_active_properties_colors_background-color
|
|
144
|
+
);
|
|
145
|
+
/* The active tab's own background-color token above is transparent by design (it's meant to
|
|
146
|
+
let whichever ambient Layer surface sits behind the Tabs show through). That means it can't
|
|
147
|
+
double as an opaque "eraser" for the baseline-patch trick below, which needs a real paint to
|
|
148
|
+
replace, not reveal-through. Layer 0 is the default/outermost surface a Tabs instance sits
|
|
149
|
+
on absent a wrapping <Layer>; see OUTLINE SELECTION BORDER below for why this is needed. */
|
|
150
|
+
--tabs-baseline-patch-bg: var(--recursica_brand_layer_0_properties_surface);
|
|
128
151
|
}
|
|
129
152
|
|
|
130
153
|
.root[data-variant="outline"][data-orientation="horizontal"] {
|
|
@@ -223,18 +246,17 @@
|
|
|
223
246
|
|
|
224
247
|
/* ---------------------------------
|
|
225
248
|
SELECTION INDICATOR & BASELINE
|
|
226
|
-
Mantine draws the active-tab underline
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
249
|
+
Mantine draws the active-tab underline natively off the shared --tabs-color var above. MUI has
|
|
250
|
+
no equivalent built-in, so we drive its own indicator slot (classes.indicator, wired in
|
|
251
|
+
Tabs.tsx) and the list's baseline border explicitly from the same vars. Pills has no underline
|
|
252
|
+
indicator — selection shows via the pill's own background/border (see COLORS & TYPOGRAPHY
|
|
253
|
+
below). Outline repurposes the indicator as a baseline patch rather than an underline (see
|
|
254
|
+
below).
|
|
231
255
|
--------------------------------- */
|
|
232
|
-
.root[data-variant="default"] .indicator
|
|
233
|
-
.root[data-variant="outline"] .indicator {
|
|
256
|
+
.root[data-variant="default"] .indicator {
|
|
234
257
|
background-color: var(--tabs-color) !important;
|
|
235
258
|
}
|
|
236
|
-
.root[data-variant="default"][data-orientation="horizontal"] .indicator
|
|
237
|
-
.root[data-variant="outline"][data-orientation="horizontal"] .indicator {
|
|
259
|
+
.root[data-variant="default"][data-orientation="horizontal"] .indicator {
|
|
238
260
|
height: var(--tabs-active-border-size) !important;
|
|
239
261
|
}
|
|
240
262
|
/* MUI's Tabs root has no border/padding of its own, so the list's margin-bottom (the
|
|
@@ -250,27 +272,52 @@
|
|
|
250
272
|
--recursica_ui-kit_components_tabs_variants_styles_default_variants_orientation_horizontal_properties_tabs-content-gap
|
|
251
273
|
) !important;
|
|
252
274
|
}
|
|
275
|
+
/* width: same reasoning as the horizontal height above, rotated 90°.
|
|
276
|
+
right: same reasoning as the horizontal bottom offset above, rotated 90° — the list's
|
|
277
|
+
margin-right (this orientation's tabs-content-gap, spacing the panel to its right) inflates the
|
|
278
|
+
root's auto width past the list's own border-right edge. The indicator is absolutely positioned
|
|
279
|
+
against that wider box, so without this offset it renders content-gap pixels to the right of the
|
|
280
|
+
divider instead of flush against it. */
|
|
281
|
+
.root[data-variant="default"][data-orientation="vertical"] .indicator {
|
|
282
|
+
width: var(--tabs-active-border-size) !important;
|
|
283
|
+
right: var(
|
|
284
|
+
--recursica_ui-kit_components_tabs_variants_styles_default_variants_orientation_vertical_properties_tabs-content-gap
|
|
285
|
+
) !important;
|
|
286
|
+
}
|
|
287
|
+
.root[data-variant="default"][data-orientation="horizontal"][data-inverted]
|
|
288
|
+
.indicator {
|
|
289
|
+
bottom: auto !important;
|
|
290
|
+
top: 0 !important;
|
|
291
|
+
}
|
|
292
|
+
.root[data-variant="pills"] .indicator {
|
|
293
|
+
display: none !important;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* Outline has no sliding underline of its own, but reuses the indicator element (already
|
|
297
|
+
positioned/sized by MUI to exactly track the selected tab, no matter which one) as a baseline
|
|
298
|
+
patch instead of hiding it — see OUTLINE SELECTION BORDER below for why a patch is needed at
|
|
299
|
+
all, and why it has to live here (in the scroller) rather than on the tab itself. */
|
|
300
|
+
.root[data-variant="outline"] .indicator {
|
|
301
|
+
background-color: var(--tabs-baseline-patch-bg) !important;
|
|
302
|
+
}
|
|
253
303
|
.root[data-variant="outline"][data-orientation="horizontal"]:not(
|
|
254
304
|
[data-inverted]
|
|
255
305
|
)
|
|
256
306
|
.indicator {
|
|
307
|
+
height: var(--tabs-inactive-border-size) !important;
|
|
257
308
|
bottom: var(
|
|
258
309
|
--recursica_ui-kit_components_tabs_variants_styles_outline_variants_orientation_horizontal_properties_tabs-content-gap
|
|
259
310
|
) !important;
|
|
260
311
|
}
|
|
261
|
-
.root[data-variant="default"][data-orientation="vertical"] .indicator,
|
|
262
|
-
.root[data-variant="outline"][data-orientation="vertical"] .indicator {
|
|
263
|
-
width: var(--tabs-active-border-size) !important;
|
|
264
|
-
}
|
|
265
|
-
.root[data-variant="default"][data-orientation="horizontal"][data-inverted]
|
|
266
|
-
.indicator,
|
|
267
312
|
.root[data-variant="outline"][data-orientation="horizontal"][data-inverted]
|
|
268
313
|
.indicator {
|
|
314
|
+
height: var(--tabs-inactive-border-size) !important;
|
|
269
315
|
bottom: auto !important;
|
|
270
|
-
top:
|
|
316
|
+
top: calc(-1 * var(--tabs-inactive-border-size)) !important;
|
|
271
317
|
}
|
|
272
|
-
.root[data-variant="
|
|
273
|
-
|
|
318
|
+
.root[data-variant="outline"][data-orientation="vertical"] .indicator {
|
|
319
|
+
width: var(--tabs-inactive-border-size) !important;
|
|
320
|
+
right: calc(-1 * var(--tabs-inactive-border-size)) !important;
|
|
274
321
|
}
|
|
275
322
|
|
|
276
323
|
.root[data-variant="default"][data-orientation="horizontal"] .list,
|
|
@@ -356,6 +403,41 @@
|
|
|
356
403
|
border-radius: var(--tabs-border-radius) 0 0 var(--tabs-border-radius);
|
|
357
404
|
}
|
|
358
405
|
|
|
406
|
+
/* ---------------------------------
|
|
407
|
+
OUTLINE SELECTION BORDER
|
|
408
|
+
Mantine's outline tab marks selection with a bordered box left open on the edge that touches
|
|
409
|
+
the list's own baseline, so the box visually connects to it instead of floating above it.
|
|
410
|
+
Every tab keeps the border geometry (transparent by default) so selecting a tab doesn't shift
|
|
411
|
+
layout; only the color changes on selection. The open edge here has 0 border-width, which
|
|
412
|
+
leaves the list's own baseline border showing straight through underneath — see the indicator
|
|
413
|
+
patch in SELECTION INDICATOR & BASELINE above, which covers just that segment. (A pseudo-element
|
|
414
|
+
on the tab itself can't do this: MUI clips tab content to its own bounds for ripple containment,
|
|
415
|
+
so anything extending past the tab's box to reach the list's border gets clipped away.)
|
|
416
|
+
--------------------------------- */
|
|
417
|
+
.root[data-variant="outline"] .tab {
|
|
418
|
+
border-style: solid;
|
|
419
|
+
border-color: transparent;
|
|
420
|
+
}
|
|
421
|
+
.root[data-variant="outline"][data-orientation="horizontal"]:not(
|
|
422
|
+
[data-inverted]
|
|
423
|
+
)
|
|
424
|
+
.tab {
|
|
425
|
+
border-width: var(--tabs-inactive-border-size)
|
|
426
|
+
var(--tabs-inactive-border-size) 0 var(--tabs-inactive-border-size);
|
|
427
|
+
}
|
|
428
|
+
.root[data-variant="outline"][data-orientation="horizontal"][data-inverted]
|
|
429
|
+
.tab {
|
|
430
|
+
border-width: 0 var(--tabs-inactive-border-size)
|
|
431
|
+
var(--tabs-inactive-border-size) var(--tabs-inactive-border-size);
|
|
432
|
+
}
|
|
433
|
+
.root[data-variant="outline"][data-orientation="vertical"] .tab {
|
|
434
|
+
border-width: var(--tabs-inactive-border-size) 0
|
|
435
|
+
var(--tabs-inactive-border-size) var(--tabs-inactive-border-size);
|
|
436
|
+
}
|
|
437
|
+
.root[data-variant="outline"] .tab:global(.Mui-selected) {
|
|
438
|
+
border-color: var(--tabs-color) !important;
|
|
439
|
+
}
|
|
440
|
+
|
|
359
441
|
/* ---------------------------------
|
|
360
442
|
COLORS & TYPOGRAPHY
|
|
361
443
|
Because colors are defined per-layer and theme via generic variable structures,
|
|
@@ -485,9 +567,7 @@
|
|
|
485
567
|
}
|
|
486
568
|
|
|
487
569
|
.root[data-variant="outline"] .tab:global(.Mui-selected) {
|
|
488
|
-
background-color: var(
|
|
489
|
-
--recursica_ui-kit_components_tabs-item_variants_styles_outline_variants_selection-states_active_properties_colors_background-color
|
|
490
|
-
) !important;
|
|
570
|
+
background-color: var(--tabs-active-bg) !important;
|
|
491
571
|
color: var(
|
|
492
572
|
--recursica_ui-kit_components_tabs-item_variants_styles_outline_variants_selection-states_active_properties_colors_text-color
|
|
493
573
|
) !important;
|
|
@@ -635,8 +715,11 @@
|
|
|
635
715
|
z-index: 0;
|
|
636
716
|
}
|
|
637
717
|
|
|
638
|
-
/* Ensure tab content sits above the hover background
|
|
639
|
-
|
|
718
|
+
/* Ensure tab content sits above the hover background. Excludes MuiTouchRipple-root: it relies on
|
|
719
|
+
its native position:absolute to stay out of flow, and forcing it to position:relative here
|
|
720
|
+
turns it into a real flex item — inserting an extra element-gap into the tab's flex row (and
|
|
721
|
+
growing the tab's width) the first time it's clicked, permanently shifting later siblings. */
|
|
722
|
+
.root .tab > *:not(:global(.MuiTouchRipple-root)) {
|
|
640
723
|
z-index: 1;
|
|
641
724
|
position: relative;
|
|
642
725
|
}
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/* EXEMPTIONS:
|
|
2
|
-
- border-size variables are ignored because a uniform 1px border is applied globally to prevent
|
|
3
|
-
unexpected layout shift or flickering during focused, disabled, or error state transitions. */
|
|
4
|
-
/* recursica-ignore: --recursica_ui-kit_components_textarea_properties_border-size */
|
|
5
|
-
/* recursica-ignore: --recursica_ui-kit_components_textarea_variants_states_disabled_properties_border-size */
|
|
6
|
-
/* recursica-ignore: --recursica_ui-kit_components_textarea_variants_states_error_properties_border-size */
|
|
7
|
-
|
|
8
1
|
/* LAYOUT SPACING OVERRIDES:
|
|
9
2
|
- Sets the --form-control-margin-bottom spacing hook to map component-specific layout tokens.
|
|
10
3
|
- Also sets the --textarea-control-{max,min}-width hooks consumed inline in TextArea.tsx, since
|
|
@@ -127,6 +120,19 @@
|
|
|
127
120
|
color: inherit;
|
|
128
121
|
}
|
|
129
122
|
|
|
123
|
+
/* MUI always renders multiline inputs through TextareaAutosize, which sets an inline `height`
|
|
124
|
+
that otherwise wins over the min-height above. Pin the height to the same rows-based formula
|
|
125
|
+
when autosize isn't requested, so it matches the plain (non-autosizing) textarea Mantine renders. */
|
|
126
|
+
.root:not([data-autosize]) .input {
|
|
127
|
+
height: calc(
|
|
128
|
+
var(--recursica_ui-kit_components_textarea_properties_rows) *
|
|
129
|
+
var(--recursica_ui-kit_components_textarea_properties_text_line-height) +
|
|
130
|
+
2 *
|
|
131
|
+
var(--recursica_ui-kit_components_textarea_properties_vertical-padding) +
|
|
132
|
+
2px
|
|
133
|
+
) !important;
|
|
134
|
+
}
|
|
135
|
+
|
|
130
136
|
/* -------------------------------------
|
|
131
137
|
STATE CASCADE ARCHITECTURE
|
|
132
138
|
-------------------------------------- */
|
|
@@ -144,8 +150,10 @@
|
|
|
144
150
|
var(--recursica_brand_states_focus_color);
|
|
145
151
|
}
|
|
146
152
|
|
|
147
|
-
/* Error State Mapping
|
|
148
|
-
|
|
153
|
+
/* Error State Mapping
|
|
154
|
+
MUI only stamps the global `Mui-error` state class onto the InputBase root slot (not the
|
|
155
|
+
input element itself), so the error trigger is scoped from `.root` down to `.input`. */
|
|
156
|
+
.root:global(.Mui-error) .input {
|
|
149
157
|
border-color: var(
|
|
150
158
|
--recursica_ui-kit_components_textarea_variants_states_error_properties_colors_border-color
|
|
151
159
|
) !important;
|
|
@@ -157,8 +165,9 @@
|
|
|
157
165
|
) !important;
|
|
158
166
|
}
|
|
159
167
|
|
|
160
|
-
/* Disabled State Mapping
|
|
161
|
-
|
|
168
|
+
/* Disabled State Mapping
|
|
169
|
+
MUI stamps `Mui-disabled` onto both the root slot and the input element directly. */
|
|
170
|
+
.input:global(.Mui-disabled) {
|
|
162
171
|
border-color: var(
|
|
163
172
|
--recursica_ui-kit_components_textarea_variants_states_disabled_properties_colors_border-color
|
|
164
173
|
) !important;
|
|
@@ -66,6 +66,7 @@ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
|
|
66
66
|
emptyValueComponent,
|
|
67
67
|
value,
|
|
68
68
|
defaultValue,
|
|
69
|
+
autosize,
|
|
69
70
|
...rest
|
|
70
71
|
} = props;
|
|
71
72
|
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
@@ -76,27 +77,6 @@ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
|
|
76
77
|
delete restRecord["variant"];
|
|
77
78
|
delete restRecord["radius"];
|
|
78
79
|
|
|
79
|
-
// Securely map core native blocks down ensuring nested CSS modules map precisely
|
|
80
|
-
const mergedClassNames: Partial<Record<string, string>> = {
|
|
81
|
-
wrapper: styles.root, // The nested Input internal relative wrapper bounding box
|
|
82
|
-
input: styles.input,
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const classNamesProp = restRecord.classNames;
|
|
86
|
-
if (
|
|
87
|
-
classNamesProp &&
|
|
88
|
-
typeof classNamesProp === "object" &&
|
|
89
|
-
!Array.isArray(classNamesProp)
|
|
90
|
-
) {
|
|
91
|
-
const o = classNamesProp as Partial<Record<string, string>>;
|
|
92
|
-
mergedClassNames.wrapper = o.wrapper
|
|
93
|
-
? `${styles.root} ${o.wrapper}`
|
|
94
|
-
: styles.root;
|
|
95
|
-
mergedClassNames.input = o.input
|
|
96
|
-
? `${styles.input} ${o.input}`
|
|
97
|
-
: styles.input;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
80
|
const wrapperClass = className
|
|
101
81
|
? `${styles.layoutOverride} ${className}`
|
|
102
82
|
: styles.layoutOverride;
|
|
@@ -130,15 +110,24 @@ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
|
|
130
110
|
/* Naked Input execution safely decoupled from Mui's macro Input.Wrapper DOM hooks */
|
|
131
111
|
<MuiTextarea
|
|
132
112
|
multiline
|
|
113
|
+
variant="standard"
|
|
133
114
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
134
115
|
inputRef={ref as any}
|
|
135
|
-
classes={mergedClassNames}
|
|
136
116
|
disabled={disabled}
|
|
137
117
|
value={value}
|
|
138
118
|
defaultValue={defaultValue}
|
|
139
119
|
label={undefined}
|
|
140
|
-
error={
|
|
120
|
+
error={!!error}
|
|
141
121
|
required={undefined}
|
|
122
|
+
slotProps={{
|
|
123
|
+
input: {
|
|
124
|
+
disableUnderline: true,
|
|
125
|
+
classes: { root: styles.root, input: styles.input },
|
|
126
|
+
...({
|
|
127
|
+
"data-autosize": autosize ? "true" : undefined,
|
|
128
|
+
} as Record<string, unknown>),
|
|
129
|
+
},
|
|
130
|
+
}}
|
|
142
131
|
{...(sanitizedProps as unknown as MuiTextareaProps)}
|
|
143
132
|
/>
|
|
144
133
|
}
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/* EXEMPTIONS:
|
|
2
|
-
- state-specific border-size variables are ignored because a uniform 1px border is applied globally to prevent
|
|
3
|
-
unexpected layout shift or flickering during focus, disabled, or error state transitions. */
|
|
4
|
-
/* recursica-ignore: --recursica_ui-kit_components_text-field_variants_states_default_properties_border-size */
|
|
5
|
-
/* recursica-ignore: --recursica_ui-kit_components_text-field_variants_states_disabled_properties_border-size */
|
|
6
|
-
/* recursica-ignore: --recursica_ui-kit_components_text-field_variants_states_error_properties_border-size */
|
|
7
|
-
/* recursica-ignore: --recursica_ui-kit_components_text-field_variants_states_focus_properties_border-size */
|
|
8
|
-
|
|
9
1
|
/* LAYOUT SPACING OVERRIDES:
|
|
10
2
|
- Sets the --form-control-margin-bottom spacing hook to map component-specific layout tokens.
|
|
11
3
|
- Also sets the --text-field-control-{max,min}-width hooks consumed inline in TextField.tsx,
|
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
/* EXEMPTIONS:
|
|
2
|
-
- state-specific border-size variables are ignored because a uniform border-size is applied globally
|
|
3
|
-
to prevent unexpected layout shift or flickering during focus, disabled, or error state transitions.
|
|
4
|
-
- icon-size/icon-color/icon-text-gap have no equivalent here: the time field has no icon slot,
|
|
5
|
-
unlike TextField/DatePicker.
|
|
6
|
-
- placeholder-opacity has no equivalent here: MUI X's field renders empty sections via its own
|
|
7
|
-
internal placeholder styling, not a native ::placeholder pseudo-element we can target. */
|
|
8
|
-
/* recursica-ignore: --recursica_ui-kit_components_time-picker_variants_states_error_properties_border-size */
|
|
9
|
-
/* recursica-ignore: --recursica_ui-kit_components_time-picker_variants_states_disabled_properties_border-size */
|
|
10
|
-
/* recursica-ignore: --recursica_ui-kit_components_time-picker_properties_icon-size */
|
|
11
|
-
/* recursica-ignore: --recursica_ui-kit_components_time-picker_properties_icon-text-gap */
|
|
12
|
-
/* recursica-ignore: --recursica_ui-kit_components_time-picker_properties_colors_icon-color */
|
|
13
|
-
/* recursica-ignore: --recursica_ui-kit_components_time-picker_properties_placeholder-opacity */
|
|
14
|
-
/* recursica-ignore: --recursica_ui-kit_components_time-picker_variants_states_disabled_properties_colors_icon-color */
|
|
15
|
-
/* recursica-ignore: --recursica_ui-kit_components_time-picker_variants_states_error_properties_colors_icon-color */
|
|
16
|
-
|
|
17
1
|
/* LAYOUT SPACING OVERRIDES:
|
|
18
2
|
- Sets the --form-control-margin-bottom spacing hook to map component-specific layout tokens. */
|
|
19
3
|
.layoutOverride {
|
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Timeline Implementation Notes
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
## Architecture
|
|
4
|
+
|
|
5
|
+
Unlike Mantine, `@mui/lab`'s `TimelineItem` has no built-in bullet/connector — it only
|
|
6
|
+
composes whatever you nest inside it. `TimelineItem.tsx` renders `TimelineSeparator` >
|
|
7
|
+
`TimelineDot` (`.itemBullet`) + `TimelineConnector` (`.itemConnector`), and `TimelineContent`
|
|
8
|
+
(`.itemBody`) containing the `title`/description/`timestamp` nodes, to reproduce Mantine's
|
|
9
|
+
single-component bullet + connecting-line structure.
|
|
10
|
+
|
|
11
|
+
- `Timeline.tsx` computes `active`/`isLast` per item (Mui has no `active` concept at all) and
|
|
12
|
+
injects them into each `Timeline.Item` as internal `__active`/`__isLast` props, mirroring
|
|
13
|
+
Mantine's own `cloneElement` pattern for propagating active state down to children.
|
|
14
|
+
- `data-active` / `data-variant` are set directly on `TimelineItem`'s real `li` root and
|
|
15
|
+
consumed via plain descendant selectors (`.item[data-active] .itemBullet`, etc.) in
|
|
16
|
+
`Timeline.module.css` — Mui's `TimelineItem` only defines a `root` classes slot, so (unlike
|
|
17
|
+
Mantine) passing a `classes` object with `item`/`itemBullet`/`itemBody`/... keys is a no-op;
|
|
18
|
+
those class names must be applied as plain `className`s on the elements we render ourselves.
|
|
19
|
+
- The last item omits `TimelineConnector` entirely so no trailing line renders past it.
|
|
20
|
+
- `Timeline.module.css` neutralizes Mui's `TimelineItem::before` opposite-content spacer
|
|
21
|
+
(`flex: 0; padding: 0`), which otherwise pushes the separator/content right since this
|
|
22
|
+
adapter never renders `TimelineOppositeContent`.
|
|
23
|
+
|
|
24
|
+
## Limitations & Missing Tokens
|
|
25
|
+
|
|
26
|
+
- **Avatar Bullet Size**: There is no specific pixel variable provided for the Avatar bullet size in the UI kit tokens (`avatar-size` evaluates to `"default"`). To maintain exact mathematical centering with the connector line, the CSS falls back to inheriting the `default` bullet size (`20px`) for avatar nodes natively. If users supply a custom sized `img` tag, it must adhere to inline structural constraints or flex mappings.
|
|
@@ -1,81 +1,58 @@
|
|
|
1
|
-
/* EXEMPTIONS:
|
|
2
|
-
- timeline-bullet_variants_types_avatar_properties_avatar-size is ignored because under the avatar timeline variant,
|
|
3
|
-
the bullet container size uses fallback bullet-size configurations to maintain vertical alignment with the
|
|
4
|
-
inactive/active connector line, while the nested Avatar subcomponent handles its own sizing natively. */
|
|
5
|
-
/* recursica-ignore: --recursica_ui-kit_components_timeline-bullet_variants_types_avatar_properties_avatar-size */
|
|
6
|
-
|
|
7
1
|
.root {
|
|
8
2
|
display: flex;
|
|
9
3
|
flex-direction: column;
|
|
10
4
|
gap: var(--recursica_ui-kit_components_timeline_properties_item-gap);
|
|
5
|
+
margin: 0 !important;
|
|
6
|
+
padding: 0 !important;
|
|
11
7
|
}
|
|
12
8
|
|
|
13
9
|
.item {
|
|
14
|
-
/*
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
) !important;
|
|
18
|
-
|
|
19
|
-
&[data-active] {
|
|
20
|
-
--tl-line-width: var(
|
|
21
|
-
--recursica_ui-kit_components_timeline_variants_selection-states_active_properties_connector-size
|
|
22
|
-
) !important;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
&[data-variant="default"] {
|
|
26
|
-
--tl-bullet-size: var(
|
|
27
|
-
--recursica_ui-kit_components_timeline-bullet_variants_types_default_properties_bullet-size
|
|
28
|
-
) !important;
|
|
29
|
-
}
|
|
30
|
-
&[data-variant="icon"] {
|
|
31
|
-
--tl-bullet-size: var(
|
|
32
|
-
--recursica_ui-kit_components_timeline-bullet_variants_types_icon_properties_bullet-size
|
|
33
|
-
) !important;
|
|
34
|
-
}
|
|
35
|
-
&[data-variant="icon-alternative"] {
|
|
36
|
-
--tl-bullet-size: var(
|
|
37
|
-
--recursica_ui-kit_components_timeline-bullet_variants_types_icon-alternative_properties_bullet-size
|
|
38
|
-
) !important;
|
|
39
|
-
}
|
|
40
|
-
&[data-variant="avatar"] {
|
|
41
|
-
/* Avatar sizing fallback to default to maintain connector alignment */
|
|
42
|
-
--tl-bullet-size: var(
|
|
43
|
-
--recursica_ui-kit_components_timeline-bullet_variants_types_default_properties_bullet-size
|
|
44
|
-
) !important;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/* Control connector lines via the item ::before pseudo-element */
|
|
48
|
-
/* Inactive connector */
|
|
49
|
-
&::before {
|
|
50
|
-
border-left-width: var(
|
|
51
|
-
--recursica_ui-kit_components_timeline_variants_selection-states_inactive_properties_connector-size
|
|
52
|
-
) !important;
|
|
53
|
-
border-left-color: var(
|
|
54
|
-
--recursica_ui-kit_components_timeline_variants_selection-states_inactive_properties_colors_connector-color
|
|
55
|
-
) !important;
|
|
56
|
-
}
|
|
10
|
+
/* Mui gives every item a 70px min-height by default; content should drive height instead */
|
|
11
|
+
min-height: 0 !important;
|
|
12
|
+
}
|
|
57
13
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
) !important;
|
|
66
|
-
}
|
|
14
|
+
/* Mui reserves a flex:1 spacer (via ::before) for the opposite-content column even when none is
|
|
15
|
+
rendered. Recursica's Timeline never uses TimelineOppositeContent, so neutralize it to keep the
|
|
16
|
+
bullet/connector column flush against the left edge. */
|
|
17
|
+
:global(.MuiTimelineItem-root)::before {
|
|
18
|
+
content: none !important;
|
|
19
|
+
flex: 0 !important;
|
|
20
|
+
padding: 0 !important;
|
|
67
21
|
}
|
|
68
22
|
|
|
69
23
|
.itemBody {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
24
|
+
padding: 0 0 0
|
|
25
|
+
var(--recursica_ui-kit_components_timeline_properties_bullet-content-gap) !important;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.itemConnector {
|
|
29
|
+
width: var(
|
|
30
|
+
--recursica_ui-kit_components_timeline_variants_selection-states_inactive_properties_connector-size
|
|
31
|
+
) !important;
|
|
32
|
+
background-color: var(
|
|
33
|
+
--recursica_ui-kit_components_timeline_variants_selection-states_inactive_properties_colors_connector-color
|
|
34
|
+
) !important;
|
|
35
|
+
}
|
|
36
|
+
.item[data-active] .itemConnector {
|
|
37
|
+
width: var(
|
|
38
|
+
--recursica_ui-kit_components_timeline_variants_selection-states_active_properties_connector-size
|
|
39
|
+
) !important;
|
|
40
|
+
background-color: var(
|
|
41
|
+
--recursica_ui-kit_components_timeline_variants_selection-states_active_properties_colors_connector-color
|
|
73
42
|
) !important;
|
|
74
43
|
}
|
|
75
44
|
|
|
76
45
|
.itemBullet {
|
|
46
|
+
display: flex !important;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
align-self: center !important;
|
|
50
|
+
margin: 0 !important;
|
|
51
|
+
padding: 0 !important;
|
|
52
|
+
box-shadow: none !important;
|
|
53
|
+
|
|
77
54
|
/* Default Variant */
|
|
78
|
-
|
|
55
|
+
.item[data-variant="default"] & {
|
|
79
56
|
width: var(
|
|
80
57
|
--recursica_ui-kit_components_timeline-bullet_variants_types_default_properties_bullet-size
|
|
81
58
|
) !important;
|
|
@@ -96,7 +73,7 @@
|
|
|
96
73
|
--recursica_ui-kit_components_timeline-bullet_variants_types_default_variants_selection-states_inactive_properties_colors_border-color
|
|
97
74
|
) !important;
|
|
98
75
|
}
|
|
99
|
-
|
|
76
|
+
.item[data-variant="default"][data-active] & {
|
|
100
77
|
background-color: var(
|
|
101
78
|
--recursica_ui-kit_components_timeline-bullet_variants_types_default_variants_selection-states_active_properties_colors_background-color
|
|
102
79
|
) !important;
|
|
@@ -106,7 +83,7 @@
|
|
|
106
83
|
}
|
|
107
84
|
|
|
108
85
|
/* Icon Variant */
|
|
109
|
-
|
|
86
|
+
.item[data-variant="icon"] & {
|
|
110
87
|
width: var(
|
|
111
88
|
--recursica_ui-kit_components_timeline-bullet_variants_types_icon_properties_bullet-size
|
|
112
89
|
) !important;
|
|
@@ -143,7 +120,7 @@
|
|
|
143
120
|
);
|
|
144
121
|
}
|
|
145
122
|
}
|
|
146
|
-
|
|
123
|
+
.item[data-variant="icon"][data-active] & {
|
|
147
124
|
background-color: var(
|
|
148
125
|
--recursica_ui-kit_components_timeline-bullet_variants_types_icon_variants_selection-states_active_properties_colors_background-color
|
|
149
126
|
) !important;
|
|
@@ -156,7 +133,7 @@
|
|
|
156
133
|
}
|
|
157
134
|
|
|
158
135
|
/* Icon Alternative Variant */
|
|
159
|
-
|
|
136
|
+
.item[data-variant="icon-alternative"] & {
|
|
160
137
|
width: var(
|
|
161
138
|
--recursica_ui-kit_components_timeline-bullet_variants_types_icon-alternative_properties_bullet-size
|
|
162
139
|
) !important;
|
|
@@ -192,8 +169,7 @@
|
|
|
192
169
|
);
|
|
193
170
|
}
|
|
194
171
|
}
|
|
195
|
-
|
|
196
|
-
& {
|
|
172
|
+
.item[data-variant="icon-alternative"][data-active] & {
|
|
197
173
|
background-color: var(
|
|
198
174
|
--recursica_ui-kit_components_timeline-bullet_variants_types_icon-alternative_variants_selection-states_active_properties_colors_background-color
|
|
199
175
|
) !important;
|
|
@@ -206,8 +182,14 @@
|
|
|
206
182
|
}
|
|
207
183
|
|
|
208
184
|
/* Avatar Variant */
|
|
209
|
-
|
|
185
|
+
.item[data-variant="avatar"] & {
|
|
210
186
|
/* Avatar sizing is often governed by the avatar itself, but we'll apply the radius and opacity */
|
|
187
|
+
width: var(
|
|
188
|
+
--recursica_ui-kit_components_timeline-bullet_variants_types_default_properties_bullet-size
|
|
189
|
+
) !important;
|
|
190
|
+
height: var(
|
|
191
|
+
--recursica_ui-kit_components_timeline-bullet_variants_types_default_properties_bullet-size
|
|
192
|
+
) !important;
|
|
211
193
|
border-radius: var(
|
|
212
194
|
--recursica_ui-kit_components_timeline-bullet_variants_types_avatar_properties_border-radius
|
|
213
195
|
) !important;
|
|
@@ -225,7 +207,7 @@
|
|
|
225
207
|
--recursica_ui-kit_components_timeline-bullet_variants_types_avatar_variants_selection-states_inactive_properties_colors_border-color
|
|
226
208
|
) !important;
|
|
227
209
|
}
|
|
228
|
-
|
|
210
|
+
.item[data-variant="avatar"][data-active] & {
|
|
229
211
|
opacity: var(
|
|
230
212
|
--recursica_ui-kit_components_timeline-bullet_variants_types_avatar_variants_selection-states_active_properties_avatar-opacity
|
|
231
213
|
) !important;
|
|
@@ -275,7 +257,7 @@
|
|
|
275
257
|
) !important;
|
|
276
258
|
|
|
277
259
|
/* Active Title Color */
|
|
278
|
-
|
|
260
|
+
.item[data-active] & {
|
|
279
261
|
color: var(
|
|
280
262
|
--recursica_ui-kit_components_timeline_variants_selection-states_active_properties_colors_title-color
|
|
281
263
|
) !important;
|
|
@@ -323,7 +305,7 @@
|
|
|
323
305
|
--recursica_ui-kit_components_timeline_variants_selection-states_inactive_properties_colors_description-color
|
|
324
306
|
);
|
|
325
307
|
|
|
326
|
-
|
|
308
|
+
.item[data-active] & {
|
|
327
309
|
color: var(
|
|
328
310
|
--recursica_ui-kit_components_timeline_variants_selection-states_active_properties_colors_description-color
|
|
329
311
|
);
|
|
@@ -360,7 +342,7 @@
|
|
|
360
342
|
--recursica_ui-kit_components_timeline_variants_selection-states_inactive_properties_colors_timestamp-color
|
|
361
343
|
);
|
|
362
344
|
|
|
363
|
-
|
|
345
|
+
.item[data-active] & {
|
|
364
346
|
color: var(
|
|
365
347
|
--recursica_ui-kit_components_timeline_variants_selection-states_active_properties_colors_timestamp-color
|
|
366
348
|
);
|