@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,115 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// @component wu-breadcrumb
|
|
3
|
+
//// Trail of links that shows where the page sits in the site.
|
|
4
|
+
////
|
|
5
|
+
//// Wrap an ordered list in a `nav` with an `aria-label`, and mark the last item with `aria-current="page"`.
|
|
6
|
+
////
|
|
7
|
+
//// @since 1.0.0
|
|
8
|
+
//// @needs none
|
|
9
|
+
//// @js none
|
|
10
|
+
//// @example html
|
|
11
|
+
//// <nav class="wu-breadcrumb" aria-label="Breadcrumb">
|
|
12
|
+
//// <ol class="wu-breadcrumb-list">
|
|
13
|
+
//// <li class="wu-breadcrumb-item"><a class="wu-breadcrumb-link" href="/">Home</a></li>
|
|
14
|
+
//// <li class="wu-breadcrumb-item"><a class="wu-breadcrumb-link" href="/projects/">Projects</a></li>
|
|
15
|
+
//// <li class="wu-breadcrumb-item"><span aria-current="page">Website</span></li>
|
|
16
|
+
//// </ol>
|
|
17
|
+
//// </nav>
|
|
18
|
+
//// @example html
|
|
19
|
+
//// <nav class="wu-breadcrumb slash sm" aria-label="Breadcrumb">
|
|
20
|
+
//// <ol class="wu-breadcrumb-list">
|
|
21
|
+
//// <li class="wu-breadcrumb-item"><a class="wu-breadcrumb-link" href="/">Home</a></li>
|
|
22
|
+
//// <li class="wu-breadcrumb-item"><span aria-current="page">Docs</span></li>
|
|
23
|
+
//// </ol>
|
|
24
|
+
//// </nav>
|
|
25
|
+
//// @modifier slash - A slash separator instead of the chevron @since 1.0.0
|
|
26
|
+
//// @modifier sm - Smaller font size @since 1.0.0
|
|
27
|
+
//// @part wu-breadcrumb-list - The `ol` that lays the items out and wraps them @since 1.0.0
|
|
28
|
+
//// @part wu-breadcrumb-item - One `li` in the trail, with a separator before it @since 1.0.0
|
|
29
|
+
//// @part wu-breadcrumb-link - Underlined link to a parent page @since 1.0.0
|
|
30
|
+
//// @state aria-current="page" - The current page: regular text weight and color, no underline @since 1.0.0
|
|
31
|
+
////
|
|
32
|
+
|
|
33
|
+
@use "@wovenui/core/mixins" as woven;
|
|
34
|
+
|
|
35
|
+
.wu-breadcrumb {
|
|
36
|
+
color: woven.token(text-muted);
|
|
37
|
+
font-size: woven.token(font-size-sm);
|
|
38
|
+
line-height: woven.token(line-height-normal);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.wu-breadcrumb-list {
|
|
42
|
+
display: flex;
|
|
43
|
+
flex-wrap: wrap;
|
|
44
|
+
align-items: center;
|
|
45
|
+
gap: woven.token(space-1) woven.token(space-2);
|
|
46
|
+
margin: 0;
|
|
47
|
+
padding: 0;
|
|
48
|
+
list-style: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.wu-breadcrumb-item {
|
|
52
|
+
display: inline-flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
gap: woven.token(space-2);
|
|
55
|
+
min-width: 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Separator: a chevron drawn with two borders, mirrored in RTL
|
|
59
|
+
.wu-breadcrumb-item + .wu-breadcrumb-item::before {
|
|
60
|
+
content: "";
|
|
61
|
+
flex: none;
|
|
62
|
+
width: 0.4em;
|
|
63
|
+
height: 0.4em;
|
|
64
|
+
border-block-start: woven.token(border-width-1) solid currentcolor;
|
|
65
|
+
border-inline-end: woven.token(border-width-1) solid currentcolor;
|
|
66
|
+
color: woven.token(text-subtle);
|
|
67
|
+
rotate: 45deg;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.wu-breadcrumb-item + .wu-breadcrumb-item:dir(rtl)::before {
|
|
71
|
+
rotate: -45deg;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.wu-breadcrumb.slash .wu-breadcrumb-item + .wu-breadcrumb-item::before {
|
|
75
|
+
content: "/";
|
|
76
|
+
content: "/" / "";
|
|
77
|
+
width: auto;
|
|
78
|
+
height: auto;
|
|
79
|
+
border: 0;
|
|
80
|
+
rotate: none;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.wu-breadcrumb.slash .wu-breadcrumb-item + .wu-breadcrumb-item:dir(rtl)::before {
|
|
84
|
+
rotate: none;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Underlined at rest so links read as links; the current page is plain text
|
|
88
|
+
.wu-breadcrumb-link {
|
|
89
|
+
border-radius: woven.token(radius-xs);
|
|
90
|
+
color: inherit;
|
|
91
|
+
text-decoration: underline;
|
|
92
|
+
text-decoration-color: woven.token(border-strong);
|
|
93
|
+
text-decoration-thickness: woven.token(border-width-1);
|
|
94
|
+
text-underline-offset: 0.2em;
|
|
95
|
+
|
|
96
|
+
&:hover {
|
|
97
|
+
color: woven.token(text-regular);
|
|
98
|
+
text-decoration-color: currentcolor;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&:focus-visible {
|
|
102
|
+
outline: woven.token(border-focus-width) solid woven.token(border-focus);
|
|
103
|
+
outline-offset: woven.token(border-focus-offset);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.wu-breadcrumb-item [aria-current="page"] {
|
|
108
|
+
color: woven.token(text-regular);
|
|
109
|
+
font-weight: woven.token(font-weight-medium);
|
|
110
|
+
text-decoration: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.wu-breadcrumb.sm {
|
|
114
|
+
font-size: woven.token(font-size-xs);
|
|
115
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// @component wu-btn-group
|
|
3
|
+
//// Joins buttons into one segmented control, as a split button, a toggle set or a radio set.
|
|
4
|
+
////
|
|
5
|
+
//// Split divider: use `brand`, `danger` or `quiet` on both buttons of a pair. Checkable: use `role="group"` with checkboxes or `role="radiogroup"` with radios.
|
|
6
|
+
////
|
|
7
|
+
//// The checked label takes the `aria-pressed` look; arrow keys are native for radios. `animated` on a button gives it the press from `wu-btn`.
|
|
8
|
+
////
|
|
9
|
+
//// @since 1.0.0
|
|
10
|
+
//// @needs button
|
|
11
|
+
//// @js none
|
|
12
|
+
//// @example html
|
|
13
|
+
//// <div class="wu-btn-group">
|
|
14
|
+
//// <button class="wu-btn brand" type="button">Save</button>
|
|
15
|
+
//// <button class="wu-btn brand caret" type="button" popovertarget="more-save" aria-label="More save options"></button>
|
|
16
|
+
//// </div>
|
|
17
|
+
//// <div id="more-save" popover>Save as draft</div>
|
|
18
|
+
//// @example html
|
|
19
|
+
//// <div class="wu-btn-group" role="radiogroup" aria-label="Align">
|
|
20
|
+
//// <label class="wu-btn"><input type="radio" name="align" class="sr-only" checked> Left</label>
|
|
21
|
+
//// <label class="wu-btn"><input type="radio" name="align" class="sr-only"> Right</label>
|
|
22
|
+
//// </div>
|
|
23
|
+
//// @example html
|
|
24
|
+
//// <div class="wu-btn-group vertical" role="group" aria-label="View">
|
|
25
|
+
//// <button class="wu-btn" type="button" aria-pressed="true">List</button>
|
|
26
|
+
//// <button class="wu-btn" type="button" aria-pressed="false">Grid</button>
|
|
27
|
+
//// </div>
|
|
28
|
+
//// @modifier vertical - Stacks the buttons in a column @since 1.0.0
|
|
29
|
+
//// @modifier brand | danger | quiet - On two neighbor buttons: a divider line between them, for split buttons @since 1.0.0
|
|
30
|
+
//// @state aria-pressed="true" - Toggle on: selected tint and an inner ring; a checked input inside the label does the same @since 1.0.0
|
|
31
|
+
////
|
|
32
|
+
|
|
33
|
+
@use "@wovenui/core/mixins" as woven;
|
|
34
|
+
|
|
35
|
+
.wu-btn-group {
|
|
36
|
+
display: inline-flex;
|
|
37
|
+
vertical-align: middle;
|
|
38
|
+
|
|
39
|
+
> .wu-btn {
|
|
40
|
+
position: relative;
|
|
41
|
+
border-radius: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
> .wu-btn:is(:hover, :focus-visible, [aria-pressed="true"], :has(> input:checked, > input:focus-visible)) {
|
|
45
|
+
z-index: woven.token(z-hover);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Toggle state: tint plus an inner ring, so color is not the only signal
|
|
49
|
+
> .wu-btn:is([aria-pressed="true"], :has(> input:checked)) {
|
|
50
|
+
background: woven.token(bg-selected);
|
|
51
|
+
box-shadow: inset 0 0 0 woven.token(border-width-1) woven.token(brand);
|
|
52
|
+
color: woven.token(text-brand);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
> .wu-btn:has(> input:focus-visible) {
|
|
56
|
+
outline: woven.token(border-focus-width) solid woven.token(border-focus);
|
|
57
|
+
outline-offset: woven.token(border-focus-offset);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
> .wu-btn:has(> input:disabled) {
|
|
61
|
+
opacity: woven.token(opacity-50);
|
|
62
|
+
pointer-events: none;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Split button divider
|
|
66
|
+
> .wu-btn.brand + .wu-btn.brand {
|
|
67
|
+
border-inline-start-color: color-mix(in srgb, woven.token(text-on-brand) 40%, transparent);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
> .wu-btn.danger + .wu-btn.danger {
|
|
71
|
+
border-inline-start-color: color-mix(in srgb, woven.token(text-on-danger) 40%, transparent);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
> .wu-btn.quiet + .wu-btn.quiet {
|
|
75
|
+
border-inline-start-color: woven.token(border-regular);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.wu-btn-group:not(.vertical) > .wu-btn {
|
|
80
|
+
&:first-child {
|
|
81
|
+
border-start-start-radius: woven.token(radius-md);
|
|
82
|
+
border-end-start-radius: woven.token(radius-md);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
&:nth-last-child(1 of .wu-btn) {
|
|
86
|
+
border-start-end-radius: woven.token(radius-md);
|
|
87
|
+
border-end-end-radius: woven.token(radius-md);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
& + .wu-btn {
|
|
91
|
+
margin-inline-start: calc(-1 * #{woven.token(border-width-1)});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.wu-btn-group.vertical {
|
|
96
|
+
flex-direction: column;
|
|
97
|
+
|
|
98
|
+
> .wu-btn:first-child {
|
|
99
|
+
border-start-start-radius: woven.token(radius-md);
|
|
100
|
+
border-start-end-radius: woven.token(radius-md);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
> .wu-btn:nth-last-child(1 of .wu-btn) {
|
|
104
|
+
border-end-start-radius: woven.token(radius-md);
|
|
105
|
+
border-end-end-radius: woven.token(radius-md);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
> .wu-btn + .wu-btn {
|
|
109
|
+
margin-block-start: calc(-1 * #{woven.token(border-width-1)});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Opt-in motion: animated gives each button the .wu-btn.animated press, set in _button.scss
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// @component wu-btn
|
|
3
|
+
//// Buttons for actions, in roles and sizes, with a caret for menus and split buttons.
|
|
4
|
+
////
|
|
5
|
+
//// A `button` element is the default; an `a` element with `wu-btn` looks the same for navigation.
|
|
6
|
+
////
|
|
7
|
+
//// Inside a `wu-field-group sm` or `lg`, a button without its own size takes the group size.
|
|
8
|
+
////
|
|
9
|
+
//// @since 1.0.0
|
|
10
|
+
//// @needs none
|
|
11
|
+
//// @js none
|
|
12
|
+
//// @example html
|
|
13
|
+
//// <button class="wu-btn" type="button">Cancel</button>
|
|
14
|
+
//// <button class="wu-btn brand" type="button">Save</button>
|
|
15
|
+
//// <button class="wu-btn danger subtle sm" type="button">Delete</button>
|
|
16
|
+
//// @example html
|
|
17
|
+
//// <button class="wu-btn icon round" type="button" aria-label="Settings">
|
|
18
|
+
//// <svg aria-hidden="true" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4" /></svg>
|
|
19
|
+
//// </button>
|
|
20
|
+
//// <button class="wu-btn brand" type="button" aria-busy="true">Saving</button>
|
|
21
|
+
//// @example html
|
|
22
|
+
//// <button class="wu-btn caret" type="button" popovertarget="actions">Actions</button>
|
|
23
|
+
//// <div id="actions" popover>Menu content</div>
|
|
24
|
+
//// @modifier brand - Solid brand fill for the main action @since 1.0.0
|
|
25
|
+
//// @modifier danger - Solid danger fill for destructive actions @since 1.0.0
|
|
26
|
+
//// @modifier subtle - With `brand` or `danger`: tinted fill and border, solid on hover @since 1.0.0
|
|
27
|
+
//// @modifier quiet - No border or fill until hover @since 1.0.0
|
|
28
|
+
//// @modifier link - Looks like a link, no padding, keeps the control height @since 1.0.0
|
|
29
|
+
//// @modifier round - Pill shape; a circle when the button is empty or holds only an svg @since 1.0.0
|
|
30
|
+
//// @modifier icon - Square button for one svg and no text; give it an `aria-label` @since 1.0.0
|
|
31
|
+
//// @modifier caret - Adds a caret after the label; an empty caret button with an `aria-label` is a narrow caret-only button for split buttons @since 1.0.0
|
|
32
|
+
//// @modifier sm | lg - Small or large control height and font size @since 1.0.0
|
|
33
|
+
//// @modifier animated - Spring press scale when the user allows motion; `wu-animated` on an ancestor or `wu-btn-group animated` does the same @since 1.0.0
|
|
34
|
+
//// @variable --wu-btn--CaretSize [0.4em] - Size of the caret @since 1.0.0
|
|
35
|
+
//// @state disabled | aria-disabled="true" - Half opacity, no pointer events @since 1.0.0
|
|
36
|
+
//// @state aria-busy="true" - Loading: blocks pointer clicks and keeps full opacity @since 1.0.0
|
|
37
|
+
//// @state :popover-open - The caret turns while the popover right after the button is open @since 1.0.0
|
|
38
|
+
////
|
|
39
|
+
|
|
40
|
+
@use "@wovenui/core/mixins" as woven;
|
|
41
|
+
|
|
42
|
+
.wu-btn {
|
|
43
|
+
display: inline-flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
gap: woven.token(space-2);
|
|
47
|
+
min-height: woven.token(control-height-md);
|
|
48
|
+
padding-inline: woven.token(control-padding-inline-md);
|
|
49
|
+
border: woven.token(border-width-1) solid woven.token(border-regular);
|
|
50
|
+
border-radius: woven.token(radius-md);
|
|
51
|
+
background: woven.token(bg-surface);
|
|
52
|
+
color: woven.token(text-regular);
|
|
53
|
+
font: inherit;
|
|
54
|
+
font-size: woven.token(font-size-sm);
|
|
55
|
+
font-weight: woven.token(font-weight-medium);
|
|
56
|
+
line-height: 1;
|
|
57
|
+
text-decoration: none;
|
|
58
|
+
white-space: nowrap;
|
|
59
|
+
cursor: pointer;
|
|
60
|
+
transition-property: background-color, border-color, color;
|
|
61
|
+
transition-duration: woven.token(duration-150);
|
|
62
|
+
transition-timing-function: woven.token(ease-out);
|
|
63
|
+
|
|
64
|
+
&:hover {
|
|
65
|
+
border-color: woven.token(border-strong);
|
|
66
|
+
background: woven.token(bg-hover);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
&:focus-visible {
|
|
70
|
+
outline: woven.token(border-focus-width) solid woven.token(border-focus);
|
|
71
|
+
outline-offset: woven.token(border-focus-offset);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
&:disabled,
|
|
75
|
+
&[aria-disabled="true"] {
|
|
76
|
+
opacity: woven.token(opacity-50);
|
|
77
|
+
pointer-events: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
&[aria-busy="true"] {
|
|
81
|
+
opacity: 1;
|
|
82
|
+
pointer-events: none;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.wu-btn.brand {
|
|
87
|
+
border-color: woven.token(brand);
|
|
88
|
+
background: woven.token(brand);
|
|
89
|
+
color: woven.token(text-on-brand);
|
|
90
|
+
|
|
91
|
+
&:hover {
|
|
92
|
+
border-color: woven.token(brand-hover);
|
|
93
|
+
background: woven.token(brand-hover);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
&:active {
|
|
97
|
+
border-color: woven.token(brand-active);
|
|
98
|
+
background: woven.token(brand-active);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.wu-btn.danger {
|
|
103
|
+
border-color: woven.token(danger);
|
|
104
|
+
background: woven.token(danger);
|
|
105
|
+
color: woven.token(text-on-danger);
|
|
106
|
+
|
|
107
|
+
&:hover {
|
|
108
|
+
border-color: woven.token(danger-hover);
|
|
109
|
+
background: woven.token(danger-hover);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
&:active {
|
|
113
|
+
border-color: woven.token(danger-active);
|
|
114
|
+
background: woven.token(danger-active);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Subtle: tinted role fill and border, solid on hover
|
|
119
|
+
.wu-btn.brand.subtle {
|
|
120
|
+
border-color: woven.token(brand-border);
|
|
121
|
+
background: woven.token(brand-subtle);
|
|
122
|
+
color: woven.token(text-brand);
|
|
123
|
+
|
|
124
|
+
&:hover {
|
|
125
|
+
border-color: woven.token(brand-hover);
|
|
126
|
+
background: woven.token(brand-hover);
|
|
127
|
+
color: woven.token(text-on-brand);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&:active {
|
|
131
|
+
border-color: woven.token(brand-active);
|
|
132
|
+
background: woven.token(brand-active);
|
|
133
|
+
color: woven.token(text-on-brand);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.wu-btn.danger.subtle {
|
|
138
|
+
border-color: woven.token(danger-border);
|
|
139
|
+
background: woven.token(danger-subtle);
|
|
140
|
+
color: woven.token(text-danger);
|
|
141
|
+
|
|
142
|
+
&:hover {
|
|
143
|
+
border-color: woven.token(danger-hover);
|
|
144
|
+
background: woven.token(danger-hover);
|
|
145
|
+
color: woven.token(text-on-danger);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
&:active {
|
|
149
|
+
border-color: woven.token(danger-active);
|
|
150
|
+
background: woven.token(danger-active);
|
|
151
|
+
color: woven.token(text-on-danger);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.wu-btn > svg {
|
|
156
|
+
flex-shrink: 0;
|
|
157
|
+
width: 1em;
|
|
158
|
+
height: 1em;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.wu-btn.quiet {
|
|
162
|
+
border-color: transparent;
|
|
163
|
+
background: transparent;
|
|
164
|
+
|
|
165
|
+
&:hover {
|
|
166
|
+
border-color: transparent;
|
|
167
|
+
background: woven.token(bg-hover);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.wu-btn.sm {
|
|
172
|
+
min-height: woven.token(control-height-sm);
|
|
173
|
+
padding-inline: woven.token(control-padding-inline-sm);
|
|
174
|
+
font-size: woven.token(font-size-xs);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.wu-btn.lg {
|
|
178
|
+
min-height: woven.token(control-height-lg);
|
|
179
|
+
padding-inline: woven.token(control-padding-inline-lg);
|
|
180
|
+
font-size: woven.token(font-size-md);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.wu-btn.caret::after {
|
|
184
|
+
content: "";
|
|
185
|
+
inline-size: var(--wu-btn--CaretSize, 0.4em);
|
|
186
|
+
block-size: var(--wu-btn--CaretSize, 0.4em);
|
|
187
|
+
margin-block-start: -0.2em;
|
|
188
|
+
border-bottom: 0.125em solid currentcolor;
|
|
189
|
+
border-right: 0.125em solid currentcolor;
|
|
190
|
+
rotate: 45deg;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Link: text only, no padding; keeps the control height so it lines up in a toolbar row
|
|
194
|
+
.wu-btn.link {
|
|
195
|
+
padding-inline: 0;
|
|
196
|
+
border-color: transparent;
|
|
197
|
+
background: transparent;
|
|
198
|
+
color: woven.token(text-link);
|
|
199
|
+
|
|
200
|
+
&:hover {
|
|
201
|
+
border-color: transparent;
|
|
202
|
+
background: transparent;
|
|
203
|
+
color: woven.token(text-link-hover);
|
|
204
|
+
text-decoration: underline;
|
|
205
|
+
text-underline-offset: 0.2em;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Icon: square box for one svg and no text; round makes it a circle
|
|
210
|
+
.wu-btn.icon {
|
|
211
|
+
min-inline-size: woven.token(control-height-md);
|
|
212
|
+
padding: 0;
|
|
213
|
+
|
|
214
|
+
> svg {
|
|
215
|
+
width: 1.25em;
|
|
216
|
+
height: 1.25em;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.wu-btn.icon.sm {
|
|
221
|
+
min-inline-size: woven.token(control-height-sm);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.wu-btn.icon.lg {
|
|
225
|
+
min-inline-size: woven.token(control-height-lg);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Round: pill; a circle when empty or holding only an svg
|
|
229
|
+
.wu-btn.round {
|
|
230
|
+
border-radius: woven.token(radius-full);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.wu-btn.round:empty,
|
|
234
|
+
.wu-btn.round:has(> svg:only-child) {
|
|
235
|
+
min-inline-size: woven.token(control-height-md);
|
|
236
|
+
padding-inline: 0;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.wu-btn.round.sm:empty,
|
|
240
|
+
.wu-btn.round.sm:has(> svg:only-child) {
|
|
241
|
+
min-inline-size: woven.token(control-height-sm);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.wu-btn.round.lg:empty,
|
|
245
|
+
.wu-btn.round.lg:has(> svg:only-child) {
|
|
246
|
+
min-inline-size: woven.token(control-height-lg);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Caret-only: square, matched to the control height of each size
|
|
250
|
+
.wu-btn.caret:empty {
|
|
251
|
+
min-inline-size: woven.token(control-height-md);
|
|
252
|
+
padding-inline: 0;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.wu-btn.caret.sm:empty {
|
|
256
|
+
min-inline-size: woven.token(control-height-sm);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.wu-btn.caret.lg:empty {
|
|
260
|
+
min-inline-size: woven.token(control-height-lg);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.wu-btn.caret:has(+ [popover]:popover-open)::after {
|
|
264
|
+
margin-block-start: 0.2em;
|
|
265
|
+
rotate: 225deg;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Size from a wu-field-group sm or lg; a button with its own sm or lg keeps it
|
|
269
|
+
@each $size, $font in ("sm": "font-size-xs", "lg": "font-size-md") {
|
|
270
|
+
$h: woven.token(control-height-#{$size});
|
|
271
|
+
|
|
272
|
+
:where(.wu-field-group.#{$size}) {
|
|
273
|
+
.wu-btn:not(.sm, .lg) {
|
|
274
|
+
min-height: $h;
|
|
275
|
+
font-size: woven.token(#{$font});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.wu-btn:not(.sm, .lg, .icon, .link, .caret:empty, .round:empty, .round:has(> svg:only-child)) {
|
|
279
|
+
padding-inline: woven.token(control-padding-inline-#{$size});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.wu-btn:not(.sm, .lg):is(.icon, .caret:empty, .round:empty, .round:has(> svg:only-child)) {
|
|
283
|
+
min-inline-size: $h;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Opt-in motion: spring press scale, also for every button of an animated group
|
|
289
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
290
|
+
.wu-btn.animated,
|
|
291
|
+
.wu-btn-group.animated > .wu-btn,
|
|
292
|
+
.wu-animated .wu-btn {
|
|
293
|
+
transition-property: background-color, border-color, color, scale;
|
|
294
|
+
transition-duration: woven.token(duration-150), woven.token(duration-150), woven.token(duration-150), woven.token(duration-500);
|
|
295
|
+
transition-timing-function: woven.token(ease-out), woven.token(ease-out), woven.token(ease-out), var(--wu-kit-ease-spring);
|
|
296
|
+
|
|
297
|
+
&:active {
|
|
298
|
+
scale: 0.95;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// @component wu-card
|
|
3
|
+
//// Bordered surface that groups a header, a body and a footer.
|
|
4
|
+
////
|
|
5
|
+
//// Put one real link, usually in the title, on `wu-card-link` to make the whole card clickable. Other controls stay clickable above it.
|
|
6
|
+
////
|
|
7
|
+
//// @since 1.0.0
|
|
8
|
+
//// @needs none
|
|
9
|
+
//// @js none
|
|
10
|
+
//// @example html
|
|
11
|
+
//// <div class="wu-card">
|
|
12
|
+
//// <div class="wu-card-header"><h3 class="wu-card-title">Plan</h3></div>
|
|
13
|
+
//// <div class="wu-card-body">Everything you need to start.</div>
|
|
14
|
+
//// <div class="wu-card-footer"><button class="wu-btn brand" type="button">Choose</button></div>
|
|
15
|
+
//// </div>
|
|
16
|
+
//// @example html
|
|
17
|
+
//// <div class="wu-card">
|
|
18
|
+
//// <div class="wu-card-body">
|
|
19
|
+
//// <h3 class="wu-card-title"><a class="wu-card-link" href="/docs/">Read the docs</a></h3>
|
|
20
|
+
//// <p>Guides for every component.</p>
|
|
21
|
+
//// </div>
|
|
22
|
+
//// </div>
|
|
23
|
+
//// @part wu-card-header - Top row for a title and actions, with a bottom border @since 1.0.0
|
|
24
|
+
//// @part wu-card-title - Heading inside the header or body @since 1.0.0
|
|
25
|
+
//// @part wu-card-body - Main content; it grows so footers line up across a row of cards @since 1.0.0
|
|
26
|
+
//// @part wu-card-footer - Bottom row for actions, aligned to the end, with a top border @since 1.0.0
|
|
27
|
+
//// @part wu-card-link - Link stretched over the whole card @since 1.0.0
|
|
28
|
+
//// @variable --wu-card--Padding [var(--wu-space-5)] - Padding of the header, body and footer @since 1.0.0
|
|
29
|
+
////
|
|
30
|
+
|
|
31
|
+
@use "@wovenui/core/mixins" as woven;
|
|
32
|
+
|
|
33
|
+
.wu-card {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
position: relative;
|
|
37
|
+
border: woven.token(border-width-1) solid woven.token(border-regular);
|
|
38
|
+
border-radius: woven.token(radius-lg);
|
|
39
|
+
background: woven.token(bg-surface);
|
|
40
|
+
color: woven.token(text-regular);
|
|
41
|
+
box-shadow: woven.token(shadow-sm);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.wu-card-header,
|
|
45
|
+
.wu-card-body,
|
|
46
|
+
.wu-card-footer {
|
|
47
|
+
padding: var(--wu-card--Padding, #{woven.token(space-5)});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.wu-card-header {
|
|
51
|
+
display: flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
justify-content: space-between;
|
|
54
|
+
gap: woven.token(space-3);
|
|
55
|
+
border-block-end: woven.token(border-width-1) solid woven.token(border-regular);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.wu-card-title {
|
|
59
|
+
margin: 0;
|
|
60
|
+
font-size: woven.token(font-size-md);
|
|
61
|
+
font-weight: woven.token(font-weight-semibold);
|
|
62
|
+
line-height: woven.token(line-height-tight);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Grows so footers line up across a row of cards
|
|
66
|
+
.wu-card-body {
|
|
67
|
+
flex-grow: 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.wu-card-footer {
|
|
71
|
+
display: flex;
|
|
72
|
+
flex-wrap: wrap;
|
|
73
|
+
align-items: center;
|
|
74
|
+
justify-content: flex-end;
|
|
75
|
+
gap: woven.token(space-2);
|
|
76
|
+
border-block-start: woven.token(border-width-1) solid woven.token(border-regular);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Whole-card link: one real link (usually in the title) stretched over the card
|
|
80
|
+
.wu-card-link {
|
|
81
|
+
color: inherit;
|
|
82
|
+
text-decoration: none;
|
|
83
|
+
|
|
84
|
+
&::after {
|
|
85
|
+
content: "";
|
|
86
|
+
position: absolute;
|
|
87
|
+
inset: 0;
|
|
88
|
+
border-radius: inherit;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&:focus-visible {
|
|
92
|
+
outline: none;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
&:focus-visible::after {
|
|
96
|
+
outline: woven.token(border-focus-width) solid woven.token(border-focus);
|
|
97
|
+
outline-offset: woven.token(border-focus-offset);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.wu-card:has(.wu-card-link) {
|
|
102
|
+
transition-property: border-color, box-shadow;
|
|
103
|
+
transition-duration: woven.token(duration-150);
|
|
104
|
+
transition-timing-function: woven.token(ease-out);
|
|
105
|
+
|
|
106
|
+
// Other controls stay clickable above the stretched link
|
|
107
|
+
:is(a, button, input, select, textarea, summary, label):not(.wu-card-link) {
|
|
108
|
+
position: relative;
|
|
109
|
+
z-index: woven.token(z-hover);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.wu-card:has(.wu-card-link:hover) {
|
|
114
|
+
border-color: woven.token(border-strong);
|
|
115
|
+
box-shadow: woven.token(shadow-md);
|
|
116
|
+
|
|
117
|
+
.wu-card-link {
|
|
118
|
+
text-decoration: underline;
|
|
119
|
+
}
|
|
120
|
+
}
|