@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,278 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// @component wu-input
|
|
3
|
+
//// Text input in three sizes, with disabled, read-only and invalid looks, plus prefix, suffix and a clear button inside the field border.
|
|
4
|
+
////
|
|
5
|
+
//// Core base already sets the border, background, hover, focus ring, invalid border, disabled look, placeholder color, padding and the md height; the kit adds the radius, type size and sizes.
|
|
6
|
+
////
|
|
7
|
+
//// `wu-input-affix` draws the box and the input inside goes bare. Prefix and suffix sit on the inline start and end, so they swap in right-to-left pages. A `wu-select` can replace the input. `sm` and `lg` go on the wrapper. `wu-input-clear` is started by the kit script: it shows while the field has text, clears it and refocuses.
|
|
8
|
+
////
|
|
9
|
+
//// @since 1.0.0
|
|
10
|
+
//// @needs none
|
|
11
|
+
//// @js optional initInputClear
|
|
12
|
+
//// @example html
|
|
13
|
+
//// <input class="wu-input" type="text" aria-label="Name" placeholder="Name">
|
|
14
|
+
//// <input class="wu-input sm" type="text" aria-label="Code" value="A-12" readonly>
|
|
15
|
+
//// <input class="wu-input lg" type="email" aria-label="Email" aria-invalid="true">
|
|
16
|
+
//// @example html
|
|
17
|
+
//// <div class="wu-input-affix">
|
|
18
|
+
//// <span class="wu-input-prefix"><svg aria-hidden="true" viewBox="0 0 24 24"><circle cx="11" cy="11" r="6" /></svg></span>
|
|
19
|
+
//// <input class="wu-input" type="search" aria-label="Search">
|
|
20
|
+
//// <button class="wu-input-clear" type="button" aria-label="Clear" hidden></button>
|
|
21
|
+
//// <span class="wu-input-suffix">USD</span>
|
|
22
|
+
//// </div>
|
|
23
|
+
//// @modifier sm | lg - Small or large control height, padding and font size; also on `wu-input-affix`, and taken from a `wu-field-group sm` or `lg` when the control has no size @since 1.0.0
|
|
24
|
+
//// @part wu-input-affix - Wrapper that draws the field box around a bare input or select, with a prefix, suffix and clear button @since 1.0.0
|
|
25
|
+
//// @part wu-input-prefix - Content before the input, such as an icon or currency symbol @since 1.0.0
|
|
26
|
+
//// @part wu-input-suffix - Content after the input, such as a unit @since 1.0.0
|
|
27
|
+
//// @part wu-input-clear - Clear button inside the affix; an empty button shows a multiplication sign; give it an `aria-label` @since 1.0.0
|
|
28
|
+
//// @state disabled - Not-allowed cursor; an affix with a disabled control dims @since 1.0.0
|
|
29
|
+
//// @state readonly - Alternate background @since 1.0.0
|
|
30
|
+
//// @state aria-invalid="true" | :user-invalid - Danger border doubled to 2px, so the change is not color alone @since 1.0.0
|
|
31
|
+
////
|
|
32
|
+
|
|
33
|
+
@use "@wovenui/core/mixins" as woven;
|
|
34
|
+
|
|
35
|
+
@mixin centered-pad($height) {
|
|
36
|
+
$rest: "#{$height} - 2 * #{woven.token(border-width-1)} - 1em * #{woven.token(line-height-normal)}";
|
|
37
|
+
|
|
38
|
+
--wu-kit-pad-start: #{round(down, calc((#{$rest}) / 2), 1px)};
|
|
39
|
+
|
|
40
|
+
padding-block: var(--wu-kit-pad-start) calc(#{$rest} - var(--wu-kit-pad-start));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Text-like <input>. Core base already sets the border, background, hover, focus ring, invalid border,
|
|
44
|
+
// disabled look, placeholder color, padding and the md height; the kit adds radius, type size and sizes.
|
|
45
|
+
.wu-input {
|
|
46
|
+
border-radius: woven.token(radius-md);
|
|
47
|
+
font-size: woven.token(font-size-md);
|
|
48
|
+
line-height: woven.token(line-height-normal);
|
|
49
|
+
|
|
50
|
+
&:disabled {
|
|
51
|
+
cursor: not-allowed;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&[readonly] {
|
|
55
|
+
background-color: woven.token(bg-alternate);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Invalid: core's danger border doubled to 2px, so the change is not color alone
|
|
59
|
+
&:is([aria-invalid="true"], :user-invalid) {
|
|
60
|
+
box-shadow: inset 0 0 0 woven.token(border-width-1) woven.token(danger);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.wu-input.sm {
|
|
65
|
+
height: woven.token(control-height-sm);
|
|
66
|
+
padding-inline: woven.token(control-padding-inline-sm);
|
|
67
|
+
font-size: woven.token(font-size-sm);
|
|
68
|
+
|
|
69
|
+
@include centered-pad(woven.token(control-height-sm));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.wu-input.lg {
|
|
73
|
+
height: woven.token(control-height-lg);
|
|
74
|
+
padding-inline: woven.token(control-padding-inline-lg);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Prefix and suffix inside the field border; the wrapper draws the box and the input inside goes bare.
|
|
78
|
+
// <div class="wu-input-affix">
|
|
79
|
+
// <span class="wu-input-prefix"><svg aria-hidden="true">...</svg></span>
|
|
80
|
+
// <input class="wu-input" type="search" aria-label="Search">
|
|
81
|
+
// <button class="wu-input-clear" type="button" aria-label="Clear" hidden></button>
|
|
82
|
+
// <span class="wu-input-suffix">USD</span>
|
|
83
|
+
// </div>
|
|
84
|
+
// Prefix and suffix sit on the inline start and end, so they swap in RTL. A wu-select can replace the input.
|
|
85
|
+
// wu-input-clear is started by the kit script: it shows with content, clears and refocuses. Sizes: sm, lg on the wrapper.
|
|
86
|
+
.wu-input-affix {
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
gap: woven.token(space-2);
|
|
90
|
+
width: 100%;
|
|
91
|
+
|
|
92
|
+
--wu-kit-affix-height: #{woven.token(control-height-md)};
|
|
93
|
+
|
|
94
|
+
height: var(--wu-kit-affix-height);
|
|
95
|
+
padding-inline: woven.token(control-padding-inline-md);
|
|
96
|
+
border: woven.token(border-width-1) solid woven.token(border-control);
|
|
97
|
+
border-radius: woven.token(radius-md);
|
|
98
|
+
background-color: woven.token(bg-surface);
|
|
99
|
+
color: woven.token(text-regular);
|
|
100
|
+
font-size: woven.token(font-size-md);
|
|
101
|
+
line-height: woven.token(line-height-normal);
|
|
102
|
+
transition: border-color woven.token(duration-150) woven.token(ease-out);
|
|
103
|
+
|
|
104
|
+
&:hover:not(:has(:disabled, [aria-invalid="true"], :user-invalid)) {
|
|
105
|
+
border-color: woven.token(border-control-hover);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
&:has(:focus-visible) {
|
|
109
|
+
outline: woven.token(border-focus-width) solid woven.token(border-focus);
|
|
110
|
+
outline-offset: calc(-1 * #{woven.token(border-focus-offset)});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
&:has(:is([aria-invalid="true"], :user-invalid)) {
|
|
114
|
+
border-color: woven.token(danger);
|
|
115
|
+
box-shadow: inset 0 0 0 woven.token(border-width-1) woven.token(danger);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&:has(.wu-input:disabled, .wu-select:disabled) {
|
|
119
|
+
background-color: woven.token(bg-disabled);
|
|
120
|
+
opacity: woven.token(opacity-50);
|
|
121
|
+
cursor: not-allowed;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
> :is(.wu-input, .wu-select) {
|
|
125
|
+
flex: 1 1 auto;
|
|
126
|
+
width: 1%;
|
|
127
|
+
min-width: 0;
|
|
128
|
+
height: 100%;
|
|
129
|
+
padding-block: 0;
|
|
130
|
+
padding-inline: 0;
|
|
131
|
+
border: 0;
|
|
132
|
+
border-radius: 0;
|
|
133
|
+
background-color: transparent;
|
|
134
|
+
box-shadow: none;
|
|
135
|
+
font-size: inherit;
|
|
136
|
+
outline: 0;
|
|
137
|
+
|
|
138
|
+
&:is(:hover, :focus-visible, :disabled, [aria-invalid="true"], :user-invalid) {
|
|
139
|
+
border: 0;
|
|
140
|
+
background-color: transparent;
|
|
141
|
+
box-shadow: none;
|
|
142
|
+
opacity: 1;
|
|
143
|
+
outline: 0;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
> .wu-input {
|
|
148
|
+
@include centered-pad(var(--wu-kit-affix-height));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// A single-line select rounds half-pixel padding down, as .wu-select.sm does, so the text sits centered.
|
|
152
|
+
// The doubled class outranks the align-items: center that select.scss sets here.
|
|
153
|
+
> .wu-select.wu-select:not([multiple], [size]:not([size="1"])) {
|
|
154
|
+
align-items: normal;
|
|
155
|
+
padding-block: round(down, calc((var(--wu-kit-affix-height) - 2 * #{woven.token(border-width-1)} - 1em * #{woven.token(line-height-normal)}) / 2), 1px);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// A native search field draws its own clear mark; the kit button replaces it
|
|
159
|
+
> input[type="search"]::-webkit-search-cancel-button {
|
|
160
|
+
appearance: none;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
> input[type="search"]::-webkit-search-decoration {
|
|
164
|
+
appearance: none;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Select arrow keeps its inline-end room inside the wrapper
|
|
168
|
+
> .wu-select:not([multiple], [size]:not([size="1"])) {
|
|
169
|
+
padding-inline-end: calc(2 * 0.3125rem + #{woven.token(space-2)});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.wu-input-prefix,
|
|
174
|
+
.wu-input-suffix {
|
|
175
|
+
display: inline-flex;
|
|
176
|
+
flex: none;
|
|
177
|
+
align-items: center;
|
|
178
|
+
color: woven.token(text-muted);
|
|
179
|
+
white-space: nowrap;
|
|
180
|
+
|
|
181
|
+
> svg {
|
|
182
|
+
flex-shrink: 0;
|
|
183
|
+
width: 1em;
|
|
184
|
+
height: 1em;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.wu-input-clear {
|
|
189
|
+
display: inline-flex;
|
|
190
|
+
flex: none;
|
|
191
|
+
align-items: center;
|
|
192
|
+
justify-content: center;
|
|
193
|
+
inline-size: 1.5em;
|
|
194
|
+
block-size: 1.5em;
|
|
195
|
+
padding: 0;
|
|
196
|
+
border: 0;
|
|
197
|
+
border-radius: woven.token(radius-full);
|
|
198
|
+
background: transparent;
|
|
199
|
+
color: woven.token(text-muted);
|
|
200
|
+
font-size: inherit;
|
|
201
|
+
line-height: 1;
|
|
202
|
+
cursor: pointer;
|
|
203
|
+
|
|
204
|
+
&:empty::before {
|
|
205
|
+
content: "\00d7";
|
|
206
|
+
font-size: 1.25em;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
&:hover {
|
|
210
|
+
background: woven.token(bg-hover);
|
|
211
|
+
color: woven.token(text-regular);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
&:focus-visible {
|
|
215
|
+
outline: woven.token(border-focus-width) solid woven.token(border-focus);
|
|
216
|
+
outline-offset: woven.token(border-focus-offset);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
&[hidden] {
|
|
220
|
+
display: none;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
> svg {
|
|
224
|
+
flex-shrink: 0;
|
|
225
|
+
width: 1em;
|
|
226
|
+
height: 1em;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.wu-input-affix.sm {
|
|
231
|
+
--wu-kit-affix-height: #{woven.token(control-height-sm)};
|
|
232
|
+
|
|
233
|
+
height: var(--wu-kit-affix-height);
|
|
234
|
+
padding-inline: woven.token(control-padding-inline-sm);
|
|
235
|
+
font-size: woven.token(font-size-sm);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.wu-input-affix.lg {
|
|
239
|
+
--wu-kit-affix-height: #{woven.token(control-height-lg)};
|
|
240
|
+
|
|
241
|
+
height: var(--wu-kit-affix-height);
|
|
242
|
+
padding-inline: woven.token(control-padding-inline-lg);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
@media (forced-colors: active) {
|
|
246
|
+
.wu-input-affix:has(:focus-visible) {
|
|
247
|
+
outline-color: Highlight;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Size from a wu-field-group sm or lg; a control with its own sm or lg keeps it
|
|
252
|
+
@each $size, $font in ("sm": "font-size-sm", "lg": "font-size-md") {
|
|
253
|
+
$h: woven.token(control-height-#{$size});
|
|
254
|
+
$pad: woven.token(control-padding-inline-#{$size});
|
|
255
|
+
$fs: woven.token(#{$font});
|
|
256
|
+
|
|
257
|
+
:where(.wu-field-group.#{$size}) {
|
|
258
|
+
.wu-input:not(.sm, .lg, .wu-input-affix > *) {
|
|
259
|
+
height: $h;
|
|
260
|
+
padding-inline: $pad;
|
|
261
|
+
font-size: $fs;
|
|
262
|
+
|
|
263
|
+
@if $size == "sm" {
|
|
264
|
+
@include centered-pad($h);
|
|
265
|
+
} @else {
|
|
266
|
+
padding-block: 0;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.wu-input-affix:not(.sm, .lg) {
|
|
271
|
+
--wu-kit-affix-height: #{$h};
|
|
272
|
+
|
|
273
|
+
height: $h;
|
|
274
|
+
padding-inline: $pad;
|
|
275
|
+
font-size: $fs;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// @component wu-list
|
|
3
|
+
//// Vertical list of rows with a title, text and room for leading or trailing content.
|
|
4
|
+
////
|
|
5
|
+
//// Use a `ul` or `ol`; add `role="list"` to keep list semantics without markers. `wu-list-body` grows between leading and trailing content such as an avatar, badge or button.
|
|
6
|
+
////
|
|
7
|
+
//// @since 1.0.0
|
|
8
|
+
//// @needs none
|
|
9
|
+
//// @js none
|
|
10
|
+
//// @example html
|
|
11
|
+
//// <ul class="wu-list divided" role="list">
|
|
12
|
+
//// <li class="wu-list-item">
|
|
13
|
+
//// <div class="wu-list-body">
|
|
14
|
+
//// <p class="wu-list-title">Ada Lovelace</p>
|
|
15
|
+
//// <p class="wu-list-text">Engineer</p>
|
|
16
|
+
//// </div>
|
|
17
|
+
//// <span class="wu-badge success">Active</span>
|
|
18
|
+
//// </li>
|
|
19
|
+
//// <li class="wu-list-item">
|
|
20
|
+
//// <div class="wu-list-body">
|
|
21
|
+
//// <p class="wu-list-title">Grace Hopper</p>
|
|
22
|
+
//// </div>
|
|
23
|
+
//// </li>
|
|
24
|
+
//// </ul>
|
|
25
|
+
//// @modifier divided - Line between rows @since 1.0.0
|
|
26
|
+
//// @modifier sm - Tighter row padding @since 1.0.0
|
|
27
|
+
//// @part wu-list-item - Row, a flex container @since 1.0.0
|
|
28
|
+
//// @part wu-list-body - Column that grows between leading and trailing content @since 1.0.0
|
|
29
|
+
//// @part wu-list-title - Row title, medium weight @since 1.0.0
|
|
30
|
+
//// @part wu-list-text - Muted supporting text @since 1.0.0
|
|
31
|
+
////
|
|
32
|
+
|
|
33
|
+
@use "@wovenui/core/mixins" as woven;
|
|
34
|
+
|
|
35
|
+
.wu-list {
|
|
36
|
+
margin: 0;
|
|
37
|
+
padding: 0;
|
|
38
|
+
color: woven.token(text-regular);
|
|
39
|
+
font-size: woven.token(font-size-sm);
|
|
40
|
+
line-height: woven.token(line-height-normal);
|
|
41
|
+
list-style: none;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.wu-list-item {
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: woven.token(space-3);
|
|
48
|
+
padding-block: woven.token(space-3);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Grows between leading and trailing content (avatar, badge, button)
|
|
52
|
+
.wu-list-body {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex: 1;
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
min-width: 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.wu-list-title {
|
|
60
|
+
margin: 0;
|
|
61
|
+
font-weight: woven.token(font-weight-medium);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.wu-list-text {
|
|
65
|
+
margin: 0;
|
|
66
|
+
color: woven.token(text-muted);
|
|
67
|
+
text-wrap: pretty;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.wu-list.divided > .wu-list-item + .wu-list-item {
|
|
71
|
+
border-block-start: woven.token(border-width-1) solid woven.token(border-regular);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.wu-list.sm > .wu-list-item {
|
|
75
|
+
padding-block: woven.token(space-2);
|
|
76
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// @component wu-modal
|
|
3
|
+
//// Dialog built on the native `dialog` element, with header, body and footer.
|
|
4
|
+
////
|
|
5
|
+
//// Esc closes it, and `closedby="any"` adds click outside where supported. `showModal()` and the `command` attribute lock page scroll; `show()` opens it non-modal and leaves the page alone.
|
|
6
|
+
////
|
|
7
|
+
//// The body scrolls on its own when the content is taller than the dialog.
|
|
8
|
+
////
|
|
9
|
+
//// @since 1.0.0
|
|
10
|
+
//// @needs none
|
|
11
|
+
//// @js none
|
|
12
|
+
//// @example html
|
|
13
|
+
//// <button class="wu-btn" type="button" commandfor="m1" command="show-modal">Open</button>
|
|
14
|
+
//// <dialog class="wu-modal" id="m1" aria-labelledby="m1-title" closedby="any">
|
|
15
|
+
//// <header class="wu-modal-header">
|
|
16
|
+
//// <h2 class="wu-modal-title" id="m1-title">Title</h2>
|
|
17
|
+
//// <button class="wu-modal-close" type="button" commandfor="m1" command="close" aria-label="Close"></button>
|
|
18
|
+
//// </header>
|
|
19
|
+
//// <div class="wu-modal-body">Content</div>
|
|
20
|
+
//// <form class="wu-modal-footer" method="dialog">
|
|
21
|
+
//// <button class="wu-btn">Cancel</button>
|
|
22
|
+
//// <button class="wu-btn brand" value="confirm">Save</button>
|
|
23
|
+
//// </form>
|
|
24
|
+
//// </dialog>
|
|
25
|
+
//// @modifier sm | lg - Narrow (24rem) or wide (48rem) dialog; the default is 32rem @since 1.0.0
|
|
26
|
+
//// @modifier animated - Fades and scales the dialog in and out and fades the backdrop when the user allows motion; `wu-animated` on an ancestor does the same @since 1.0.0
|
|
27
|
+
//// @part wu-modal-header - Top row for the title and close button @since 1.0.0
|
|
28
|
+
//// @part wu-modal-title - Dialog heading @since 1.0.0
|
|
29
|
+
//// @part wu-modal-close - Close button drawn with the shared close icon; give it an `aria-label` @since 1.0.0
|
|
30
|
+
//// @part wu-modal-body - Scrolling content area @since 1.0.0
|
|
31
|
+
//// @part wu-modal-footer - Bottom row for actions, aligned to the inline end @since 1.0.0
|
|
32
|
+
//// @variable --wu-modal--Width [32rem] - Dialog width @since 1.0.0
|
|
33
|
+
//// @variable --wu-modal--MaxHeight [calc(100dvh - 4rem)] - Largest dialog height before the body scrolls @since 1.0.0
|
|
34
|
+
//// @variable --wu-modal--Backdrop [50% black, 70% in dark themes] - Backdrop color @since 1.0.0
|
|
35
|
+
//// @state open - Displays the dialog as a flex column @since 1.0.0
|
|
36
|
+
////
|
|
37
|
+
|
|
38
|
+
@use "@wovenui/core/mixins" as woven;
|
|
39
|
+
@use "../close";
|
|
40
|
+
|
|
41
|
+
.wu-modal {
|
|
42
|
+
inset: 0;
|
|
43
|
+
inline-size: var(--wu-modal--Width, 32rem);
|
|
44
|
+
max-inline-size: calc(100% - #{woven.token(space-8)});
|
|
45
|
+
block-size: fit-content;
|
|
46
|
+
max-block-size: var(--wu-modal--MaxHeight, calc(100dvh - #{woven.token(space-16)}));
|
|
47
|
+
margin: auto;
|
|
48
|
+
padding: 0;
|
|
49
|
+
border: woven.token(border-width-1) solid woven.token(border-regular);
|
|
50
|
+
border-radius: woven.token(radius-lg);
|
|
51
|
+
background: woven.token(bg-surface);
|
|
52
|
+
color: woven.token(text-regular);
|
|
53
|
+
box-shadow: woven.token(shadow-xl);
|
|
54
|
+
z-index: woven.token(z-modal);
|
|
55
|
+
|
|
56
|
+
&[open] {
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-direction: column;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&::backdrop {
|
|
62
|
+
background: var(--wu-modal--Backdrop, color-mix(in srgb, #{woven.token(black)} 50%, transparent));
|
|
63
|
+
|
|
64
|
+
// Stronger in dark themes, so the dialog stands apart
|
|
65
|
+
@include woven.dark-mode {
|
|
66
|
+
background: var(--wu-modal--Backdrop, color-mix(in srgb, #{woven.token(black)} 70%, transparent));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Page scroll lock while one is open with showModal(); show() opens it non-modal and leaves the page alone.
|
|
72
|
+
// The gutter keeps the page from shifting when its scrollbar goes away.
|
|
73
|
+
:root:has(.wu-modal:modal) {
|
|
74
|
+
overflow: hidden;
|
|
75
|
+
scrollbar-gutter: stable;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.wu-modal.sm {
|
|
79
|
+
inline-size: var(--wu-modal--Width, 24rem);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.wu-modal.lg {
|
|
83
|
+
inline-size: var(--wu-modal--Width, 48rem);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.wu-modal-header,
|
|
87
|
+
.wu-modal-footer {
|
|
88
|
+
display: flex;
|
|
89
|
+
flex: none;
|
|
90
|
+
align-items: center;
|
|
91
|
+
gap: woven.token(space-2);
|
|
92
|
+
margin: 0;
|
|
93
|
+
padding-block: woven.token(space-4);
|
|
94
|
+
padding-inline: woven.token(space-5);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.wu-modal-header {
|
|
98
|
+
justify-content: space-between;
|
|
99
|
+
border-block-end: woven.token(border-width-1) solid woven.token(border-regular);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.wu-modal-title {
|
|
103
|
+
margin: 0;
|
|
104
|
+
font-size: woven.token(font-size-lg);
|
|
105
|
+
font-weight: woven.token(font-weight-semibold);
|
|
106
|
+
line-height: woven.token(line-height-tight);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Scrolls on its own when the content is taller than the dialog
|
|
110
|
+
.wu-modal-body {
|
|
111
|
+
flex: 1 1 auto;
|
|
112
|
+
min-block-size: 0;
|
|
113
|
+
padding: woven.token(space-5);
|
|
114
|
+
overflow-y: auto;
|
|
115
|
+
overscroll-behavior: contain;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.wu-modal-footer {
|
|
119
|
+
flex-wrap: wrap;
|
|
120
|
+
justify-content: flex-end;
|
|
121
|
+
border-block-start: woven.token(border-width-1) solid woven.token(border-regular);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.wu-modal-close {
|
|
125
|
+
@include close.button;
|
|
126
|
+
|
|
127
|
+
margin-inline-end: calc(-1 * #{woven.token(space-2)});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Opt-in motion: the dialog fades and scales in and out, the backdrop fades
|
|
131
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
132
|
+
.wu-modal.animated,
|
|
133
|
+
.wu-animated .wu-modal {
|
|
134
|
+
opacity: 0;
|
|
135
|
+
scale: 0.96;
|
|
136
|
+
transition:
|
|
137
|
+
opacity woven.token(duration-200) woven.token(ease-out),
|
|
138
|
+
scale woven.token(duration-200) woven.token(ease-out),
|
|
139
|
+
display woven.token(duration-200) allow-discrete,
|
|
140
|
+
overlay woven.token(duration-200) allow-discrete;
|
|
141
|
+
|
|
142
|
+
&::backdrop {
|
|
143
|
+
opacity: 0;
|
|
144
|
+
transition:
|
|
145
|
+
opacity woven.token(duration-200) woven.token(ease-out),
|
|
146
|
+
display woven.token(duration-200) allow-discrete,
|
|
147
|
+
overlay woven.token(duration-200) allow-discrete;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
&[open] {
|
|
151
|
+
opacity: 1;
|
|
152
|
+
scale: 1;
|
|
153
|
+
|
|
154
|
+
@starting-style {
|
|
155
|
+
opacity: 0;
|
|
156
|
+
scale: 0.96;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
&[open]::backdrop {
|
|
161
|
+
opacity: 1;
|
|
162
|
+
|
|
163
|
+
@starting-style {
|
|
164
|
+
opacity: 0;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// @component wu-page-header
|
|
3
|
+
//// Page title row with an optional description, breadcrumb and action buttons.
|
|
4
|
+
////
|
|
5
|
+
//// Actions line up with the title and wrap below it on narrow screens. A direct `wu-breadcrumb` child takes its own full-width row above the title.
|
|
6
|
+
////
|
|
7
|
+
//// @since 1.0.0
|
|
8
|
+
//// @needs none
|
|
9
|
+
//// @js none
|
|
10
|
+
//// @example html
|
|
11
|
+
//// <header class="wu-page-header divided">
|
|
12
|
+
//// <nav class="wu-breadcrumb" aria-label="Breadcrumb">
|
|
13
|
+
//// <ol>
|
|
14
|
+
//// <li><a href="/projects">Projects</a></li>
|
|
15
|
+
//// <li aria-current="page">Apollo</li>
|
|
16
|
+
//// </ol>
|
|
17
|
+
//// </nav>
|
|
18
|
+
//// <div class="wu-page-header-main">
|
|
19
|
+
//// <h1 class="wu-page-header-title">Apollo</h1>
|
|
20
|
+
//// <p class="wu-page-header-text">Launch plan and open tasks.</p>
|
|
21
|
+
//// </div>
|
|
22
|
+
//// <div class="wu-page-header-actions">
|
|
23
|
+
//// <button class="wu-btn" type="button">Share</button>
|
|
24
|
+
//// <button class="wu-btn brand" type="button">New task</button>
|
|
25
|
+
//// </div>
|
|
26
|
+
//// </header>
|
|
27
|
+
//// @modifier divided - Adds a bottom border and padding under the header @since 1.0.0
|
|
28
|
+
//// @part wu-page-header-main - Column that holds the title and description @since 1.0.0
|
|
29
|
+
//// @part wu-page-header-title - Page heading @since 1.0.0
|
|
30
|
+
//// @part wu-page-header-text - Muted description under the title @since 1.0.0
|
|
31
|
+
//// @part wu-page-header-actions - Row of buttons, centered on the title first line @since 1.0.0
|
|
32
|
+
////
|
|
33
|
+
|
|
34
|
+
@use "@wovenui/core/mixins" as woven;
|
|
35
|
+
|
|
36
|
+
.wu-page-header {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-wrap: wrap;
|
|
39
|
+
align-items: flex-start;
|
|
40
|
+
justify-content: space-between;
|
|
41
|
+
gap: woven.token(space-3) woven.token(space-4);
|
|
42
|
+
color: woven.token(text-regular);
|
|
43
|
+
|
|
44
|
+
> .wu-breadcrumb {
|
|
45
|
+
flex-basis: 100%;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.wu-page-header-main {
|
|
50
|
+
display: flex;
|
|
51
|
+
flex: 1 1 woven.token(space-64);
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
gap: woven.token(space-1);
|
|
54
|
+
min-width: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.wu-page-header-title {
|
|
58
|
+
margin: 0;
|
|
59
|
+
font-size: woven.token(font-size-2xl);
|
|
60
|
+
font-weight: woven.token(font-weight-semibold);
|
|
61
|
+
line-height: woven.token(line-height-tight);
|
|
62
|
+
text-wrap: balance;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.wu-page-header-text {
|
|
66
|
+
max-inline-size: 65ch;
|
|
67
|
+
margin: 0;
|
|
68
|
+
color: woven.token(text-muted);
|
|
69
|
+
font-size: woven.token(font-size-sm);
|
|
70
|
+
text-wrap: pretty;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Centered on the title's first line, however long the description is
|
|
74
|
+
.wu-page-header-actions {
|
|
75
|
+
display: flex;
|
|
76
|
+
flex-wrap: wrap;
|
|
77
|
+
align-items: center;
|
|
78
|
+
gap: woven.token(space-2);
|
|
79
|
+
min-block-size: calc(#{woven.token(font-size-2xl)} * #{woven.token(line-height-tight)});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.wu-page-header.divided {
|
|
83
|
+
padding-block-end: woven.token(space-4);
|
|
84
|
+
border-block-end: woven.token(border-width-1) solid woven.token(border-regular);
|
|
85
|
+
}
|