@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.
Files changed (35) hide show
  1. package/README.md +86 -2
  2. package/dist/controllers/index.d.ts +2 -0
  3. package/dist/controllers/s-banner.d.ts +41 -0
  4. package/dist/controllers/s-toast.d.ts +97 -0
  5. package/dist/css/stacks.css +18884 -18912
  6. package/dist/css/stacks.min.css +1 -1
  7. package/dist/js/stacks.js +5252 -5260
  8. package/dist/js/stacks.min.js +1 -1
  9. package/dist/stacks.d.ts +1 -1
  10. package/lib/css/components/anchors.less +61 -0
  11. package/lib/css/components/block-link.less +80 -0
  12. package/lib/css/components/buttons.less +20 -4
  13. package/lib/css/components/expandable.less +1 -1
  14. package/lib/css/components/inputs.less +4 -0
  15. package/lib/css/components/link.less +104 -0
  16. package/lib/css/components/post-summary.less +327 -356
  17. package/lib/css/components/table.less +297 -0
  18. package/lib/css/stacks-dynamic.less +0 -8
  19. package/lib/css/stacks-static.less +9 -1
  20. package/lib/test/s-banner.test.ts +73 -0
  21. package/lib/test/s-banner.visual.test.ts +61 -0
  22. package/lib/test/s-button.visual.test.ts +12 -0
  23. package/lib/test/s-toast.test.ts +63 -0
  24. package/lib/test/s-toast.visual.test.ts +48 -0
  25. package/lib/test/s-tooltip.test.ts +62 -0
  26. package/lib/test/s-tooltip.visual.test.ts +31 -0
  27. package/lib/ts/controllers/index.ts +2 -0
  28. package/lib/ts/controllers/s-banner.ts +149 -0
  29. package/lib/ts/controllers/s-toast.ts +357 -0
  30. package/lib/ts/index.ts +4 -0
  31. package/lib/ts/stacks.ts +1 -1
  32. package/lib/tsconfig.json +2 -2
  33. package/package.json +35 -19
  34. package/lib/css/components/links.less +0 -214
  35. 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/tables.less";
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
+ });