@stackoverflow/stacks 2.1.0 → 2.2.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.
@@ -1,3 +1,8 @@
1
+ @import (reference) "../base/internal.less";
2
+ @import (reference) "../exports/color-mixins.less";
3
+ @import (reference) "../exports/constants-helpers.less";
4
+ @import (reference) "../exports/mixins.less";
5
+
1
6
  //
2
7
  // STACK OVERFLOW
3
8
  // UTILITIES
@@ -78,6 +83,31 @@
78
83
  background-image: url("data:image/svg+xml;,%3Csvg width='574' height='60' viewBox='0 0 574 60' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect opacity='0.8' x='27.1224' y='20.0458' width='5' height='13' transform='rotate(-139 27.1224 20.0458)' fill='%23F23B14'/%3E%3Crect opacity='0.8' x='118.478' y='7.00201' width='5' height='13' transform='rotate(-38.8114 118.478 7.00201)' fill='%23FBBA23'/%3E%3Crect opacity='0.8' x='504.616' y='25.4479' width='5' height='13' transform='rotate(-60.2734 504.616 25.4479)' fill='%23F23B14'/%3E%3Crect opacity='0.6' x='538.983' y='45.555' width='5' height='13' transform='rotate(16.7826 538.983 45.555)' fill='%232A2F6A'/%3E%3Crect opacity='0.3' x='470.322' y='2.63625' width='5' height='13' transform='rotate(11.295 470.322 2.63625)' fill='%2333AAFF'/%3E%3Crect opacity='0.3' x='190.295' y='4.58138' width='5' height='13' transform='rotate(27.5954 190.295 4.58138)' fill='%23F23B14'/%3E%3Crect opacity='0.8' x='234.303' y='16.3233' width='5' height='13' transform='rotate(-41.8233 234.303 16.3233)' fill='%2365BB5C'/%3E%3Crect opacity='0.6' x='369.702' y='40.9875' width='5' height='13' transform='rotate(-56.419 369.702 40.9875)' fill='%2333AAFF'/%3E%3Crect opacity='0.3' x='402.121' y='31.0848' width='5' height='13' transform='rotate(-17.9234 402.121 31.0848)' fill='%23F23B14'/%3E%3Crect opacity='0.6' x='200.316' y='31.9328' width='5' height='13' transform='rotate(-15.8896 200.316 31.9328)' fill='%232A2F6A'/%3E%3Crect opacity='0.6' x='69.6745' y='23.4725' width='6' height='10' transform='rotate(70.0266 69.6745 23.4725)' fill='%2365BB5C'/%3E%3Crect opacity='0.6' x='291.945' y='7.16931' width='6' height='10' transform='rotate(30.4258 291.945 7.16931)' fill='%23FBBA23'/%3E%3Crect opacity='0.3' x='33.7754' y='38.2208' width='6' height='10' transform='rotate(38.6056 33.7754 38.2208)' fill='%23FBBA23'/%3E%3Crect opacity='0.8' x='109.752' y='31.1743' width='6' height='10' transform='rotate(28.5296 109.752 31.1743)' fill='%2333AAFF'/%3E%3Crect opacity='0.3' x='278.081' y='37.8695' width='6' height='10' transform='rotate(-26.5651 278.081 37.8695)' fill='%23F23B14'/%3E%3Crect opacity='0.8' x='416.294' y='11.5573' width='6' height='10' transform='rotate(-22.8498 416.294 11.5573)' fill='%23FBBA23'/%3E%3Crect opacity='0.3' x='354.667' y='9.32341' width='6' height='10' transform='rotate(17.7506 354.667 9.32341)' fill='%232A2F6A'/%3E%3Crect opacity='0.8' x='532.404' y='16.6372' width='6' height='10' transform='rotate(-75.3432 532.404 16.6372)' fill='%23FBBA23'/%3E%3Crect opacity='0.6' x='460.463' y='39.3557' width='6' height='10' transform='rotate(45.4982 460.463 39.3557)' fill='%2365BB5C'/%3E%3C/svg%3E");
79
84
  }
80
85
 
86
+ // Focus styles
87
+ .focus,
88
+ .f\:focus:focus,
89
+ .f\:focus:focus-within {
90
+ .focus-styles();
91
+ }
92
+
93
+ .focus-inset,
94
+ .f\:focus-inset:focus,
95
+ .f\:focus-inset:focus-within {
96
+ .focus-styles(true);
97
+ }
98
+
99
+ .focus-bordered,
100
+ .f\:focus-bordered:focus,
101
+ .f\:focus-bordered:focus-within {
102
+ .focus-styles(false, true);
103
+ }
104
+
105
+ .focus-inset-bordered,
106
+ .f\:focus-inset-bordered:focus,
107
+ .f\:focus-inset-bordered:focus-within {
108
+ .focus-styles(true, true);
109
+ }
110
+
81
111
  // ============================================================================
82
112
  // $ OBJECT-FIT / OBJECT-POSITION
83
113
  // ----------------------------------------------------------------------------
@@ -0,0 +1,12 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { renderLess } from "../test/less-test-utils";
3
+
4
+ describe("atomic: misc", () => {
5
+ it("should output all atomic css classes", async () => {
6
+ const css = await renderLess(`
7
+ @import "./lib/atomic/misc.less";
8
+ `);
9
+
10
+ expect(css).toMatchSnapshot();
11
+ });
12
+ });
@@ -1,28 +1,38 @@
1
1
  import { runA11yTests } from "../../test/a11y-test-utils";
2
- // import { Icons } from "@stackoverflow/stacks-icons";
2
+ import { IconEyeSm } from "@stackoverflow/stacks-icons/icons";
3
3
  import "../../index";
4
4
 
5
5
  const variants = {
6
6
  blings: ["gold", "silver", "bronze"],
7
7
  numbers: ["answered", "bounty", "important", "rep", "rep-down", "votes"],
8
- states: {
9
- filled: ["danger", "muted"],
10
- other: ["info", "warning"],
11
- },
8
+ filled: ["danger", "muted"],
9
+ states: ["danger", "muted", "info", "new", "warning"],
12
10
  users: ["admin", "moderator", "staff"],
13
11
  };
14
12
 
15
13
  describe("badge", () => {
16
- // Award badges (Default/badge counts)
14
+ // Base badge
15
+ runA11yTests({
16
+ baseClass: "s-badge",
17
+ children: {
18
+ default: `base badge`,
19
+ },
20
+ tag: "span",
21
+ });
22
+
23
+ // Award badges
17
24
  variants.blings.map((bling) => {
18
25
  runA11yTests({
19
26
  baseClass: "s-badge",
20
27
  variants: [bling],
21
28
  children: {
22
29
  default: `<span class="s-award-bling s-award-bling__${bling}">
23
- Altruist
30
+ with bling
24
31
  </span>`,
25
32
  },
33
+ options: {
34
+ includeNullVariant: false,
35
+ },
26
36
  tag: "span",
27
37
  });
28
38
  });
@@ -34,22 +44,49 @@ describe("badge", () => {
34
44
  children: {
35
45
  default: "123",
36
46
  },
47
+ options: {
48
+ includeNullVariant: false,
49
+ },
50
+ tag: "span",
51
+ });
52
+
53
+ // State badges
54
+ runA11yTests({
55
+ baseClass: "s-badge",
56
+ variants: variants.states,
57
+ children: {
58
+ default: `badge`,
59
+ },
60
+ tag: "span",
61
+ skippedTestids: ["s-badge-dark-new"],
62
+ });
63
+
64
+ // State badges w/ filled modifier
65
+ runA11yTests({
66
+ baseClass: "s-badge",
67
+ variants: variants.filled,
68
+ modifiers: {
69
+ primary: ["filled"],
70
+ },
71
+ children: {
72
+ default: `filled badge`,
73
+ },
37
74
  options: {
38
75
  includeNullModifier: false,
39
76
  },
40
77
  tag: "span",
41
78
  });
42
79
 
43
- // Icon badges
80
+ // State badges w/ filled modifier and icon
44
81
  runA11yTests({
45
82
  baseClass: "s-badge",
46
- variants: [...variants.states.filled, ...variants.states.other],
83
+ variants: variants.filled,
47
84
  modifiers: {
48
- primary: ["icon"],
85
+ primary: ["filled"],
86
+ secondary: ["icon"],
49
87
  },
50
88
  children: {
51
- default: "with icon",
52
- // icon: Icons.IconEyeSm, // TODO fix the icon imports
89
+ default: `${IconEyeSm} icon badge`,
53
90
  },
54
91
  options: {
55
92
  includeNullModifier: false,
@@ -57,20 +94,18 @@ describe("badge", () => {
57
94
  tag: "span",
58
95
  });
59
96
 
60
- // Filled badges
97
+ // State badges w/ icon
61
98
  runA11yTests({
62
99
  baseClass: "s-badge",
63
- variants: variants.states.filled,
100
+ variants: variants.states.filter((state) => state !== "new"),
64
101
  modifiers: {
65
102
  primary: ["icon"],
66
103
  },
67
104
  children: {
68
- default: "filled",
69
- // icon: Icons.IconEyeOffSm, // TODO fix the icon imports
105
+ default: `${IconEyeSm} icon badge`,
70
106
  },
71
107
  options: {
72
108
  includeNullModifier: false,
73
- includeNullVariant: false,
74
109
  },
75
110
  tag: "span",
76
111
  });
@@ -83,7 +118,10 @@ describe("badge", () => {
83
118
  primary: ["xs", "sm"],
84
119
  },
85
120
  children: {
86
- default: "user",
121
+ default: "user badge",
122
+ },
123
+ options: {
124
+ includeNullVariant: false,
87
125
  },
88
126
  tag: "span",
89
127
  });
@@ -97,6 +135,9 @@ describe("badge", () => {
97
135
  children: {
98
136
  default: "size badge",
99
137
  },
138
+ options: {
139
+ includeNullModifier: false,
140
+ },
100
141
  tag: "span",
101
142
  });
102
143
  });
@@ -4,10 +4,12 @@
4
4
  --_ba-bg: var(--black-150);
5
5
  --_ba-fc: var(--black-500);
6
6
  --_ba-fs: var(--fs-caption);
7
+ --_ba-fw: normal;
7
8
  --_ba-g: 0.3em;
8
9
  --_ba-lh: 2;
9
10
  --_ba-px: var(--su6);
10
11
  --_ba-py: 0;
12
+ --_ba-tt: unset;
11
13
  --_ba-wmn: 0;
12
14
 
13
15
  // CONTEXTUAL STYLES
@@ -26,6 +28,10 @@
26
28
  &__staff {
27
29
  --_ba-bc: currentColor;
28
30
  }
31
+
32
+ &__new {
33
+ --_ba-fc: var(--purple-600);
34
+ }
29
35
  });
30
36
 
31
37
  // MODIFIERS
@@ -208,6 +214,14 @@
208
214
  }
209
215
  }
210
216
 
217
+ &&__new {
218
+ --_ba-bc: var(--_ba-bg);
219
+ --_ba-bg: var(--purple-100);
220
+ --_ba-fc: var(--purple-400);
221
+ --_ba-fw: bold;
222
+ --_ba-tt: uppercase;
223
+ }
224
+
211
225
  // CHILD ELEMENTS
212
226
  &--image, // Included with no base class to account for usage in .s-progress__badge
213
227
  & &--image {
@@ -228,14 +242,15 @@
228
242
  color: var(--_ba-fc);
229
243
  font-size: var(--_ba-fs);
230
244
  gap: var(--_ba-g);
245
+ font-weight: var(--_ba-fw);
231
246
  line-height: var(--_ba-lh);
232
247
  min-width: var(--_ba-wmn);
233
248
  padding: var(--_ba-py) var(--_ba-px);
249
+ text-transform: var(--_ba-tt);
234
250
 
235
251
  align-items: center;
236
252
  border-radius: var(--br-sm);
237
253
  display: inline-flex;
238
- font-weight: normal;
239
254
  justify-content: center;
240
255
  text-decoration: none;
241
256
  vertical-align: middle;
@@ -1,15 +1,13 @@
1
1
  import { runVisualTests } from "../../test/visual-test-utils";
2
- // import { Icons } from "@stackoverflow/stacks-icons";
2
+ import { IconEyeSm } from "@stackoverflow/stacks-icons/icons";
3
3
  import "../../index";
4
4
  import { html } from "@open-wc/testing";
5
5
 
6
6
  const variants = {
7
7
  blings: ["gold", "silver", "bronze"],
8
8
  numbers: ["answered", "bounty", "important", "rep", "rep-down", "votes"],
9
- states: {
10
- filled: ["danger", "muted"],
11
- other: ["info", "warning"],
12
- },
9
+ filled: ["danger", "muted"],
10
+ states: ["danger", "muted", "info", "new", "warning"],
13
11
  users: ["admin", "moderator", "staff"],
14
12
  };
15
13
 
@@ -46,7 +44,6 @@ describe("badge", () => {
46
44
  },
47
45
  options: {
48
46
  includeNullVariant: false,
49
- includeNullModifier: false,
50
47
  },
51
48
  tag: "span",
52
49
  template,
@@ -62,22 +59,52 @@ describe("badge", () => {
62
59
  },
63
60
  options: {
64
61
  includeNullVariant: false,
62
+ },
63
+ tag: "span",
64
+ template,
65
+ });
66
+
67
+ // State badges
68
+ runVisualTests({
69
+ baseClass: "s-badge",
70
+ variants: variants.states,
71
+ children: {
72
+ default: `state badge`,
73
+ },
74
+ tag: "span",
75
+ options: {
76
+ includeNullVariant: false,
77
+ },
78
+ template,
79
+ });
80
+
81
+ // State badges w/ filled modifier
82
+ runVisualTests({
83
+ baseClass: "s-badge",
84
+ variants: variants.filled,
85
+ modifiers: {
86
+ primary: ["filled"],
87
+ },
88
+ children: {
89
+ default: `filled badge`,
90
+ },
91
+ options: {
65
92
  includeNullModifier: false,
66
93
  },
67
94
  tag: "span",
68
95
  template,
69
96
  });
70
97
 
71
- // Icon badges
98
+ // State badges w/ filled modifier and icon
72
99
  runVisualTests({
73
100
  baseClass: "s-badge",
74
- variants: [...variants.states.filled, ...variants.states.other],
101
+ variants: variants.filled,
75
102
  modifiers: {
76
- primary: ["icon"],
103
+ primary: ["filled"],
104
+ secondary: ["icon"],
77
105
  },
78
106
  children: {
79
- default: "with icon",
80
- // icon: Icons.IconEyeSm, // TODO fix the icon imports
107
+ default: `${IconEyeSm} icon badge`,
81
108
  },
82
109
  options: {
83
110
  includeNullModifier: false,
@@ -86,17 +113,18 @@ describe("badge", () => {
86
113
  template,
87
114
  });
88
115
 
89
- // Filled badges
116
+ // State badges w/ icon
90
117
  runVisualTests({
91
118
  baseClass: "s-badge",
92
- variants: variants.states.filled,
119
+ variants: variants.states.filter((state) => state !== "new"),
120
+ modifiers: {
121
+ primary: ["icon"],
122
+ },
93
123
  children: {
94
- default: "filled",
95
- // icon: Icons.IconEyeOffSm, // TODO fix the icon imports
124
+ default: `${IconEyeSm} icon badge`,
96
125
  },
97
126
  options: {
98
127
  includeNullModifier: false,
99
- includeNullVariant: false,
100
128
  },
101
129
  tag: "span",
102
130
  template,
@@ -412,7 +412,7 @@
412
412
  .focus-styles(true, true);
413
413
  }
414
414
 
415
- &:not(&__link):not(&__unset)&:not(&__facebook):not(&__github):not(&__google):not(.is-selected):focus-visible,
415
+ &:not(&__link):not(&__unset):not(&__facebook):not(&__github):not(&__google):not(.is-selected):focus-visible,
416
416
  &--radio:focus-visible + & {
417
417
  &,
418
418
  &.s-btn__filled {
@@ -425,17 +425,30 @@
425
425
  }
426
426
  }
427
427
 
428
- &:not(&__link):not(&__unset)&:not(&__facebook):not(&__github):not(&__google):not(.is-selected) {
428
+ &:not(&__link):not(&__unset):not(&__facebook):not(&__github):not(&__google):not(.is-selected) {
429
429
  &:hover {
430
430
  &.s-btn__filled {
431
431
  background-color: var(--_bu-filled-bg-hover);
432
432
  border-color: var(--_bu-filled-bc-hover);
433
433
  color: var(--_bu-filled-fc-hover);
434
434
  }
435
+
435
436
  &:not(.s-btn__outlined) {
436
437
  border-color: var(--_bu-bc-hover);
437
438
  }
438
439
 
440
+ &:visited:not(:hover):not(:focus) {
441
+ &.s-btn__filled {
442
+ background-color: var(--_bu-filled-bg);
443
+ border-color: var(--_bu-filled-bc);
444
+ color: var(--_bu-filled-fc);
445
+ }
446
+
447
+ background-color: var(--_bu-bg);
448
+ border-color: var(--_bu-bc);
449
+ color: var(--_bu-fc);
450
+ }
451
+
439
452
  background-color: var(--_bu-bg-hover);
440
453
  color: var(--_bu-fc-hover);
441
454
  }
@@ -453,19 +466,6 @@
453
466
  }
454
467
  }
455
468
 
456
-
457
- &:visited:not(:hover):not(:focus) {
458
- &.s-btn__filled {
459
- background-color: var(--_bu-filled-bg);
460
- border-color: var(--_bu-filled-bc);
461
- color: var(--_bu-filled-fc);
462
- }
463
-
464
- background-color: var(--_bu-bg);
465
- border-color: var(--_bu-bc);
466
- color: var(--_bu-fc);
467
- }
468
-
469
469
  background-color: var(--_bu-bg, inherit); // [1]
470
470
  border: var(--_bu-baw) solid var(--_bu-bc);
471
471
  border-radius: var(--_bu-br);
@@ -0,0 +1,81 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runA11yTests } from "../../test/a11y-test-utils";
3
+ import "../../index";
4
+
5
+ const modifiers = [
6
+ {
7
+ name: "error",
8
+ parentClasses: "has-error",
9
+ },
10
+ {
11
+ name: "success",
12
+ parentClasses: "has-success",
13
+ },
14
+ {
15
+ name: "warning",
16
+ parentClasses: "has-warning",
17
+ },
18
+ {
19
+ name: "disabled",
20
+ parentClasses: "is-disabled",
21
+ },
22
+ {
23
+ name: "readonly",
24
+ parentClasses: "is-readonly",
25
+ },
26
+ {
27
+ name: "creditcard",
28
+ modifier: "creditcard",
29
+ inputClasses: "s-input__creditcard",
30
+ },
31
+ {
32
+ name: "search",
33
+ modifier: "search",
34
+ inputClasses: "s-input__search",
35
+ },
36
+ ];
37
+
38
+ const getSvgPath = (name: string) => {
39
+ switch (name) {
40
+ case "creditcard":
41
+ return '<path d="M3 3h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2Zm0 6v4h12V9H3Zm0-3h12V5H3v1Z"></path>';
42
+ case "search":
43
+ return '<path d="m18 16.5-5.14-5.18h-.35a7 7 0 1 0-1.19 1.19v.35L16.5 18l1.5-1.5ZM12 7A5 5 0 1 1 2 7a5 5 0 0 1 10 0Z"></path>';
44
+ default:
45
+ return '<path d="M9.06 3C4 3 1 9 1 9s3 6 8.06 6C14 15 17 9 17 9s-3-6-7.94-6ZM9 13a4 4 0 1 1 0-8 4 4 0 0 1 0 8Zm0-2a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2 2 2 0 0 0 2 2Z"></path>'; // eye icon path
46
+ }
47
+ };
48
+
49
+ describe("input-icon", () => {
50
+ modifiers.forEach(({ name, parentClasses, modifier }) => {
51
+ runA11yTests({
52
+ baseClass: `s-input-icon`,
53
+ tag: "svg",
54
+ children: {
55
+ [name]: getSvgPath(name), // IconSearch
56
+ },
57
+ modifiers: {
58
+ standalone: modifier ? [`${modifier}`] : [],
59
+ global: parentClasses ? [`parent-${parentClasses}`] : [],
60
+ },
61
+ attributes: {
62
+ "aria-hidden": "true",
63
+ "width": "18",
64
+ "height": "18",
65
+ "viewBox": "0 0 18 18",
66
+ },
67
+ template: ({ component, testid }) => html`
68
+ <div
69
+ data-testid="${testid}"
70
+ class="d-flex fd-column g4 fc-black ps-relative wmx2 p8 ${parentClasses ??
71
+ ""}"
72
+ >
73
+ <div class="d-flex ps-relative svg-icon">${component}</div>
74
+ </div>
75
+ `,
76
+ options: {
77
+ includeNullModifier: false,
78
+ },
79
+ });
80
+ });
81
+ });
@@ -0,0 +1,92 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runVisualTests } from "../../test/visual-test-utils";
3
+ import "../../index";
4
+
5
+ const modifiers = [
6
+ {
7
+ name: "error",
8
+ parentClasses: "has-error",
9
+ },
10
+ {
11
+ name: "success",
12
+ parentClasses: "has-success",
13
+ },
14
+ {
15
+ name: "warning",
16
+ parentClasses: "has-warning",
17
+ },
18
+ {
19
+ name: "disabled",
20
+ parentClasses: "is-disabled",
21
+ },
22
+ {
23
+ name: "readonly",
24
+ parentClasses: "is-readonly",
25
+ },
26
+ {
27
+ name: "creditcard",
28
+ modifier: "creditcard",
29
+ inputClasses: "s-input__creditcard",
30
+ },
31
+ {
32
+ name: "search",
33
+ modifier: "search",
34
+ inputClasses: "s-input__search",
35
+ },
36
+ ];
37
+
38
+ const getSvgPath = (name: string) => {
39
+ switch (name) {
40
+ case "creditcard":
41
+ return '<path d="M3 3h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2Zm0 6v4h12V9H3Zm0-3h12V5H3v1Z"></path>';
42
+ case "search":
43
+ return '<path d="m18 16.5-5.14-5.18h-.35a7 7 0 1 0-1.19 1.19v.35L16.5 18l1.5-1.5ZM12 7A5 5 0 1 1 2 7a5 5 0 0 1 10 0Z"></path>';
44
+ default:
45
+ return '<path d="M9.06 3C4 3 1 9 1 9s3 6 8.06 6C14 15 17 9 17 9s-3-6-7.94-6ZM9 13a4 4 0 1 1 0-8 4 4 0 0 1 0 8Zm0-2a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2 2 2 0 0 0 2 2Z"></path>'; // eye icon path
46
+ }
47
+ };
48
+
49
+ describe("input-icon", () => {
50
+ modifiers.forEach(({ name, parentClasses, modifier, inputClasses }) => {
51
+ runVisualTests({
52
+ baseClass: `s-input-icon`,
53
+ tag: "svg",
54
+ children: {
55
+ [name]: getSvgPath(name), // IconSearch
56
+ },
57
+ modifiers: {
58
+ standalone: modifier ? [`${modifier}`] : [],
59
+ global: parentClasses ? [`parent-${parentClasses}`] : [],
60
+ },
61
+ attributes: {
62
+ "aria-hidden": "true",
63
+ "width": "18",
64
+ "height": "18",
65
+ "viewBox": "0 0 18 18",
66
+ },
67
+ template: ({ component, testid }) => html`
68
+ <div
69
+ data-testid="${testid}"
70
+ class="d-flex fd-column g4 fc-black ps-relative wmx2 p8 ${parentClasses ??
71
+ ""}"
72
+ >
73
+ <label class="s-label v-visible-sr" for="ex-input"
74
+ >Input</label
75
+ >
76
+ <div class="d-flex ps-relative svg-icon">
77
+ <input
78
+ id="ex-input"
79
+ type="text"
80
+ class="s-input ${inputClasses ?? ""}"
81
+ placeholder="${name} input…"
82
+ />
83
+ ${component}
84
+ </div>
85
+ </div>
86
+ `,
87
+ options: {
88
+ includeNullModifier: false,
89
+ },
90
+ });
91
+ });
92
+ });
@@ -0,0 +1,72 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runA11yTests } from "../../test/a11y-test-utils";
3
+ import "../../index";
4
+
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ const template = ({ component, testid, className }: any) => html`
7
+ <div class="d-inline-flex p8 ${className}" data-testid="${testid}">
8
+ ${component}
9
+ </div>
10
+ `;
11
+
12
+ const child = (attr?: string): string => {
13
+ return `
14
+ <label for="select-menu">Transportation method</label>
15
+ <select id="select-menu" ${attr}>
16
+ <option value="" selected>Please select one…</option>
17
+ <option value="walk">Walk</option>
18
+ <option value="bike">Bicycle</option>
19
+ <option value="car">Automobile</option>
20
+ <option value="rail">Train</option>
21
+ <option value="fly">Plane</option>
22
+ </select>`;
23
+ };
24
+
25
+ describe("select", () => {
26
+ // default, sizes
27
+ runA11yTests({
28
+ baseClass: "s-select",
29
+ modifiers: {
30
+ primary: ["sm", "md", "lg", "xl"],
31
+ },
32
+ children: {
33
+ default: child(),
34
+ },
35
+ template,
36
+ });
37
+
38
+ // modifier classes
39
+ [
40
+ {
41
+ class: "is-disabled",
42
+ attr: 'disabled=""',
43
+ },
44
+ {
45
+ class: "is-readonly",
46
+ attr: 'readonly=""',
47
+ },
48
+ {
49
+ class: "has-success",
50
+ },
51
+ {
52
+ class: "has-error",
53
+ },
54
+ {
55
+ class: "has-warning",
56
+ },
57
+ ].forEach((state) => {
58
+ runA11yTests({
59
+ baseClass: `s-select state-${state.class}`,
60
+ children: {
61
+ default: child(state.attr),
62
+ },
63
+ template: ({ component, testid }) =>
64
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
65
+ template({ component, testid, className: state.class }),
66
+ options: {
67
+ includeNullModifier: false,
68
+ },
69
+ skippedTestids: [/readonly/], // Skipping readonly since it doesn't need to meet APCA contrast minimums
70
+ });
71
+ });
72
+ });