Skip to content

Commit e867fcf

Browse files
pricopmdo
andauthored
Refine Stepper component (#42165)
* Add stepper font size variable to tokens map Since the `--stepper-size` container is customizable, it makes sense for the `font-size` to be as well, when using larger sizes, larger font size may also be required. This also changes the default `font-size` to `-sm` size for the counter inside the bubble. This is the perfect example where if we use the `-sm` variant, it makes the text feel more relaxed inside the bubble. * Reduce stepper track size from 0.25rem to 0.125rem This further relaxes the component by taking away the attention from the track itself, allowing bubbles and text to be more easily readable at a glance without feeling overcrowded. The industry standard is 1px or 2px at max. As a result, the stepper tracker has been reduced to down to `2px` from `4px` For reference: - Tailwind UI practices `2px` width: https://tailwindcss.com/plus/ui-blocks/application-ui/navigation/progress-bars#component-4b1efed043d1ab5688c705f2e27524f3 - Material UI practices `1px` width: https://material.angular.dev/components/stepper/overview - Preline UI practices `1px` width: https://preline.co/docs/stepper.html - Flowbite UI practices `1px` width: https://flowbite.com/docs/components/stepper/ - ReUI practices `1px` width: https://reui.io/patterns/stepper * Add align-items start to horizontal stepper This will make the text to always start at the top, regardless of whether other bubbles have a multi-line text or not. * Fixed horizontal stepper text gap & text overflow Fixes the horizontal bottom row being fixed in height, causing the spacing between the count bubble and the text not be the same as intended (as the gap dictates), nor as its vertical stepper counterpart. This also fixes the text overflowing outside fixed boundaries, causing it to move in places it shouldn't be. * Refactor to use logical properties Fixed RTL mode by making use of logical properties instead of physical ones. * Colored the right side stepper line Colored the right side stepper line instead of the left side for active elements. This is the natural way, if I reached the next step, then the edge leading to it should be colored in the color of the completed step. * Fixed stepper width not account for stepper's gap Fixed stepper width not account for stepper's gap * Added complex stepper support for vertical steppers - Added complex stepper support for vertical steppers. - Added --stepper-text-gap CSS var (customizable spacing between text & bubble) - Fixed text overflow for vertical steppers when the text is too long * Restored 1fr for the rows template Restored 1fr for the rows template. While I believed it looked better before, I'd rather keep the row size across all steps. * tweaks * make container query instead, add new utility to make container queries easier * Remove stepper playground --------- Co-authored-by: Mark Otto <markdotto@gmail.com>
1 parent ce3149b commit e867fcf

4 files changed

Lines changed: 122 additions & 486 deletions

File tree

scss/_stepper.scss

Lines changed: 97 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
@use "sass:map";
21
@use "config" as *;
32
@use "functions" as *;
43
@use "layout/breakpoints" as *;
@@ -13,8 +12,10 @@ $stepper-tokens: defaults(
1312
(
1413
--stepper-size: 2rem,
1514
--stepper-gap: 1rem,
15+
--stepper-font-size: var(--font-size-sm),
16+
--stepper-text-gap: .5rem,
17+
--stepper-track-size: .125rem,
1618
--stepper-bg: var(--bg-2),
17-
--stepper-track-size: .25rem,
1819
--stepper-active-color: var(--primary-contrast),
1920
--stepper-active-bg: var(--primary-bg),
2021
),
@@ -29,117 +30,127 @@ $stepper-tokens: defaults(
2930
grid-auto-flow: column;
3031

3132
.stepper-item {
32-
grid-template-rows: repeat(2, var(--stepper-size));
33+
grid-template-rows: var(--stepper-size) auto;
3334
grid-template-columns: auto;
35+
align-items: start;
3436
justify-items: center;
37+
text-align: center;
3538

3639
&::after {
37-
top: calc((var(--stepper-size) * .5) - (var(--stepper-track-size) * .5));
38-
right: 0;
39-
bottom: auto;
40-
left: calc(-50% - var(--stepper-gap));
41-
width: auto;
40+
inset-block-start: calc((var(--stepper-size) * .5) - (var(--stepper-track-size) * .5));
41+
inset-block-end: auto;
42+
inset-inline-start: 50%;
43+
inset-inline-end: 100%;
44+
width: calc(100% + var(--stepper-gap));
4245
height: var(--stepper-track-size);
4346
}
4447

4548
&:last-child::after {
46-
right: 50%;
49+
right: 100%;
4750
}
4851
}
4952
}
5053
// scss-docs-end stepper-horizontal-mixin
5154

52-
// scss-docs-start stepper-css
53-
.stepper {
54-
// scss-docs-start stepper-css-vars
55-
@include tokens($stepper-tokens);
56-
// scss-docs-end stepper-css-vars
57-
58-
display: grid;
59-
grid-auto-rows: 1fr;
60-
grid-auto-flow: row;
61-
gap: var(--stepper-gap);
62-
padding-left: 0;
63-
list-style: none;
64-
counter-reset: stepper;
65-
}
55+
@layer components {
56+
.stepper {
57+
@include tokens($stepper-tokens);
58+
59+
display: grid;
60+
grid-auto-rows: 1fr;
61+
grid-auto-flow: row;
62+
gap: var(--stepper-gap);
63+
padding-inline-start: 0;
64+
list-style: none;
65+
counter-reset: stepper;
66+
}
6667

67-
.stepper-item {
68-
position: relative;
69-
display: grid;
70-
grid-template-rows: auto;
71-
grid-template-columns: var(--stepper-size) auto;
72-
gap: .5rem;
73-
place-items: center;
74-
justify-items: start;
75-
text-align: center;
76-
text-decoration: none;
77-
78-
// The counter
79-
&::before {
68+
.stepper-item {
8069
position: relative;
81-
z-index: 1;
82-
display: flex;
83-
flex-shrink: 0;
70+
display: grid;
71+
grid-template-rows: auto;
72+
grid-template-columns: var(--stepper-size) auto;
73+
gap: var(--stepper-text-gap);
8474
align-items: center;
85-
justify-content: center;
86-
width: var(--stepper-size);
87-
height: var(--stepper-size);
88-
padding: .5rem;
89-
font-weight: 600;
90-
line-height: 1;
91-
text-align: center;
92-
content: counter(stepper);
93-
counter-increment: stepper;
94-
background-color: var(--stepper-bg);
95-
@include border-radius(50%);
75+
text-decoration: none;
76+
77+
// The counter
78+
&::before {
79+
position: relative;
80+
z-index: 1;
81+
display: flex;
82+
flex-shrink: 0;
83+
align-items: center;
84+
justify-content: center;
85+
width: var(--stepper-size);
86+
height: var(--stepper-size);
87+
padding: .5rem;
88+
font-size: var(--stepper-font-size);
89+
font-weight: 600;
90+
line-height: 1;
91+
text-align: center;
92+
content: counter(stepper);
93+
counter-increment: stepper;
94+
background-color: var(--stepper-bg);
95+
@include border-radius(50%);
96+
}
97+
98+
// Connecting lines
99+
&::after {
100+
position: absolute;
101+
inset-block-start: 50%;
102+
inset-block-end: 100%;
103+
inset-inline-start: calc((var(--stepper-size) * .5) - (var(--stepper-track-size) * .5));
104+
width: var(--stepper-track-size);
105+
height: calc(100% + var(--stepper-gap));
106+
content: "";
107+
background-color: var(--stepper-bg);
108+
}
109+
110+
// Avoid sibling selector for easier CSS overrides
111+
&:last-child::after {
112+
display: none;
113+
}
114+
115+
&.active {
116+
&::before,
117+
&::after {
118+
color: var(--theme-contrast, var(--stepper-active-color));
119+
background-color: var(--theme-bg, var(--stepper-active-bg));
120+
}
121+
}
96122
}
97123

98-
// Connecting lines
99-
&::after {
100-
position: absolute;
101-
top: calc(var(--stepper-gap) * -1);
102-
bottom: 100%;
103-
left: calc((var(--stepper-size) * .5) - (var(--stepper-track-size) * .5));
104-
width: var(--stepper-track-size);
105-
content: "";
124+
// Targets the last .active element from a sequence of active elements
125+
.stepper-item.active:not(:has(+ .stepper-item.active))::after {
106126
background-color: var(--stepper-bg);
107127
}
108128

109-
// Avoid sibling selector for easier CSS overrides
110-
&:first-child::after {
111-
display: none;
129+
.stepper-horizontal {
130+
@include stepper-horizontal();
112131
}
113132

114-
&.active {
115-
&::before,
116-
&::after {
117-
color: var(--theme-contrast, var(--stepper-active-color));
118-
background-color: var(--theme-bg, var(--stepper-active-bg));
133+
@include loop-breakpoints-down() using ($breakpoint, $next, $infix) {
134+
@if $next {
135+
.stepper-horizontal#{$infix} {
136+
@include container-breakpoint-up($next) {
137+
@include stepper-horizontal();
138+
}
139+
}
119140
}
120141
}
121-
}
122142

123-
@each $breakpoint in map.keys($breakpoints) {
124-
@include media-breakpoint-up($breakpoint) {
125-
$infix: breakpoint-infix($breakpoint, $breakpoints);
143+
// scss-docs-start stepper-overflow
144+
.stepper-overflow {
145+
container-type: inline-size;
146+
overflow-x: auto;
147+
overscroll-behavior-x: contain;
148+
-webkit-overflow-scrolling: touch;
126149

127-
.stepper-horizontal#{$infix} {
128-
@include stepper-horizontal();
150+
> .stepper {
151+
width: max-content;
152+
min-width: 100%;
129153
}
130154
}
155+
// scss-docs-end stepper-overflow
131156
}
132-
133-
// scss-docs-start stepper-overflow
134-
.stepper-overflow {
135-
container-type: inline-size;
136-
overflow-x: auto;
137-
overscroll-behavior-x: contain;
138-
-webkit-overflow-scrolling: touch;
139-
140-
> .stepper {
141-
width: max-content;
142-
min-width: 100%;
143-
}
144-
}
145-
// scss-docs-end stepper-overflow

scss/_utilities.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ $utilities: map.merge(
8686
values: auto hidden visible scroll,
8787
),
8888
// scss-docs-end utils-overflow
89+
"container": (
90+
property: container-type,
91+
class: contains,
92+
values: (
93+
"inline": inline-size,
94+
"size": size,
95+
)
96+
),
8997
// scss-docs-start utils-display
9098
"display": (
9199
responsive: true,

0 commit comments

Comments
 (0)