@stackoverflow/stacks 1.6.6 → 1.7.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/README.md +86 -2
- package/dist/controllers/index.d.ts +2 -0
- package/dist/controllers/s-banner.d.ts +41 -0
- package/dist/controllers/s-toast.d.ts +97 -0
- package/dist/css/stacks.css +18884 -18912
- package/dist/css/stacks.min.css +1 -1
- package/dist/js/stacks.js +5252 -5260
- package/dist/js/stacks.min.js +1 -1
- package/dist/stacks.d.ts +1 -1
- package/lib/css/components/anchors.less +61 -0
- package/lib/css/components/block-link.less +80 -0
- package/lib/css/components/buttons.less +20 -4
- package/lib/css/components/expandable.less +1 -1
- package/lib/css/components/inputs.less +4 -0
- package/lib/css/components/link.less +104 -0
- package/lib/css/components/post-summary.less +327 -356
- package/lib/css/components/table.less +297 -0
- package/lib/css/stacks-dynamic.less +0 -8
- package/lib/css/stacks-static.less +9 -1
- package/lib/test/s-banner.test.ts +73 -0
- package/lib/test/s-banner.visual.test.ts +61 -0
- package/lib/test/s-button.visual.test.ts +12 -0
- package/lib/test/s-toast.test.ts +63 -0
- package/lib/test/s-toast.visual.test.ts +48 -0
- package/lib/test/s-tooltip.test.ts +62 -0
- package/lib/test/s-tooltip.visual.test.ts +31 -0
- package/lib/ts/controllers/index.ts +2 -0
- package/lib/ts/controllers/s-banner.ts +149 -0
- package/lib/ts/controllers/s-toast.ts +357 -0
- package/lib/ts/index.ts +4 -0
- package/lib/ts/stacks.ts +1 -1
- package/lib/tsconfig.json +2 -2
- package/package.json +35 -19
- package/lib/css/components/links.less +0 -214
- package/lib/css/components/tables.less +0 -313
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
.s-table-container {
|
|
2
|
+
overflow-x: auto;
|
|
3
|
+
@scrollbar-styles();
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.s-table {
|
|
7
|
+
@ta-cell-border: var(--su-static1) solid var(--bc-medium);
|
|
8
|
+
@ta-columns: (100% / 12);
|
|
9
|
+
|
|
10
|
+
--_ta-tbody-tbody-bc: var(--bc-medium);
|
|
11
|
+
--_ta-tbody-tbody-bw: var(--su-static2);
|
|
12
|
+
--_ta-tbody-tr-even-bg: unset;
|
|
13
|
+
--_ta-td-bbw: 0;
|
|
14
|
+
--_ta-td-bc: var(--bc-medium);
|
|
15
|
+
--_ta-td-fs: unset;
|
|
16
|
+
--_ta-td-fw: unset;
|
|
17
|
+
--_ta-td-p: var(--su8);
|
|
18
|
+
--_ta-td-ta: left;
|
|
19
|
+
--_ta-td-va: middle;
|
|
20
|
+
--_ta-td-w: unset;
|
|
21
|
+
--_ta-thead-th-bg: var(--black-025);
|
|
22
|
+
--_ta-th-bbw: 0;
|
|
23
|
+
--_ta-th-bc: var(--bc-medium);
|
|
24
|
+
--_ta-th-fs: unset;
|
|
25
|
+
--_ta-th-p: var(--su8);
|
|
26
|
+
--_ta-th-ta: left;
|
|
27
|
+
--_ta-th-va: middle;
|
|
28
|
+
--_ta-th-w: unset;
|
|
29
|
+
|
|
30
|
+
// VARIANTS
|
|
31
|
+
&&__stripes {
|
|
32
|
+
--_ta-tbody-tr-even-bg: var(--black-025);
|
|
33
|
+
--_ta-thead-th-bg: var(--black-050);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// MODIFIERS
|
|
37
|
+
&.ta-center {
|
|
38
|
+
--_ta-td-ta: center;
|
|
39
|
+
--_ta-th-ta: center;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&.ta-left {
|
|
43
|
+
--_ta-td-ta: left;
|
|
44
|
+
--_ta-th-ta: left;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&.ta-justify {
|
|
48
|
+
--_ta-td-ta: justify;
|
|
49
|
+
--_ta-th-ta: justify;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&.ta-right {
|
|
53
|
+
--_ta-td-ta: right;
|
|
54
|
+
--_ta-th-ta: right;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&.va-bottom {
|
|
58
|
+
--_ta-td-va: bottom;
|
|
59
|
+
--_ta-th-va: bottom;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
&.va-middle {
|
|
63
|
+
--_ta-td-va: middle;
|
|
64
|
+
--_ta-th-va: middle;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&.va-top {
|
|
68
|
+
--_ta-td-va: top;
|
|
69
|
+
--_ta-th-va: top;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
&&__b0 {
|
|
73
|
+
--_ta-td-bc: transparent;
|
|
74
|
+
--_ta-th-bc: transparent;
|
|
75
|
+
--_ta-tbody-tbody-bc: transparent; // [1]
|
|
76
|
+
--_ta-tbody-tbody-bw: var(--su-static12); // [1]
|
|
77
|
+
--_ta-thead-th-bg: transparent;
|
|
78
|
+
|
|
79
|
+
thead th {
|
|
80
|
+
font-size: inherit;
|
|
81
|
+
text-transform: initial;
|
|
82
|
+
letter-spacing: initial;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&&__bx {
|
|
87
|
+
tr {
|
|
88
|
+
> *:not(:first-child) {
|
|
89
|
+
border-left-color: transparent;
|
|
90
|
+
}
|
|
91
|
+
> *:not(:last-child) {
|
|
92
|
+
border-right-color: transparent;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
&&__bx-simple {
|
|
98
|
+
--_ta-thead-th-bg: transparent;
|
|
99
|
+
--_ta-foot-td-bc: transparent;
|
|
100
|
+
--_ta-foot-th-bc: transparent;
|
|
101
|
+
|
|
102
|
+
td,
|
|
103
|
+
th {
|
|
104
|
+
border-left-color: transparent;
|
|
105
|
+
border-right-color: transparent;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
tbody tr {
|
|
109
|
+
&:first-of-type th,
|
|
110
|
+
&:first-of-type td {
|
|
111
|
+
border-top-color: transparent;
|
|
112
|
+
}
|
|
113
|
+
&:last-of-type th,
|
|
114
|
+
&:last-of-type td {
|
|
115
|
+
border-bottom-color: transparent;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
thead th {
|
|
120
|
+
border-top-color: transparent;
|
|
121
|
+
border-bottom-color: var(--bc-darker);
|
|
122
|
+
font-size: inherit;
|
|
123
|
+
text-transform: initial;
|
|
124
|
+
letter-spacing: initial;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
&&__sortable {
|
|
129
|
+
thead th {
|
|
130
|
+
a { // If an anchor is used, it should appear like a normal header
|
|
131
|
+
color: inherit;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&.is-sorted { // Selected state
|
|
135
|
+
color: var(--black-900);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
color: var(--fc-light);
|
|
139
|
+
cursor: pointer;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Sizes
|
|
144
|
+
&&__sm {
|
|
145
|
+
--_ta-td-p: var(--su4);
|
|
146
|
+
--_ta-th-p: var(--su4);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
&&__lg {
|
|
150
|
+
--_ta-td-p: var(--su12);
|
|
151
|
+
--_ta-th-p: var(--su12);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// CHILD ELEMENTS
|
|
155
|
+
& &--cell {
|
|
156
|
+
.generate-cell-widths-classes(@n, @i: 1) when (@i =< @n) {
|
|
157
|
+
&@{i} { // generates iterated cell classes
|
|
158
|
+
@ta-cell-w: @ta-columns * @i;
|
|
159
|
+
--_ta-td-w: @ta-cell-w;
|
|
160
|
+
--_ta-th-w: @ta-cell-w;
|
|
161
|
+
}
|
|
162
|
+
.generate-cell-widths-classes(@n, (@i + 1));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.generate-cell-widths-classes(12);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
& &--totals {
|
|
169
|
+
--_ta-td-fs: var(--fs-subheading);
|
|
170
|
+
--_ta-td-pt: var(--su12);
|
|
171
|
+
--_ta-td-fw: bold;
|
|
172
|
+
--_ta-th-fs: var(--fs-subheading);
|
|
173
|
+
--_ta-th-pt: var(--su12);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
tbody {
|
|
177
|
+
+ tbody { // If two table bodies are next to each other, visually separate them
|
|
178
|
+
border-top: var(--_ta-tbody-tbody-bw) solid var(--_ta-tbody-tbody-bc);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
th {
|
|
182
|
+
font-weight: normal;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
tr {
|
|
186
|
+
&:nth-child(2n) {
|
|
187
|
+
background-color: var(--_ta-tbody-tr-even-bg);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
td {
|
|
193
|
+
.s-checkbox {
|
|
194
|
+
display: block;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
&.s-table--bulk {
|
|
198
|
+
--_ta-td-w: calc(var(--su32) - var(--su2)); // 30px;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
&.s-table--progress {
|
|
202
|
+
--_ta-td-ta: right;
|
|
203
|
+
--_ta-td-brw: 0;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
&.s-table--progress-bar {
|
|
207
|
+
--_ta-td-blw: 0;
|
|
208
|
+
--_ta-td-pl: 0;
|
|
209
|
+
--_ta-td-w: 120px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
border: var(--su-static1) solid var(--_ta-td-bc);
|
|
213
|
+
border-bottom-width: var(--_ta-td-bbw, var(--su-static1));
|
|
214
|
+
border-left-width: var(--_ta-td-blw, var(--su-static1));
|
|
215
|
+
border-right-width: var(--_ta-td-brw, var(--su-static1));
|
|
216
|
+
border-top-width: var(--_ta-td-btw, var(--su-static1));
|
|
217
|
+
font-size: var(--_ta-td-fs);
|
|
218
|
+
font-weight: var(--_ta-td-fw);
|
|
219
|
+
padding: var(--_ta-td-p);
|
|
220
|
+
padding-left: var(--_ta-td-pl, var(--_ta-td-p));
|
|
221
|
+
padding-top: var(--_ta-td-pt, var(--_ta-td-p));
|
|
222
|
+
text-align: var(--_ta-td-ta);
|
|
223
|
+
vertical-align: var(--_ta-td-va);
|
|
224
|
+
width: var(--_ta-td-w);
|
|
225
|
+
|
|
226
|
+
color: var(--fc-medium);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
tfoot {
|
|
230
|
+
td {
|
|
231
|
+
border-bottom-color: var(--_ta-foot-td-bc, var(--_ta-td-bc));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
th {
|
|
235
|
+
border-bottom-color: var(--_ta-foot-th-bc, var(--_ta-td-bc));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
th {
|
|
240
|
+
.s-checkbox {
|
|
241
|
+
display: block;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
&.s-table--bulk {
|
|
245
|
+
--_ta-th-w: calc(var(--su32) - var(--su2)); // 30px;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
border: var(--su-static1) solid var(--_ta-th-bc);
|
|
249
|
+
border-width: var(--su-static1) var(--su-static1) var(--_ta-th-bbw);
|
|
250
|
+
font-size: var(--_ta-th-fs);
|
|
251
|
+
padding: var(--_ta-th-p);
|
|
252
|
+
padding-top: var(--_ta-th-pt, var(--_ta-th-p));
|
|
253
|
+
text-align: var(--_ta-th-ta);
|
|
254
|
+
vertical-align: var(--_ta-th-va);
|
|
255
|
+
width: var(--_ta-th-w);
|
|
256
|
+
|
|
257
|
+
color: var(--fc-dark);
|
|
258
|
+
font-weight: bold;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
thead {
|
|
262
|
+
th {
|
|
263
|
+
background-color: var(--_ta-thead-th-bg);
|
|
264
|
+
|
|
265
|
+
line-height: var(--lh-sm);
|
|
266
|
+
vertical-align: bottom;
|
|
267
|
+
white-space: nowrap;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
tr {
|
|
272
|
+
&:last-of-type {
|
|
273
|
+
--_ta-td-bbw: var(--su-static1);
|
|
274
|
+
--_ta-th-bbw: var(--su-static1);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
&.is-disabled {
|
|
278
|
+
background-color: var(--black-025);
|
|
279
|
+
--_ta-tbody-tr-even-bg: var(--black-025);
|
|
280
|
+
|
|
281
|
+
th:not(.is-enabled),
|
|
282
|
+
td:not(.is-enabled) {
|
|
283
|
+
opacity: calc(var(--_o-disabled) * 0.6); // 0.5 * 0.6 = 0.3
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
border-collapse: collapse;
|
|
289
|
+
border-spacing: 0;
|
|
290
|
+
display: table;
|
|
291
|
+
font-size: var(--fs-body1);
|
|
292
|
+
max-width: 100%;
|
|
293
|
+
width: 100%;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// [1] This makes the border transparent, so we need to use whitespace
|
|
297
|
+
// to achieve the same effect a 2px gray border achieves.
|
|
@@ -17,14 +17,6 @@
|
|
|
17
17
|
// -- SET BASIC STYLES FOR BODY
|
|
18
18
|
@import "base/body.less";
|
|
19
19
|
|
|
20
|
-
// -- COMPONENTS
|
|
21
|
-
@import "components/buttons.less";
|
|
22
|
-
@import "components/links.less";
|
|
23
|
-
@import "components/link-previews.less";
|
|
24
|
-
@import "components/notices.less";
|
|
25
|
-
@import "components/tags.less";
|
|
26
|
-
@import "components/pagination.less";
|
|
27
|
-
|
|
28
20
|
// -- LESS CONSTANTS AND MIXINS
|
|
29
21
|
@import "exports/exports.less";
|
|
30
22
|
|
|
@@ -18,10 +18,13 @@
|
|
|
18
18
|
|
|
19
19
|
// -- COMPONENTS
|
|
20
20
|
@import "components/activity-indicator.less";
|
|
21
|
+
@import "components/anchors.less";
|
|
21
22
|
@import "components/award-bling.less";
|
|
22
23
|
@import "components/avatars.less";
|
|
23
24
|
@import "components/badges.less";
|
|
25
|
+
@import "components/buttons.less";
|
|
24
26
|
@import "components/empty-states.less";
|
|
27
|
+
@import "components/block-link.less";
|
|
25
28
|
@import "components/breadcrumbs.less";
|
|
26
29
|
@import "components/button-groups.less";
|
|
27
30
|
@import "components/cards.less";
|
|
@@ -29,17 +32,22 @@
|
|
|
29
32
|
@import "components/expandable.less";
|
|
30
33
|
@import "components/inputs.less";
|
|
31
34
|
@import "components/labels.less";
|
|
35
|
+
@import "components/link.less";
|
|
36
|
+
@import "components/link-previews.less";
|
|
32
37
|
@import "components/menu.less";
|
|
33
38
|
@import "components/modals.less";
|
|
34
39
|
@import "components/navigation.less";
|
|
40
|
+
@import "components/notices.less";
|
|
35
41
|
@import "components/page-titles.less";
|
|
42
|
+
@import "components/pagination.less";
|
|
36
43
|
@import "components/popovers.less";
|
|
37
44
|
@import "components/post-summary.less";
|
|
38
45
|
@import "components/progress-bars.less";
|
|
39
46
|
@import "components/prose.less";
|
|
40
47
|
@import "components/sidebar-widgets.less";
|
|
41
48
|
@import "components/spinner.less";
|
|
42
|
-
@import "components/
|
|
49
|
+
@import "components/table.less";
|
|
50
|
+
@import "components/tags.less";
|
|
43
51
|
@import "components/toggle-switches.less";
|
|
44
52
|
@import "components/topbar.less";
|
|
45
53
|
@import "components/uploader.less";
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { html, fixture, expect } from "@open-wc/testing";
|
|
2
|
+
import { screen } from "@testing-library/dom";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import "../ts/index";
|
|
5
|
+
import { showBanner, hideBanner } from "../ts/index";
|
|
6
|
+
|
|
7
|
+
const user = userEvent.setup();
|
|
8
|
+
|
|
9
|
+
describe("s-banner", () => {
|
|
10
|
+
it("trigger should make banner visible", async () => {
|
|
11
|
+
await fixture(html`
|
|
12
|
+
<button data-toggle="s-banner" data-target="#test-banner">
|
|
13
|
+
Show test banner
|
|
14
|
+
</button>
|
|
15
|
+
<aside
|
|
16
|
+
role="alert"
|
|
17
|
+
id="test-banner"
|
|
18
|
+
class="s-banner"
|
|
19
|
+
aria-labelledby="banner-message"
|
|
20
|
+
aria-hidden="true"
|
|
21
|
+
data-controller="s-banner"
|
|
22
|
+
data-s-banner-target="banner"
|
|
23
|
+
data-testid="test-banner"
|
|
24
|
+
>
|
|
25
|
+
Test banner
|
|
26
|
+
</aside>
|
|
27
|
+
`);
|
|
28
|
+
|
|
29
|
+
const button = screen.getByRole("button");
|
|
30
|
+
const banner = screen.getByTestId("test-banner");
|
|
31
|
+
|
|
32
|
+
expect(banner).to.have.attribute("aria-hidden", "true");
|
|
33
|
+
button.addEventListener("click", () => showBanner(banner));
|
|
34
|
+
|
|
35
|
+
await user.click(button);
|
|
36
|
+
expect(banner).to.have.attribute("aria-hidden", "false");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("trigger should hide banner", async () => {
|
|
40
|
+
await fixture(html`
|
|
41
|
+
<aside
|
|
42
|
+
role="alert"
|
|
43
|
+
id="test-banner"
|
|
44
|
+
class="s-banner"
|
|
45
|
+
aria-labelledby="banner-message"
|
|
46
|
+
aria-hidden="false"
|
|
47
|
+
data-controller="s-banner"
|
|
48
|
+
data-s-banner-target="banner"
|
|
49
|
+
data-testid="test-banner"
|
|
50
|
+
>
|
|
51
|
+
Test banner
|
|
52
|
+
<button
|
|
53
|
+
type="button"
|
|
54
|
+
class="s-btn s-banner--btn"
|
|
55
|
+
aria-label="Dismiss"
|
|
56
|
+
data-toggle="s-banner"
|
|
57
|
+
data-target="#test-banner"
|
|
58
|
+
>
|
|
59
|
+
Close banner
|
|
60
|
+
</button>
|
|
61
|
+
</aside>
|
|
62
|
+
`);
|
|
63
|
+
|
|
64
|
+
const button = screen.getByRole("button");
|
|
65
|
+
const banner = screen.getByTestId("test-banner");
|
|
66
|
+
|
|
67
|
+
expect(banner).to.have.attribute("aria-hidden", "false");
|
|
68
|
+
button.addEventListener("click", () => hideBanner(banner));
|
|
69
|
+
|
|
70
|
+
await user.click(button);
|
|
71
|
+
expect(banner).to.have.attribute("aria-hidden", "true");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { html, fixture } from "@open-wc/testing";
|
|
2
|
+
import { visualDiff } from "@web/test-runner-visual-regression";
|
|
3
|
+
import "../ts/index";
|
|
4
|
+
|
|
5
|
+
const testBanner = (variant = "info", important = false) => {
|
|
6
|
+
const importantClass = important ? "s-banner__important" : "";
|
|
7
|
+
|
|
8
|
+
return html`<aside
|
|
9
|
+
class="s-banner s-banner__${variant} ${importantClass} is-pinned ps-relatives"
|
|
10
|
+
role="alert"
|
|
11
|
+
aria-hidden="false"
|
|
12
|
+
>
|
|
13
|
+
<div
|
|
14
|
+
class="d-flex flex__center jc-space-between s-banner--container"
|
|
15
|
+
role="alertdialog"
|
|
16
|
+
aria-describedby="banner-message"
|
|
17
|
+
>
|
|
18
|
+
<div aria-label="banner message">
|
|
19
|
+
Test Banner: ${variant} ${importantClass}
|
|
20
|
+
</div>
|
|
21
|
+
<div class="ml-auto myn8">
|
|
22
|
+
<span class="s-btn s-banner--btn">Close</span>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</aside>`;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
describe("s-banner", () => {
|
|
29
|
+
it("should not introduce visual regressions for info banner", async () => {
|
|
30
|
+
const banner = await fixture(testBanner("info"));
|
|
31
|
+
await visualDiff(banner, "s-banner__info");
|
|
32
|
+
});
|
|
33
|
+
it("should not introduce visual regressions for important info banner", async () => {
|
|
34
|
+
const banner = await fixture(testBanner("info", true));
|
|
35
|
+
await visualDiff(banner, "s-banner__info-important");
|
|
36
|
+
});
|
|
37
|
+
it("should not introduce visual regressions for success banner", async () => {
|
|
38
|
+
const banner = await fixture(testBanner("success"));
|
|
39
|
+
await visualDiff(banner, "s-banner__success");
|
|
40
|
+
});
|
|
41
|
+
it("should not introduce visual regressions for important success banner", async () => {
|
|
42
|
+
const banner = await fixture(testBanner("success", true));
|
|
43
|
+
await visualDiff(banner, "s-banner__success-important");
|
|
44
|
+
});
|
|
45
|
+
it("should not introduce visual regressions for warning banner", async () => {
|
|
46
|
+
const banner = await fixture(testBanner("warning"));
|
|
47
|
+
await visualDiff(banner, "s-banner__warning");
|
|
48
|
+
});
|
|
49
|
+
it("should not introduce visual regressions for important warning banner", async () => {
|
|
50
|
+
const banner = await fixture(testBanner("warning", true));
|
|
51
|
+
await visualDiff(banner, "s-banner__warning-important");
|
|
52
|
+
});
|
|
53
|
+
it("should not introduce visual regressions for danger banner", async () => {
|
|
54
|
+
const banner = await fixture(testBanner("danger"));
|
|
55
|
+
await visualDiff(banner, "s-banner__danger");
|
|
56
|
+
});
|
|
57
|
+
it("should not introduce visual regressions for important danger banner", async () => {
|
|
58
|
+
const banner = await fixture(testBanner("danger", true));
|
|
59
|
+
await visualDiff(banner, "s-banner__danger-important");
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { html, fixture } from "@open-wc/testing";
|
|
2
|
+
import { visualDiff } from "@web/test-runner-visual-regression";
|
|
3
|
+
import "../ts/index";
|
|
4
|
+
|
|
5
|
+
describe("s-btn", () => {
|
|
6
|
+
it("should not introduce visual regressions for loading button", async () => {
|
|
7
|
+
const btn = await fixture(html`
|
|
8
|
+
<button class="s-btn is-loading" type="button">Loading</button>
|
|
9
|
+
`);
|
|
10
|
+
await visualDiff(btn, "s-btn-is-loading");
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { html, fixture, expect } from "@open-wc/testing";
|
|
2
|
+
import { screen } from "@testing-library/dom";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import "../ts/index";
|
|
5
|
+
import { showToast, hideToast } from "../ts/index";
|
|
6
|
+
|
|
7
|
+
const user = userEvent.setup();
|
|
8
|
+
|
|
9
|
+
const testToast = (hidden = true) => html` <button
|
|
10
|
+
class="js-open-test-toast"
|
|
11
|
+
data-toggle="s-toast"
|
|
12
|
+
data-target="#test-toast"
|
|
13
|
+
>
|
|
14
|
+
Show test toast
|
|
15
|
+
</button>
|
|
16
|
+
<button type="button" aria-label="Dismiss">Close toast</button>
|
|
17
|
+
<div
|
|
18
|
+
role="alertdialog"
|
|
19
|
+
id="test-toast"
|
|
20
|
+
class="s-toast"
|
|
21
|
+
aria-hidden="${hidden}"
|
|
22
|
+
aria-labelledby="toast-message"
|
|
23
|
+
data-controller="s-toast"
|
|
24
|
+
data-s-toast-target="toast"
|
|
25
|
+
data-s-toast-return-element=".js-open-test-toast[data-target='#test-toast']"
|
|
26
|
+
data-testid="test-toast"
|
|
27
|
+
>
|
|
28
|
+
<aside class="s-notice s-notice__success">
|
|
29
|
+
<div id="notice-message">Test toast</div>
|
|
30
|
+
</aside>
|
|
31
|
+
</div>`;
|
|
32
|
+
|
|
33
|
+
describe("s-toast", () => {
|
|
34
|
+
it("trigger should make toast visible", async () => {
|
|
35
|
+
await fixture(testToast(true));
|
|
36
|
+
|
|
37
|
+
const button = screen.getAllByRole("button")[0]; // Trigger button
|
|
38
|
+
const toast = screen.getByTestId("test-toast");
|
|
39
|
+
|
|
40
|
+
expect(toast).to.have.attribute("aria-hidden", "true");
|
|
41
|
+
button.addEventListener("click", () => showToast(toast));
|
|
42
|
+
|
|
43
|
+
await user.click(button);
|
|
44
|
+
expect(toast).to.have.attribute("aria-hidden", "false");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("trigger should hide toast", async () => {
|
|
48
|
+
await fixture(testToast(false));
|
|
49
|
+
|
|
50
|
+
const button = screen.getAllByRole("button")[1]; // Close button
|
|
51
|
+
const toast = screen.getByTestId("test-toast");
|
|
52
|
+
|
|
53
|
+
expect(toast).to.have.attribute("aria-hidden", "false");
|
|
54
|
+
button.addEventListener("click", () => hideToast(toast));
|
|
55
|
+
|
|
56
|
+
await user.click(button);
|
|
57
|
+
expect(toast).to.have.attribute("aria-hidden", "true");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// TODO: add test for refocus trigger
|
|
61
|
+
|
|
62
|
+
// TODO: add test for removing toast from DOM
|
|
63
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { html, fixture } from "@open-wc/testing";
|
|
2
|
+
import { visualDiff } from "@web/test-runner-visual-regression";
|
|
3
|
+
import "../ts/index";
|
|
4
|
+
|
|
5
|
+
const testToast = (variant = "info", important = false) => {
|
|
6
|
+
const importantClass = important ? "s-notice__important" : "";
|
|
7
|
+
|
|
8
|
+
return html`<div class="s-toast" aria-hidden="false">
|
|
9
|
+
<aside class="s-notice s-notice__${variant} ${importantClass}">
|
|
10
|
+
Test toast: ${variant} ${importantClass}
|
|
11
|
+
</aside>
|
|
12
|
+
</div>`;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
describe("s-toast", () => {
|
|
16
|
+
it("should not introduce visual regressions for info toast", async () => {
|
|
17
|
+
const toast = await fixture(testToast("info"));
|
|
18
|
+
await visualDiff(toast, "s-toast__info");
|
|
19
|
+
});
|
|
20
|
+
it("should not introduce visual regressions for important info toast", async () => {
|
|
21
|
+
const toast = await fixture(testToast("info", true));
|
|
22
|
+
await visualDiff(toast, "s-toast__info-important");
|
|
23
|
+
});
|
|
24
|
+
it("should not introduce visual regressions for success toast", async () => {
|
|
25
|
+
const toast = await fixture(testToast("success"));
|
|
26
|
+
await visualDiff(toast, "s-toast__success");
|
|
27
|
+
});
|
|
28
|
+
it("should not introduce visual regressions for important success toast", async () => {
|
|
29
|
+
const toast = await fixture(testToast("success", true));
|
|
30
|
+
await visualDiff(toast, "s-toast__success-important");
|
|
31
|
+
});
|
|
32
|
+
it("should not introduce visual regressions for warning toast", async () => {
|
|
33
|
+
const toast = await fixture(testToast("warning"));
|
|
34
|
+
await visualDiff(toast, "s-toast__warning");
|
|
35
|
+
});
|
|
36
|
+
it("should not introduce visual regressions for important warning toast", async () => {
|
|
37
|
+
const toast = await fixture(testToast("warning", true));
|
|
38
|
+
await visualDiff(toast, "s-toast__warning-important");
|
|
39
|
+
});
|
|
40
|
+
it("should not introduce visual regressions for danger toast", async () => {
|
|
41
|
+
const toast = await fixture(testToast("danger"));
|
|
42
|
+
await visualDiff(toast, "s-toast__danger");
|
|
43
|
+
});
|
|
44
|
+
it("should not introduce visual regressions for important danger toast", async () => {
|
|
45
|
+
const toast = await fixture(testToast("danger", true));
|
|
46
|
+
await visualDiff(toast, "s-toast__danger-important");
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { html, fixture, expect } from "@open-wc/testing";
|
|
2
|
+
import { screen, waitForElementToBeRemoved } from "@testing-library/dom";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import "../ts/index";
|
|
5
|
+
|
|
6
|
+
const user = userEvent.setup();
|
|
7
|
+
|
|
8
|
+
describe("s-tooltip", () => {
|
|
9
|
+
it("should make the tooltip element visible on hover (after a delay)", async () => {
|
|
10
|
+
const trigger = await fixture(html`
|
|
11
|
+
<button
|
|
12
|
+
class="s-btn s-btn__filled"
|
|
13
|
+
role="button"
|
|
14
|
+
data-controller="s-tooltip"
|
|
15
|
+
title="tooltip content"
|
|
16
|
+
data-s-tooltip-placement="bottom-start"
|
|
17
|
+
>
|
|
18
|
+
Hover tooltip popover
|
|
19
|
+
</button>
|
|
20
|
+
`);
|
|
21
|
+
|
|
22
|
+
expect(screen.queryByRole("tooltip")).to.be.null;
|
|
23
|
+
|
|
24
|
+
await user.hover(trigger);
|
|
25
|
+
const tooltip = await screen.findByRole("tooltip");
|
|
26
|
+
expect(tooltip).to.be.visible;
|
|
27
|
+
|
|
28
|
+
await user.unhover(trigger);
|
|
29
|
+
await waitForElementToBeRemoved(() => screen.queryByRole("tooltip"));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should not flicker when the host contains an SVG and the user hover on it", async () => {
|
|
33
|
+
await fixture(html`
|
|
34
|
+
<button
|
|
35
|
+
class="s-btn"
|
|
36
|
+
role="button"
|
|
37
|
+
title="tooltip content"
|
|
38
|
+
data-controller="s-tooltip"
|
|
39
|
+
data-s-tooltip-placement="bottom-start"
|
|
40
|
+
>
|
|
41
|
+
<svg
|
|
42
|
+
data-testid="svg"
|
|
43
|
+
aria-hidden="true"
|
|
44
|
+
class="bg-red-500"
|
|
45
|
+
width="18"
|
|
46
|
+
height="18"
|
|
47
|
+
viewBox="0 0 18 18"
|
|
48
|
+
></svg>
|
|
49
|
+
👈 Shouldn't flicker 🤷
|
|
50
|
+
</button>
|
|
51
|
+
`);
|
|
52
|
+
const button = screen.getByRole("button");
|
|
53
|
+
const svg = screen.getByTestId("svg");
|
|
54
|
+
|
|
55
|
+
await user.hover(button);
|
|
56
|
+
const tooltip = await screen.findByRole("tooltip");
|
|
57
|
+
expect(tooltip).to.be.visible;
|
|
58
|
+
|
|
59
|
+
await user.hover(svg);
|
|
60
|
+
expect(tooltip).to.be.visible;
|
|
61
|
+
});
|
|
62
|
+
});
|