@stackoverflow/stacks 2.0.4 → 2.0.6

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.
@@ -26,9 +26,9 @@
26
26
  }
27
27
 
28
28
  &&__grayscale {
29
- --_an-a-fc: var(--black-400);
30
- --_an-a-fc-hover: var(--black-500);
31
- --_an-a-fc-visited: var(--black-600);
29
+ --_an-a-fc: var(--black-500);
30
+ --_an-a-fc-hover: var(--black-600);
31
+ --_an-a-fc-visited: var(--black-400);
32
32
  }
33
33
 
34
34
  &&__inherit {
@@ -67,8 +67,8 @@ a,
67
67
 
68
68
  &__grayscale {
69
69
  --_li-fc: var(--black-500);
70
- --_li-fc-hover: var(--black-400);
71
- --_li-fc-visited: var(--black-600);
70
+ --_li-fc-hover: var(--black-600);
71
+ --_li-fc-visited: var(--black-400);
72
72
  }
73
73
 
74
74
  &__inherit {
@@ -0,0 +1,42 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runComponentTests } from "../../test/test-utils";
3
+ import { IconClearSm } from "@stackoverflow/stacks-icons/icons";
4
+ import "../../index";
5
+
6
+ describe("modal", () => {
7
+ runComponentTests({
8
+ type: "a11y",
9
+ baseClass: `s-modal`,
10
+ variants: ["danger"],
11
+ modifiers: {
12
+ primary: ["celebration"],
13
+ secondary: ["full"],
14
+ },
15
+ children: {
16
+ default: `
17
+ <div class="s-modal--dialog" role="document">
18
+ <h1 class="s-modal--header" id="modal-title">Modal header</h1>
19
+ <p class="s-modal--body" id="modal-description">Modal body. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.</p>
20
+ <div class="d-flex gx8 s-modal--footer">
21
+ <button class="s-btn s-btn__filled" type="button">Confirm</button>
22
+ <button class="s-btn s-btn__muted" type="button">Cancel</button>
23
+ </div>
24
+ <button class="s-modal--close s-btn s-btn__muted" type="button" aria-label="Close">
25
+ ${IconClearSm}
26
+ </button>
27
+ </div>
28
+ `,
29
+ },
30
+ tag: "aside",
31
+ attributes: {
32
+ "id": "example-modal",
33
+ "tabindex": "-1",
34
+ "aria-hidden": "false",
35
+ "aria-labelledby": "modal-title",
36
+ "class": "ps-relative p32",
37
+ },
38
+ template: ({ component, testid }) => html`
39
+ <div class="m8 ws6" data-testid="${testid}">${component}</div>
40
+ `,
41
+ });
42
+ });
@@ -9,6 +9,14 @@
9
9
  --_mo-header-fc: var(--fc-dark);
10
10
 
11
11
  // CONTEXTUAL STYLES
12
+ .dark-mode({
13
+ --_mo-dialog-bg: var(--black-225);
14
+ });
15
+
16
+ .highcontrast-dark-mode({
17
+ --_mo-dialog-bg: var(--black-200);
18
+ });
19
+
12
20
  &[aria-hidden="false"] {
13
21
  &,
14
22
  .s-modal--dialog {
@@ -60,10 +68,6 @@
60
68
  }
61
69
 
62
70
  & &--dialog {
63
- .dark-mode({
64
- --_mo-dialog-bg: var(--black-225);
65
- });
66
-
67
71
  padding: var(--_mo-dialog-pt) var(--su24) var(--su24);
68
72
 
69
73
  @scrollbar-styles();
@@ -0,0 +1,42 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runComponentTests } from "../../test/test-utils";
3
+ import { IconClearSm } from "@stackoverflow/stacks-icons/icons";
4
+ import "../../index";
5
+
6
+ describe("modal", () => {
7
+ runComponentTests({
8
+ type: "visual",
9
+ baseClass: `s-modal`,
10
+ variants: ["danger"],
11
+ modifiers: {
12
+ primary: ["celebration"],
13
+ secondary: ["full"],
14
+ },
15
+ children: {
16
+ default: `
17
+ <div class="s-modal--dialog" role="document">
18
+ <h1 class="s-modal--header" id="modal-title">Modal header</h1>
19
+ <p class="s-modal--body" id="modal-description">Modal body. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.</p>
20
+ <div class="d-flex gx8 s-modal--footer">
21
+ <button class="s-btn s-btn__filled" type="button">Confirm</button>
22
+ <button class="s-btn s-btn__muted" type="button">Cancel</button>
23
+ </div>
24
+ <button class="s-modal--close s-btn s-btn__muted" type="button" aria-label="Close">
25
+ ${IconClearSm}
26
+ </button>
27
+ </div>
28
+ `,
29
+ },
30
+ tag: "aside",
31
+ attributes: {
32
+ "id": "example-modal",
33
+ "tabindex": "-1",
34
+ "aria-hidden": "false",
35
+ "aria-labelledby": "modal-title",
36
+ "class": "ps-relative p32",
37
+ },
38
+ template: ({ component, testid }) => html`
39
+ <div class="m8 ws6" data-testid="${testid}">${component}</div>
40
+ `,
41
+ });
42
+ });
@@ -1,5 +1,6 @@
1
1
  import { html } from "@open-wc/testing";
2
2
  import { runComponentTests } from "../../test/test-utils";
3
+ import { WCAGNonTextContrast } from "../../test/assertions";
3
4
  import "../../index";
4
5
 
5
6
  const items = [
@@ -74,5 +75,8 @@ describe("navigation", () => {
74
75
  ${component}
75
76
  </nav>
76
77
  `,
78
+ additionalAssertions: [WCAGNonTextContrast],
79
+ // TODO: fix non-text-contrast SC for s-navigation__muted
80
+ skippedTestids: [/s-navigation-(light|dark)-muted/],
77
81
  });
78
82
  });
@@ -1,4 +1,5 @@
1
1
  import { runComponentTests } from "../../test/test-utils";
2
+ import { WCAGNonTextContrast } from "../../test/assertions";
2
3
  import "../../index";
3
4
 
4
5
  describe("pagination", () => {
@@ -16,5 +17,6 @@ describe("pagination", () => {
16
17
  <a class="s-pagination--item" href="#">Next</a>
17
18
  `,
18
19
  },
20
+ additionalAssertions: [WCAGNonTextContrast],
19
21
  });
20
22
  });
@@ -296,12 +296,12 @@ body .themed {
296
296
  --black-500: hsl(210, 8%, 25%);
297
297
  --black-600: hsl(210, 8%, 5%);
298
298
  --black: hsl(0, 0%, 0%);
299
- --orange-100: hsl(23, 85%, 97%);
300
- --orange-200: hsl(27, 85%, 87%);
301
- --orange-300: hsl(27, 85%, 72%);
302
- --orange-400: hsl(27, 80%, 52%);
303
- --orange-500: hsl(27, 80%, 43%);
304
- --orange-600: hsl(27, 80%, 29%);
299
+ --orange-100: hsl(23, 87%, 97%);
300
+ --orange-200: hsl(27, 87%, 87%);
301
+ --orange-300: hsl(27, 87%, 72%);
302
+ --orange-400: hsl(27, 89%, 48%);
303
+ --orange-500: hsl(27, 87%, 41%);
304
+ --orange-600: hsl(27, 87%, 27%);
305
305
  --blue-100: hsl(210, 80%, 96%);
306
306
  --blue-200: hsl(210, 80%, 91%);
307
307
  --blue-300: hsl(210, 78%, 76%);
@@ -84,12 +84,12 @@ body:not(.theme-highcontrast).theme-system .theme-light__forced .themed {
84
84
  --black-500: hsl(210, 8%, 25%);
85
85
  --black-600: hsl(210, 8%, 5%);
86
86
  --black: hsl(0, 0%, 0%);
87
- --orange-100: hsl(23, 85%, 97%);
88
- --orange-200: hsl(27, 85%, 87%);
89
- --orange-300: hsl(27, 85%, 72%);
90
- --orange-400: hsl(27, 80%, 52%);
91
- --orange-500: hsl(27, 80%, 43%);
92
- --orange-600: hsl(27, 80%, 29%);
87
+ --orange-100: hsl(23, 87%, 97%);
88
+ --orange-200: hsl(27, 87%, 87%);
89
+ --orange-300: hsl(27, 87%, 72%);
90
+ --orange-400: hsl(27, 89%, 48%);
91
+ --orange-500: hsl(27, 87%, 41%);
92
+ --orange-600: hsl(27, 87%, 27%);
93
93
  --blue-100: hsl(210, 80%, 96%);
94
94
  --blue-200: hsl(210, 80%, 91%);
95
95
  --blue-300: hsl(210, 78%, 76%);
@@ -463,10 +463,10 @@ body.theme-highcontrast.theme-system .theme-light__forced {
463
463
  --black: hsl(0, 0%, 0%);
464
464
  --orange-100: hsl(23, 87%, 97%);
465
465
  --orange-200: hsl(23, 87%, 97%);
466
- --orange-300: hsl(27, 90%, 55%);
467
- --orange-400: hsl(27, 90%, 55%);
468
- --orange-500: hsl(27, 80%, 28%);
469
- --orange-600: hsl(27, 80%, 28%);
466
+ --orange-300: hsl(27, 89%, 48%);
467
+ --orange-400: hsl(27, 87%, 29%);
468
+ --orange-500: hsl(27, 87%, 21%);
469
+ --orange-600: hsl(27, 87%, 21%);
470
470
  --blue-100: hsl(210, 80%, 96%);
471
471
  --blue-200: hsl(210, 80%, 96%);
472
472
  --blue-300: hsl(210, 70%, 48%);
@@ -86,12 +86,12 @@
86
86
 
87
87
  // Orange
88
88
  .set-orange() {
89
- 100: hsl(23, 85%, 97%);
90
- 200: hsl(27, 85%, 87%);
91
- 300: hsl(27, 85%, 72%);
92
- 400: hsl(27, 80%, 52%);
93
- 500: hsl(27, 80%, 43%);
94
- 600: hsl(27, 80%, 29%);
89
+ 100: hsl(23, 87%, 97%);
90
+ 200: hsl(27, 87%, 87%);
91
+ 300: hsl(27, 87%, 72%);
92
+ 400: hsl(27, 89%, 48%);
93
+ 500: hsl(27, 87%, 41%);
94
+ 600: hsl(27, 87%, 27%);
95
95
  }
96
96
  .set-orange-dark() {
97
97
  100: hsl(27, 55%, 20%);
@@ -104,10 +104,10 @@
104
104
  .set-orange-hc() {
105
105
  100: hsl(23, 87%, 97%);
106
106
  200: hsl(23, 87%, 97%);
107
- 300: hsl(27, 90%, 55%);
108
- 400: hsl(27, 90%, 55%);
109
- 500: hsl(27, 80%, 28%);
110
- 600: hsl(27, 80%, 28%);
107
+ 300: hsl(27, 89%, 48%);
108
+ 400: hsl(27, 87%, 29%);
109
+ 500: hsl(27, 87%, 21%);
110
+ 600: hsl(27, 87%, 21%);
111
111
  }
112
112
  .set-orange-hc-dark() {
113
113
  100: hsl(27, 30%, 19%);
@@ -0,0 +1,29 @@
1
+ import { expect } from "@open-wc/testing";
2
+ import Color from "colorjs.io";
3
+ import type { AdditionalAssertion } from "./test-utils";
4
+
5
+ // TODO: evaluate if we can do this check against all the components
6
+ // automatically instead of having to add the assertion manually
7
+ export const WCAGNonTextContrast: AdditionalAssertion = {
8
+ description:
9
+ "should pass WCAG22 1.4.11 non-text-contrast success criterion (https://www.w3.org/TR/WCAG22/#non-text-contrast)",
10
+ assertion: (node) => {
11
+ const selectedNode = node.querySelector(".is-selected") as HTMLElement;
12
+ const selectedNodeStyles = window.getComputedStyle(selectedNode);
13
+ const bodyStyles = window.getComputedStyle(document.body);
14
+ const bgBodyColor = new Color(
15
+ bodyStyles.getPropertyValue("background-color")
16
+ );
17
+ const bgSelectedNodeColor = new Color(
18
+ selectedNodeStyles.getPropertyValue("background-color")
19
+ );
20
+
21
+ // we are specificng WCAG21 because of colorjs.io API
22
+ // WCAG21 and WCAG22 algoirthms are the same
23
+ const WCAGcontrast = bgSelectedNodeColor.contrast(
24
+ bgBodyColor,
25
+ "WCAG21"
26
+ );
27
+ expect(WCAGcontrast).to.be.at.least(3);
28
+ },
29
+ };
@@ -22,6 +22,10 @@ export const defaultOptions = {
22
22
 
23
23
  type Themes = ["light" | "dark" | "highcontrast" | ""];
24
24
  type TestTypes = "visual" | "a11y";
25
+ export type AdditionalAssertion = {
26
+ description: string;
27
+ assertion: (node: HTMLElement) => Promise<void> | void;
28
+ };
25
29
 
26
30
  type TestOptions = {
27
31
  /**
@@ -92,6 +96,10 @@ type ComponentTestArgs = {
92
96
  * Type of test to run
93
97
  */
94
98
  type: TestTypes;
99
+ /**
100
+ * Additional assertions to run against the test element
101
+ */
102
+ additionalAssertions: AdditionalAssertion[];
95
103
  };
96
104
 
97
105
  interface ComponentTestsArgs extends ComponentTestVariationArgs {
@@ -132,6 +140,10 @@ interface ComponentTestsArgs extends ComponentTestVariationArgs {
132
140
  * Type of test to run
133
141
  */
134
142
  type: TestTypes;
143
+ /**
144
+ * Additional assertions to run against the test element
145
+ */
146
+ additionalAssertions?: AdditionalAssertion[];
135
147
  }
136
148
 
137
149
  type ComponentTestModifiers = {
@@ -299,6 +311,7 @@ const runComponentTest = ({
299
311
  testid,
300
312
  theme,
301
313
  type,
314
+ additionalAssertions,
302
315
  }: ComponentTestArgs) => {
303
316
  const getDescription = (type: TestTypes) => {
304
317
  switch (type) {
@@ -344,6 +357,14 @@ const runComponentTest = ({
344
357
  await visualDiff(el, testid);
345
358
  }
346
359
  });
360
+
361
+ additionalAssertions.forEach((assertion) => {
362
+ it(`${type}: ${testid} ${assertion.description}`, async () => {
363
+ await fixture(element);
364
+ const el = screen.getByTestId(testid);
365
+ await assertion.assertion(el);
366
+ });
367
+ });
347
368
  };
348
369
 
349
370
  /**
@@ -361,6 +382,7 @@ const runComponentTests = ({
361
382
  tag,
362
383
  template,
363
384
  type,
385
+ additionalAssertions = [],
364
386
  }: ComponentTestsArgs) => {
365
387
  getComponentTestVariations({
366
388
  baseClass,
@@ -428,6 +450,7 @@ const runComponentTests = ({
428
450
  testid: testidModified,
429
451
  theme,
430
452
  type,
453
+ additionalAssertions,
431
454
  });
432
455
  });
433
456
  });
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "type": "git",
6
6
  "url": "https://github.com/StackExchange/Stacks.git"
7
7
  },
8
- "version": "2.0.4",
8
+ "version": "2.0.6",
9
9
  "files": [
10
10
  "dist",
11
11
  "lib"
@@ -45,23 +45,25 @@
45
45
  "devDependencies": {
46
46
  "@11ty/eleventy": "^2.0.1",
47
47
  "@highlightjs/cdn-assets": "^11.9.0",
48
- "@open-wc/testing": "^3.2.0",
48
+ "@open-wc/testing": "^3.2.2",
49
49
  "@rollup/plugin-commonjs": "^25.0.7",
50
- "@rollup/plugin-replace": "^5.0.4",
51
- "@stackoverflow/stacks-editor": "^0.9.0",
50
+ "@rollup/plugin-replace": "^5.0.5",
51
+ "@stackoverflow/stacks-editor": "^0.9.1",
52
52
  "@stackoverflow/stacks-icons": "^6.0.0",
53
53
  "@testing-library/dom": "^9.3.3",
54
54
  "@testing-library/user-event": "^14.5.1",
55
55
  "@types/cssbeautify": "^0.3.4",
56
56
  "@types/less": "^3.0.5",
57
- "@typescript-eslint/eslint-plugin": "^6.9.0",
58
- "@typescript-eslint/parser": "^6.9.0",
59
- "@web/dev-server-esbuild": "^0.4.3",
60
- "@web/dev-server-rollup": "^0.5.4",
61
- "@web/test-runner": "^0.17.2",
62
- "@web/test-runner-playwright": "^0.10.2",
63
- "@web/test-runner-visual-regression": "^0.8.2",
57
+ "@types/mocha": "^10.0.3",
58
+ "@typescript-eslint/eslint-plugin": "^6.9.1",
59
+ "@typescript-eslint/parser": "^6.9.1",
60
+ "@web/dev-server-esbuild": "^1.0.0",
61
+ "@web/dev-server-rollup": "^0.6.0",
62
+ "@web/test-runner": "^0.18.0",
63
+ "@web/test-runner-playwright": "^0.11.0",
64
+ "@web/test-runner-visual-regression": "^0.9.0",
64
65
  "apca-check": "^0.1.0",
66
+ "colorjs.io": "^0.4.5",
65
67
  "concurrently": "^8.2.2",
66
68
  "css-loader": "^6.8.1",
67
69
  "cssbeautify": "^0.3.1",
@@ -69,7 +71,7 @@
69
71
  "docsearch.js": "^2.6.3",
70
72
  "eleventy-plugin-highlightjs": "^1.1.0",
71
73
  "eleventy-plugin-nesting-toc": "^1.3.0",
72
- "eslint": "^8.52.0",
74
+ "eslint": "^8.53.0",
73
75
  "eslint-config-prettier": "^9.0.0",
74
76
  "eslint-plugin-no-unsanitized": "^4.0.2",
75
77
  "jquery": "^3.7.1",