@wovenui/components 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +284 -2
- package/dist/components.json +4204 -0
- package/dist/llms-full.txt +2839 -0
- package/dist/wovenui-kit.css +5002 -0
- package/dist/wovenui-kit.css.map +1 -0
- package/dist/wovenui-kit.iife.js +532 -0
- package/dist/wovenui-kit.js +529 -0
- package/dist/wovenui-kit.min.css +2 -0
- package/dist/wovenui-kit.min.css.map +1 -0
- package/package.json +268 -4
- package/src/_close.scss +45 -0
- package/src/_helpers.scss +11 -0
- package/src/_kit.scss +124 -0
- package/src/_shared.scss +10 -0
- package/src/components/_accordion.scss +132 -0
- package/src/components/_alert.scss +161 -0
- package/src/components/_autocomplete.scss +129 -0
- package/src/components/_avatar-group.scss +80 -0
- package/src/components/_avatar.scss +134 -0
- package/src/components/_badge.scss +91 -0
- package/src/components/_breadcrumb.scss +115 -0
- package/src/components/_btn-group.scss +113 -0
- package/src/components/_button.scss +301 -0
- package/src/components/_card.scss +120 -0
- package/src/components/_checkbox.scss +168 -0
- package/src/components/_code-block.scss +78 -0
- package/src/components/_confirm-modal.scss +75 -0
- package/src/components/_data-table.scss +79 -0
- package/src/components/_desc-list.scss +180 -0
- package/src/components/_divider.scss +66 -0
- package/src/components/_dot.scss +115 -0
- package/src/components/_drawer.scss +200 -0
- package/src/components/_dropdown.scss +182 -0
- package/src/components/_empty-state.scss +146 -0
- package/src/components/_field-group.scss +68 -0
- package/src/components/_field-message.scss +75 -0
- package/src/components/_field.scss +127 -0
- package/src/components/_form-actions.scss +58 -0
- package/src/components/_info-row.scss +69 -0
- package/src/components/_input-group.scss +87 -0
- package/src/components/_input.scss +278 -0
- package/src/components/_list.scss +76 -0
- package/src/components/_modal.scss +168 -0
- package/src/components/_page-header.scss +85 -0
- package/src/components/_pagination.scss +138 -0
- package/src/components/_panel.scss +69 -0
- package/src/components/_popover.scss +154 -0
- package/src/components/_progress-circle.scss +123 -0
- package/src/components/_progress.scss +122 -0
- package/src/components/_radio.scss +162 -0
- package/src/components/_segmented.scss +183 -0
- package/src/components/_select.scss +154 -0
- package/src/components/_sidebar.scss +300 -0
- package/src/components/_skeleton.scss +90 -0
- package/src/components/_spinner.scss +84 -0
- package/src/components/_stat.scss +92 -0
- package/src/components/_table.scss +460 -0
- package/src/components/_tabs.scss +327 -0
- package/src/components/_tag.scss +143 -0
- package/src/components/_text.scss +42 -0
- package/src/components/_textarea.scss +57 -0
- package/src/components/_timeline.scss +196 -0
- package/src/components/_title.scss +41 -0
- package/src/components/_toast.scss +221 -0
- package/src/components/_toggle.scss +171 -0
- package/src/components/_toolbar.scss +74 -0
- package/src/components/_topbar.scss +204 -0
- package/src/entries/accordion.scss +4 -0
- package/src/entries/alert.scss +4 -0
- package/src/entries/autocomplete.scss +4 -0
- package/src/entries/avatar-group.scss +4 -0
- package/src/entries/avatar.scss +4 -0
- package/src/entries/badge.scss +4 -0
- package/src/entries/breadcrumb.scss +4 -0
- package/src/entries/btn-group.scss +4 -0
- package/src/entries/button.scss +4 -0
- package/src/entries/card.scss +4 -0
- package/src/entries/checkbox.scss +4 -0
- package/src/entries/code-block.scss +4 -0
- package/src/entries/confirm-modal.scss +4 -0
- package/src/entries/data-table.scss +4 -0
- package/src/entries/desc-list.scss +4 -0
- package/src/entries/divider.scss +4 -0
- package/src/entries/dot.scss +4 -0
- package/src/entries/drawer.scss +4 -0
- package/src/entries/dropdown.scss +4 -0
- package/src/entries/empty-state.scss +4 -0
- package/src/entries/field-group.scss +4 -0
- package/src/entries/field-message.scss +4 -0
- package/src/entries/field.scss +4 -0
- package/src/entries/form-actions.scss +4 -0
- package/src/entries/info-row.scss +4 -0
- package/src/entries/input-group.scss +4 -0
- package/src/entries/input.scss +4 -0
- package/src/entries/list.scss +4 -0
- package/src/entries/modal.scss +4 -0
- package/src/entries/page-header.scss +4 -0
- package/src/entries/pagination.scss +4 -0
- package/src/entries/panel.scss +4 -0
- package/src/entries/popover.scss +4 -0
- package/src/entries/progress-circle.scss +4 -0
- package/src/entries/progress.scss +4 -0
- package/src/entries/radio.scss +4 -0
- package/src/entries/segmented.scss +4 -0
- package/src/entries/select.scss +4 -0
- package/src/entries/sidebar.scss +4 -0
- package/src/entries/skeleton.scss +4 -0
- package/src/entries/spinner.scss +4 -0
- package/src/entries/stat.scss +4 -0
- package/src/entries/table.scss +4 -0
- package/src/entries/tabs.scss +4 -0
- package/src/entries/tag.scss +4 -0
- package/src/entries/text.scss +4 -0
- package/src/entries/textarea.scss +4 -0
- package/src/entries/timeline.scss +4 -0
- package/src/entries/title.scss +4 -0
- package/src/entries/toast.scss +4 -0
- package/src/entries/toggle.scss +4 -0
- package/src/entries/toolbar.scss +4 -0
- package/src/entries/topbar.scss +4 -0
- package/src/index.scss +7 -0
- package/src/js/autocomplete.js +86 -0
- package/src/js/data-table.js +141 -0
- package/src/js/index.js +34 -0
- package/src/js/input-clear.js +25 -0
- package/src/js/package.json +3 -0
- package/src/js/tabs.js +73 -0
- package/src/js/toast.js +161 -0
- package/src/js/util.js +21 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// @component wu-timeline
|
|
3
|
+
//// Ordered list of events with markers and a rail, role colors and a progress mode.
|
|
4
|
+
////
|
|
5
|
+
//// Role words on an item color its marker; `success`, `warning` and `danger` also change the marker shape, so color is not the only cue.
|
|
6
|
+
////
|
|
7
|
+
//// With `aria-current="step"` on one item the list becomes a progress rail: earlier items filled, the current one ringed, later ones hollow. Say "completed" in the item text too.
|
|
8
|
+
////
|
|
9
|
+
//// @since 1.0.0
|
|
10
|
+
//// @needs none
|
|
11
|
+
//// @js none
|
|
12
|
+
//// @example html
|
|
13
|
+
//// <ol class="wu-timeline">
|
|
14
|
+
//// <li class="wu-timeline-item success">
|
|
15
|
+
//// <p class="wu-timeline-title">Order shipped</p>
|
|
16
|
+
//// <time class="wu-timeline-time" datetime="2026-03-02">2 March</time>
|
|
17
|
+
//// <p class="wu-timeline-text">Handed to the carrier.</p>
|
|
18
|
+
//// </li>
|
|
19
|
+
//// <li class="wu-timeline-item danger">
|
|
20
|
+
//// <p class="wu-timeline-title">Payment failed</p>
|
|
21
|
+
//// <time class="wu-timeline-time" datetime="2026-03-01">1 March</time>
|
|
22
|
+
//// </li>
|
|
23
|
+
//// </ol>
|
|
24
|
+
//// @example html
|
|
25
|
+
//// <ol class="wu-timeline">
|
|
26
|
+
//// <li class="wu-timeline-item"><p class="wu-timeline-title">Cart (completed)</p></li>
|
|
27
|
+
//// <li class="wu-timeline-item" aria-current="step"><p class="wu-timeline-title">Payment</p></li>
|
|
28
|
+
//// <li class="wu-timeline-item"><p class="wu-timeline-title">Confirmation</p></li>
|
|
29
|
+
//// </ol>
|
|
30
|
+
//// @modifier brand | info - On an item: marker color @since 1.0.0
|
|
31
|
+
//// @modifier success | warning | danger - On an item: marker color and a check, triangle or octagon shape @since 1.0.0
|
|
32
|
+
//// @modifier animated - Each rail segment draws once as it scrolls into view when the user allows motion; `wu-animated` on an ancestor does the same @since 1.0.0
|
|
33
|
+
//// @part wu-timeline-item - One event: a marker, a rail to the next item and the content @since 1.0.0
|
|
34
|
+
//// @part wu-timeline-title - Event title in medium weight @since 1.0.0
|
|
35
|
+
//// @part wu-timeline-time - Muted time or date line @since 1.0.0
|
|
36
|
+
//// @part wu-timeline-text - Muted description @since 1.0.0
|
|
37
|
+
//// @state aria-current="step" - On an item: the current step, ringed; earlier items fill and later ones turn hollow @since 1.0.0
|
|
38
|
+
////
|
|
39
|
+
|
|
40
|
+
@use "@wovenui/core/mixins" as woven;
|
|
41
|
+
|
|
42
|
+
$marker: woven.token(space-3);
|
|
43
|
+
|
|
44
|
+
.wu-timeline {
|
|
45
|
+
margin: 0;
|
|
46
|
+
padding: 0;
|
|
47
|
+
color: woven.token(text-regular);
|
|
48
|
+
font-size: woven.token(font-size-sm);
|
|
49
|
+
line-height: woven.token(line-height-normal);
|
|
50
|
+
list-style: none;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.wu-timeline-item {
|
|
54
|
+
position: relative;
|
|
55
|
+
padding-block-end: woven.token(space-6);
|
|
56
|
+
padding-inline-start: calc(#{$marker} + #{woven.token(space-3)});
|
|
57
|
+
|
|
58
|
+
// Marker, centered on the first line
|
|
59
|
+
&::before {
|
|
60
|
+
content: "";
|
|
61
|
+
position: absolute;
|
|
62
|
+
inset-block-start: calc((1lh - #{$marker}) / 2);
|
|
63
|
+
inset-inline-start: 0;
|
|
64
|
+
width: $marker;
|
|
65
|
+
height: $marker;
|
|
66
|
+
border-radius: woven.token(radius-full);
|
|
67
|
+
background: woven.token(border-strong);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Rail to the next marker
|
|
71
|
+
&::after {
|
|
72
|
+
content: "";
|
|
73
|
+
position: absolute;
|
|
74
|
+
inset-block: calc((1lh + #{$marker}) / 2 + #{woven.token(space-1)}) calc(#{woven.token(space-1)} - (1lh - #{$marker}) / 2);
|
|
75
|
+
inset-inline-start: calc((#{$marker} - #{woven.token(border-width-2)}) / 2);
|
|
76
|
+
width: woven.token(border-width-2);
|
|
77
|
+
border-radius: woven.token(radius-full);
|
|
78
|
+
background: woven.token(border-regular);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
&:last-child {
|
|
82
|
+
padding-block-end: 0;
|
|
83
|
+
|
|
84
|
+
&::after {
|
|
85
|
+
content: none;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.wu-timeline-title {
|
|
91
|
+
margin: 0;
|
|
92
|
+
font-weight: woven.token(font-weight-medium);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.wu-timeline-time {
|
|
96
|
+
display: block;
|
|
97
|
+
color: woven.token(text-muted);
|
|
98
|
+
font-size: woven.token(font-size-xs);
|
|
99
|
+
font-variant-numeric: tabular-nums;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.wu-timeline-text {
|
|
103
|
+
margin: 0;
|
|
104
|
+
margin-block-start: woven.token(space-1);
|
|
105
|
+
color: woven.token(text-muted);
|
|
106
|
+
text-wrap: pretty;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@each $role in "brand", "success", "danger", "warning", "info" {
|
|
110
|
+
.wu-timeline-item.#{$role}::before {
|
|
111
|
+
background: woven.token($role);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Shape markers from _shared.scss
|
|
116
|
+
.wu-timeline-item:is(.success, .warning, .danger)::before {
|
|
117
|
+
border-radius: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.wu-timeline-item.success::before {
|
|
121
|
+
clip-path: var(--wu-kit-marker-check);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.wu-timeline-item.warning::before {
|
|
125
|
+
clip-path: var(--wu-kit-marker-triangle);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.wu-timeline-item.danger::before {
|
|
129
|
+
clip-path: var(--wu-kit-marker-octagon);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Progress: completed
|
|
133
|
+
.wu-timeline-item:has(~ [aria-current="step"]) {
|
|
134
|
+
&::before,
|
|
135
|
+
&::after {
|
|
136
|
+
background: woven.token(brand);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Progress: current, a ring
|
|
141
|
+
.wu-timeline-item[aria-current="step"] {
|
|
142
|
+
&::before {
|
|
143
|
+
border-radius: woven.token(radius-full);
|
|
144
|
+
clip-path: none;
|
|
145
|
+
background: woven.token(bg-surface);
|
|
146
|
+
box-shadow:
|
|
147
|
+
inset 0 0 0 woven.token(border-width-2) woven.token(brand),
|
|
148
|
+
0 0 0 woven.token(border-width-4) woven.token(brand-subtle);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.wu-timeline-title {
|
|
152
|
+
font-weight: woven.token(font-weight-semibold);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Progress: upcoming, hollow
|
|
157
|
+
.wu-timeline-item[aria-current="step"] ~ .wu-timeline-item {
|
|
158
|
+
color: woven.token(text-muted);
|
|
159
|
+
|
|
160
|
+
&::before {
|
|
161
|
+
border-radius: woven.token(radius-full);
|
|
162
|
+
clip-path: none;
|
|
163
|
+
background: woven.token(bg-surface);
|
|
164
|
+
box-shadow: inset 0 0 0 woven.token(border-width-2) woven.token(border-strong);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Opt-in motion: each rail segment draws once as it scrolls into view
|
|
169
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
170
|
+
.wu-timeline.animated,
|
|
171
|
+
.wu-animated .wu-timeline {
|
|
172
|
+
> .wu-timeline-item::after {
|
|
173
|
+
transform-origin: top;
|
|
174
|
+
animation: wu-timeline-draw woven.token(duration-500) woven.token(ease-out) both;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@supports (animation-timeline: view()) {
|
|
178
|
+
> .wu-timeline-item::after {
|
|
179
|
+
animation-duration: auto;
|
|
180
|
+
animation-timing-function: linear;
|
|
181
|
+
animation-timeline: view();
|
|
182
|
+
animation-range: entry 0% cover 40%;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@keyframes wu-timeline-draw {
|
|
189
|
+
from {
|
|
190
|
+
scale: 1 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
to {
|
|
194
|
+
scale: 1 1;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// @component wu-title
|
|
3
|
+
//// Visual heading size on any element, in four steps.
|
|
4
|
+
////
|
|
5
|
+
//// Pick the heading level for the document outline and the size for the look.
|
|
6
|
+
////
|
|
7
|
+
//// @since 1.0.0
|
|
8
|
+
//// @needs none
|
|
9
|
+
//// @js none
|
|
10
|
+
//// @example html
|
|
11
|
+
//// <h2 class="wu-title xl">Extra large title</h2>
|
|
12
|
+
//// <h2 class="wu-title">Default title</h2>
|
|
13
|
+
//// @example html
|
|
14
|
+
//// <h3 class="wu-title lg">An h3 with the large size</h3>
|
|
15
|
+
//// @modifier sm - Large size, one step below the default @since 1.0.0
|
|
16
|
+
//// @modifier lg - 2xl size @since 1.0.0
|
|
17
|
+
//// @modifier xl - 3xl size @since 1.0.0
|
|
18
|
+
////
|
|
19
|
+
|
|
20
|
+
@use "@wovenui/core/mixins" as woven;
|
|
21
|
+
|
|
22
|
+
.wu-title {
|
|
23
|
+
margin: 0;
|
|
24
|
+
color: woven.token(text-regular);
|
|
25
|
+
font-size: woven.token(font-size-xl);
|
|
26
|
+
font-weight: woven.token(font-weight-semibold);
|
|
27
|
+
line-height: woven.token(line-height-tight);
|
|
28
|
+
text-wrap: balance;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.wu-title.sm {
|
|
32
|
+
font-size: woven.token(font-size-lg);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.wu-title.lg {
|
|
36
|
+
font-size: woven.token(font-size-2xl);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.wu-title.xl {
|
|
40
|
+
font-size: woven.token(font-size-3xl);
|
|
41
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// @component wu-toast
|
|
3
|
+
//// Short notification in a corner of the viewport, shown in a polite live region.
|
|
4
|
+
////
|
|
5
|
+
//// The region sits at the bottom end corner by default and scrolls when the toasts are taller than the viewport. The title text carries the meaning, not the color.
|
|
6
|
+
////
|
|
7
|
+
//// `toast("Saved")` from the kit script adds a toast, and the region when the page has none. It closes the toast after a delay, pauses on hover and focus, keeps at most three open and skips a repeat of an open message.
|
|
8
|
+
////
|
|
9
|
+
//// Create the region at page load; a region added together with its first toast may not be announced.
|
|
10
|
+
////
|
|
11
|
+
//// @since 1.0.0
|
|
12
|
+
//// @needs none
|
|
13
|
+
//// @js required toast, dismiss
|
|
14
|
+
//// @example html
|
|
15
|
+
//// <section class="wu-toast-region animated" aria-live="polite" aria-label="Notifications">
|
|
16
|
+
//// <div class="wu-toast success">
|
|
17
|
+
//// <p class="wu-toast-title">Saved</p>
|
|
18
|
+
//// <p>Your changes are live.</p>
|
|
19
|
+
//// <button class="wu-toast-close" type="button" aria-label="Close"></button>
|
|
20
|
+
//// </div>
|
|
21
|
+
//// </section>
|
|
22
|
+
//// @example html
|
|
23
|
+
//// <section class="wu-toast-region top-end" aria-live="polite" aria-label="Notifications"></section>
|
|
24
|
+
//// @modifier brand | success | danger | warning | info - On a toast: role color on the start edge and the title @since 1.0.0
|
|
25
|
+
//// @modifier top-start | top-end | bottom-start - On the region: moves it to another corner; the default is the bottom end corner @since 1.0.0
|
|
26
|
+
//// @modifier animated - On the region: toasts slide in, fade out and stack behind the newest, fanning out on hover or focus; `wu-animated` on an ancestor does the same @since 1.0.0
|
|
27
|
+
//// @part wu-toast-region - Fixed live region that holds the toasts; hidden when empty @since 1.0.0
|
|
28
|
+
//// @part wu-toast-title - Toast title in semibold weight @since 1.0.0
|
|
29
|
+
//// @part wu-toast-close - Close button with `aria-label`, its cross drawn in CSS @since 1.0.0
|
|
30
|
+
//// @variable --wu-toast--Width [22rem] - Width of the toasts in the region @since 1.0.0
|
|
31
|
+
//// @state hidden - On a toast: removed from layout, after a fade out with `animated` @since 1.0.0
|
|
32
|
+
//// @state :empty - A region with no toasts is hidden @since 1.0.0
|
|
33
|
+
////
|
|
34
|
+
|
|
35
|
+
@use "@wovenui/core/mixins" as woven;
|
|
36
|
+
@use "../close";
|
|
37
|
+
|
|
38
|
+
$-gap: woven.token(space-2);
|
|
39
|
+
$-edge: woven.token(space-4);
|
|
40
|
+
$-depth: "(sibling-count() - sibling-index())";
|
|
41
|
+
|
|
42
|
+
// The padding keeps the toast shadows inside the scrolling region; the toasts sit $-edge from the viewport edge
|
|
43
|
+
.wu-toast-region {
|
|
44
|
+
position: fixed;
|
|
45
|
+
inset-block-end: 0;
|
|
46
|
+
inset-inline-end: 0;
|
|
47
|
+
z-index: woven.token(z-toast);
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
gap: $-gap;
|
|
51
|
+
inline-size: min(calc(var(--wu-toast--Width, 22rem) + 2 * #{$-edge}), 100%);
|
|
52
|
+
max-block-size: 100dvh;
|
|
53
|
+
padding: $-edge;
|
|
54
|
+
overflow-y: auto;
|
|
55
|
+
overscroll-behavior: contain;
|
|
56
|
+
scrollbar-width: thin;
|
|
57
|
+
pointer-events: none;
|
|
58
|
+
|
|
59
|
+
&:empty {
|
|
60
|
+
display: none;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.wu-toast-region.top-start,
|
|
65
|
+
.wu-toast-region.top-end {
|
|
66
|
+
inset-block: 0 auto;
|
|
67
|
+
flex-direction: column-reverse;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.wu-toast-region.top-start,
|
|
71
|
+
.wu-toast-region.bottom-start {
|
|
72
|
+
inset-inline: 0 auto;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.wu-toast {
|
|
76
|
+
flex: none;
|
|
77
|
+
display: grid;
|
|
78
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
79
|
+
column-gap: woven.token(space-2);
|
|
80
|
+
align-items: start;
|
|
81
|
+
padding-block: woven.token(space-3);
|
|
82
|
+
padding-inline: woven.token(space-4) woven.token(space-2);
|
|
83
|
+
border: woven.token(border-width-1) solid woven.token(border-regular);
|
|
84
|
+
border-radius: woven.token(radius-md);
|
|
85
|
+
background: woven.token(bg-raised);
|
|
86
|
+
color: woven.token(text-regular);
|
|
87
|
+
font-size: woven.token(font-size-sm);
|
|
88
|
+
line-height: woven.token(line-height-normal);
|
|
89
|
+
box-shadow: woven.token(shadow-lg);
|
|
90
|
+
pointer-events: auto;
|
|
91
|
+
|
|
92
|
+
&[hidden] {
|
|
93
|
+
display: none;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
> :not(.wu-toast-close) {
|
|
97
|
+
grid-column: 1;
|
|
98
|
+
margin: 0;
|
|
99
|
+
min-inline-size: 0;
|
|
100
|
+
overflow-wrap: anywhere;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
> :not(.wu-toast-close) + :not(.wu-toast-close) {
|
|
104
|
+
margin-block-start: woven.token(space-1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.wu-toast-title {
|
|
109
|
+
font-weight: woven.token(font-weight-semibold);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@each $role in "brand", "success", "danger", "warning", "info" {
|
|
113
|
+
.wu-toast.#{$role} {
|
|
114
|
+
border-inline-start: woven.token(border-width-4) solid woven.token($role);
|
|
115
|
+
|
|
116
|
+
> .wu-toast-title {
|
|
117
|
+
color: woven.token(text-#{$role});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.wu-toast-close {
|
|
123
|
+
@include close.button;
|
|
124
|
+
|
|
125
|
+
grid-area: 1 / 2 / span 9;
|
|
126
|
+
margin-block: calc(-1 * #{woven.token(space-1)});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Stack: older toasts stack behind the newest and fan out while the region
|
|
130
|
+
// is hovered or focused. Layout only; the motion below is separate, so reduced motion keeps the same stack.
|
|
131
|
+
@supports (z-index: sibling-index()) {
|
|
132
|
+
.wu-toast-region.animated,
|
|
133
|
+
.wu-animated .wu-toast-region {
|
|
134
|
+
display: grid;
|
|
135
|
+
max-block-size: none;
|
|
136
|
+
overflow: visible;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.wu-toast-region.animated > .wu-toast,
|
|
140
|
+
.wu-animated .wu-toast-region > .wu-toast {
|
|
141
|
+
grid-area: 1 / 1;
|
|
142
|
+
align-self: end;
|
|
143
|
+
transform-origin: 50% 100%;
|
|
144
|
+
opacity: clamp(0, 3 - #{$-depth}, 1);
|
|
145
|
+
translate: 0 calc(#{$-depth} * -1 * #{woven.token(space-3)});
|
|
146
|
+
scale: calc(1 - #{$-depth} * 0.05);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Fully hidden behind the stack: not focusable until the stack fans out
|
|
150
|
+
.wu-toast-region.animated:not(:hover, :focus-within) > .wu-toast:nth-last-child(n + 4),
|
|
151
|
+
.wu-animated .wu-toast-region:not(:hover, :focus-within) > .wu-toast:nth-last-child(n + 4) {
|
|
152
|
+
visibility: hidden;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.wu-toast-region.top-start.animated > .wu-toast,
|
|
156
|
+
.wu-toast-region.top-end.animated > .wu-toast,
|
|
157
|
+
.wu-animated .wu-toast-region.top-start > .wu-toast,
|
|
158
|
+
.wu-animated .wu-toast-region.top-end > .wu-toast {
|
|
159
|
+
align-self: start;
|
|
160
|
+
transform-origin: 50% 0;
|
|
161
|
+
translate: 0 calc(#{$-depth} * #{woven.token(space-3)});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.wu-toast-region.animated:is(:hover, :focus-within) > .wu-toast,
|
|
165
|
+
.wu-animated .wu-toast-region:is(:hover, :focus-within) > .wu-toast {
|
|
166
|
+
opacity: 1;
|
|
167
|
+
translate: 0 calc(#{$-depth} * (-100% - #{$-gap}));
|
|
168
|
+
scale: 1;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.wu-toast-region.top-start.animated:is(:hover, :focus-within) > .wu-toast,
|
|
172
|
+
.wu-toast-region.top-end.animated:is(:hover, :focus-within) > .wu-toast,
|
|
173
|
+
.wu-animated .wu-toast-region.top-start:is(:hover, :focus-within) > .wu-toast,
|
|
174
|
+
.wu-animated .wu-toast-region.top-end:is(:hover, :focus-within) > .wu-toast {
|
|
175
|
+
translate: 0 calc(#{$-depth} * (100% + #{$-gap}));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Opt-in motion: toasts slide in, fade out, and glide between stack positions
|
|
180
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
181
|
+
.wu-toast-region.animated > .wu-toast,
|
|
182
|
+
.wu-animated .wu-toast-region > .wu-toast {
|
|
183
|
+
transition:
|
|
184
|
+
opacity woven.token(duration-300) woven.token(ease-out),
|
|
185
|
+
translate woven.token(duration-500) var(--wu-kit-ease-spring),
|
|
186
|
+
scale woven.token(duration-500) var(--wu-kit-ease-spring),
|
|
187
|
+
visibility woven.token(duration-300) allow-discrete,
|
|
188
|
+
display woven.token(duration-300) allow-discrete;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Entry: after the stack rules, so the slide wins on the first frame
|
|
192
|
+
.wu-toast-region.animated > .wu-toast,
|
|
193
|
+
.wu-animated .wu-toast-region > .wu-toast {
|
|
194
|
+
@starting-style {
|
|
195
|
+
opacity: 0;
|
|
196
|
+
translate: 0 100%;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.wu-toast-region.top-start.animated > .wu-toast,
|
|
201
|
+
.wu-toast-region.top-end.animated > .wu-toast,
|
|
202
|
+
.wu-animated .wu-toast-region.top-start > .wu-toast,
|
|
203
|
+
.wu-animated .wu-toast-region.top-end > .wu-toast {
|
|
204
|
+
@starting-style {
|
|
205
|
+
opacity: 0;
|
|
206
|
+
translate: 0 -100%;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Closing: fade out before removal
|
|
211
|
+
.wu-toast-region.animated > .wu-toast[hidden],
|
|
212
|
+
.wu-animated .wu-toast-region > .wu-toast[hidden] {
|
|
213
|
+
opacity: 0;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
@media (forced-colors: active) {
|
|
218
|
+
.wu-toast {
|
|
219
|
+
border-inline-start-width: woven.token(border-width-4);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// @component wu-toggle
|
|
3
|
+
//// On and off switch built on a native checkbox with `role="switch"`.
|
|
4
|
+
////
|
|
5
|
+
//// The track is 2.25em by 1.25em with a 1em thumb, so it follows the root type size and the `sm` and `lg` steps.
|
|
6
|
+
////
|
|
7
|
+
//// @since 1.0.0
|
|
8
|
+
//// @needs none
|
|
9
|
+
//// @js none
|
|
10
|
+
//// @example html
|
|
11
|
+
//// <label class="wu-toggle">
|
|
12
|
+
//// <input class="wu-toggle-input" type="checkbox" role="switch" checked>
|
|
13
|
+
//// <span class="wu-toggle-label">Email notifications</span>
|
|
14
|
+
//// </label>
|
|
15
|
+
//// @example html
|
|
16
|
+
//// <label class="wu-toggle lg animated">
|
|
17
|
+
//// <input class="wu-toggle-input" type="checkbox" role="switch" aria-invalid="true">
|
|
18
|
+
//// <span class="wu-toggle-label">Accept the terms</span>
|
|
19
|
+
//// </label>
|
|
20
|
+
//// @modifier sm | lg - Smaller or larger switch and label @since 1.0.0
|
|
21
|
+
//// @modifier animated - Spring thumb when the user allows motion; `wu-animated` on an ancestor does the same @since 1.0.0
|
|
22
|
+
//// @part wu-toggle-input - The checkbox: track and thumb @since 1.0.0
|
|
23
|
+
//// @part wu-toggle-label - Label text beside the switch @since 1.0.0
|
|
24
|
+
//// @state :checked - Brand track and the thumb moved to the end @since 1.0.0
|
|
25
|
+
//// @state disabled - Half opacity and a not-allowed cursor @since 1.0.0
|
|
26
|
+
//// @state aria-invalid="true" | :user-invalid - Danger outline @since 1.0.0
|
|
27
|
+
////
|
|
28
|
+
|
|
29
|
+
@use "@wovenui/core/mixins" as woven;
|
|
30
|
+
|
|
31
|
+
.wu-toggle {
|
|
32
|
+
display: inline-flex;
|
|
33
|
+
align-items: flex-start;
|
|
34
|
+
gap: woven.token(space-2);
|
|
35
|
+
color: woven.token(text-regular);
|
|
36
|
+
font-size: woven.token(font-size-md);
|
|
37
|
+
line-height: woven.token(line-height-normal);
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
|
|
40
|
+
&:has(.wu-toggle-input:disabled) {
|
|
41
|
+
opacity: woven.token(opacity-50);
|
|
42
|
+
cursor: not-allowed;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.wu-toggle-input {
|
|
47
|
+
display: inline-grid;
|
|
48
|
+
flex: none;
|
|
49
|
+
place-items: center start;
|
|
50
|
+
width: 2.25em;
|
|
51
|
+
height: 1.25em;
|
|
52
|
+
margin: 0;
|
|
53
|
+
margin-block-start: calc((1lh - 1.25em) / 2);
|
|
54
|
+
padding-inline: 0.125em;
|
|
55
|
+
border: 0;
|
|
56
|
+
border-radius: woven.token(radius-full);
|
|
57
|
+
background: woven.token(border-control);
|
|
58
|
+
font-size: inherit;
|
|
59
|
+
line-height: inherit;
|
|
60
|
+
vertical-align: middle;
|
|
61
|
+
appearance: none;
|
|
62
|
+
cursor: pointer;
|
|
63
|
+
transition-property: background-color;
|
|
64
|
+
transition-duration: woven.token(duration-150);
|
|
65
|
+
transition-timing-function: woven.token(ease-out);
|
|
66
|
+
|
|
67
|
+
// Thumb
|
|
68
|
+
&::before {
|
|
69
|
+
content: "";
|
|
70
|
+
width: 1em;
|
|
71
|
+
height: 1em;
|
|
72
|
+
border-radius: woven.token(radius-full);
|
|
73
|
+
background: woven.token(bg-surface);
|
|
74
|
+
box-shadow: woven.token(shadow-sm);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
&:hover:not(:disabled, :checked) {
|
|
78
|
+
background: woven.token(border-control-hover);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
&:is([aria-invalid="true"], :user-invalid) {
|
|
82
|
+
outline: woven.token(border-width-1) solid woven.token(danger);
|
|
83
|
+
outline-offset: woven.token(border-width-1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&:focus-visible {
|
|
87
|
+
outline: woven.token(border-focus-width) solid woven.token(border-focus);
|
|
88
|
+
outline-offset: woven.token(border-focus-offset);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&:checked {
|
|
92
|
+
background: woven.token(brand);
|
|
93
|
+
|
|
94
|
+
&::before {
|
|
95
|
+
background: woven.token(text-on-brand);
|
|
96
|
+
translate: 1em 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&:hover:not(:disabled) {
|
|
100
|
+
background: woven.token(brand-hover);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
&:checked:dir(rtl)::before {
|
|
105
|
+
translate: -1em 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
&:disabled {
|
|
109
|
+
opacity: woven.token(opacity-50);
|
|
110
|
+
cursor: not-allowed;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.wu-toggle > &:disabled {
|
|
114
|
+
opacity: 1;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.wu-toggle-label {
|
|
119
|
+
min-width: 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.wu-toggle.sm {
|
|
123
|
+
font-size: woven.token(font-size-sm);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.wu-toggle.lg {
|
|
127
|
+
font-size: woven.token(font-size-lg);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Calm default: the thumb slides without overshoot
|
|
131
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
132
|
+
.wu-toggle-input::before {
|
|
133
|
+
transition: translate woven.token(duration-150) woven.token(ease-out);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Opt-in motion: spring thumb
|
|
137
|
+
.wu-toggle.animated .wu-toggle-input::before,
|
|
138
|
+
.wu-animated .wu-toggle-input::before {
|
|
139
|
+
transition: translate woven.token(duration-500) var(--wu-kit-ease-spring);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@media (forced-colors: active) {
|
|
144
|
+
.wu-toggle-input {
|
|
145
|
+
padding-inline: calc(0.125em - #{woven.token(border-width-1)});
|
|
146
|
+
border: woven.token(border-width-1) solid CanvasText;
|
|
147
|
+
background: Canvas;
|
|
148
|
+
forced-color-adjust: none;
|
|
149
|
+
|
|
150
|
+
&::before {
|
|
151
|
+
background: CanvasText;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
&:checked {
|
|
155
|
+
border-color: Highlight;
|
|
156
|
+
background: Highlight;
|
|
157
|
+
|
|
158
|
+
&::before {
|
|
159
|
+
background: HighlightText;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
&:disabled {
|
|
164
|
+
border-color: GrayText;
|
|
165
|
+
|
|
166
|
+
&::before {
|
|
167
|
+
background: GrayText;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|