@stackoverflow/stacks 1.10.4 → 1.10.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.
Files changed (29) hide show
  1. package/dist/components/code-block/code-block.fixtures.d.ts +2 -0
  2. package/dist/css/stacks.css +3 -2
  3. package/dist/css/stacks.min.css +1 -1
  4. package/lib/components/code-block/code-block.a11y.test.ts +30 -0
  5. package/lib/components/code-block/code-block.fixtures.ts +88 -0
  6. package/lib/components/code-block/code-block.visual.test.ts +20 -0
  7. package/lib/components/input_textarea/input_textarea.a11y.test.ts +105 -0
  8. package/lib/components/input_textarea/input_textarea.visual.test.ts +98 -0
  9. package/lib/components/modal/modal.less +1 -0
  10. package/lib/components/navigation/navigation.a11y.test.ts +80 -0
  11. package/lib/components/navigation/navigation.visual.test.ts +101 -0
  12. package/lib/components/notice/notice.a11y.test.ts +22 -0
  13. package/lib/components/notice/notice.visual.test.ts +26 -0
  14. package/lib/components/page-title/page-title.a11y.test.ts +31 -0
  15. package/lib/components/page-title/page-title.visual.test.ts +59 -0
  16. package/lib/components/pagination/pagination.a11y.test.ts +22 -0
  17. package/lib/components/pagination/pagination.visual.test.ts +26 -0
  18. package/lib/components/spinner/spinner.a11y.test.ts +15 -0
  19. package/lib/components/spinner/spinner.visual.test.ts +43 -0
  20. package/lib/components/tag/tag.a11y.test.ts +23 -0
  21. package/lib/components/tag/tag.visual.test.ts +46 -0
  22. package/lib/components/toast/toast.a11y.test.ts +35 -0
  23. package/lib/components/toast/toast.visual.test.ts +10 -6
  24. package/lib/components/user-card/user-card.less +2 -2
  25. package/lib/test/axe-apca/README.md +19 -0
  26. package/lib/test/axe-apca/src/axe-apca.test.ts +77 -1
  27. package/lib/test/axe-apca/src/axe-apca.ts +16 -8
  28. package/lib/test/test-utils.ts +8 -6
  29. package/package.json +10 -10
@@ -0,0 +1,30 @@
1
+ import { defaultOptions, runComponentTests } from "../../test/test-utils";
2
+ import highlightedFixtures from "./code-block.fixtures";
3
+ import "../../index";
4
+
5
+ describe("code block", () => {
6
+ Object.keys(highlightedFixtures).forEach((language) => {
7
+ runComponentTests({
8
+ type: "a11y",
9
+ tag: "pre",
10
+ baseClass: `s-code-block language-${language}`,
11
+ children: {
12
+ default: highlightedFixtures[language],
13
+ },
14
+ options: {
15
+ ...defaultOptions,
16
+ includeNullModifier: false,
17
+ },
18
+ // TODO new colors should resolve this issue
19
+ skippedTestids: [
20
+ "s-code-block-language-html-light",
21
+ "s-code-block-language-html-highcontrast-light",
22
+ "s-code-block-language-html-highcontrast-dark",
23
+ "s-code-block-language-html-dark",
24
+ "s-code-block-language-css-dark",
25
+ "s-code-block-language-javascript-dark",
26
+ "s-code-block-language-javascript-highcontrast-light",
27
+ ],
28
+ });
29
+ });
30
+ });
@@ -0,0 +1,88 @@
1
+ import type { LanguageFn } from "highlight.js";
2
+ import hljs from "highlight.js/lib/core";
3
+ import hljsJavascript from "highlight.js/lib/languages/javascript";
4
+ import hljsCss from "highlight.js/lib/languages/css";
5
+ import hljsHtml from "highlight.js/lib/languages/xml";
6
+
7
+ const hljsLanguages: Record<string, LanguageFn> = {
8
+ javascript: hljsJavascript,
9
+ css: hljsCss,
10
+ html: hljsHtml,
11
+ };
12
+
13
+ const javascriptFixture = `
14
+ import React, { Component } from 'react'
15
+ import { IP } from '../constants/IP'
16
+ import { withAuth0 } from '@auth0/auth0-react';
17
+
18
+ class AddATournament extends Component {
19
+ componentDidMount() {
20
+ this.myNewListOfAllTournamentsWithAuth()
21
+ }
22
+ }
23
+
24
+ export default withAuth0(AddATournament);
25
+ `;
26
+
27
+ const cssFixture = `
28
+ .s-input,
29
+ .s-textarea {
30
+ -webkit-appearance: none;
31
+ width: 100%;
32
+ margin: 0;
33
+ padding: 0.6em 0.7em;
34
+ border: 1px solid var(--bc-darker);
35
+ border-radius: 3px;
36
+ background-color: var(--white);
37
+ color: var(--fc-dark);
38
+ font-size: 13px;
39
+ font-family: inherit;
40
+ line-height: 1.15384615;
41
+ scrollbar-color: var(--scrollbar) transparent;
42
+ }
43
+ @supports (-webkit-overflow-scrolling: touch) {
44
+ .s-input,
45
+ .s-textarea {
46
+ font-size: 16px;
47
+ padding: 0.36em 0.55em;
48
+ }
49
+ .s-input::-webkit-input-placeholder,
50
+ .s-textarea::-webkit-input-placeholder {
51
+ line-height: normal !important;
52
+ }
53
+ }
54
+ `;
55
+
56
+ const htmlFixture = `
57
+ <form class="d-flex gy4 fd-column">
58
+ <label class="flex--item s-label" for="question-title">Question title</label>
59
+ <div class="d-flex ps-relative">
60
+ <input class="flex--item s-input" type="text" id="question-title" placeholder="e.g. Why doesn’t Stack Overflow use a custom web font?"/>
61
+ </div>
62
+ </form>
63
+ `;
64
+
65
+ const fixtures: Record<string, string> = {
66
+ javascript: javascriptFixture,
67
+ css: cssFixture,
68
+ html: htmlFixture,
69
+ };
70
+
71
+ const highlightFixture = (fixture: string, language: string) => {
72
+ const hljsLanguage = hljsLanguages[language];
73
+ hljs.registerLanguage(language, hljsLanguage);
74
+
75
+ const highlightedCode = hljs.highlight(fixture, { language }).value;
76
+
77
+ return `<code>${highlightedCode}</code>`;
78
+ };
79
+
80
+ const highlightedFixtures = Object.keys(fixtures).reduce(
81
+ (acc, language) => {
82
+ acc[language] = highlightFixture(fixtures[language], language);
83
+ return acc;
84
+ },
85
+ {} as Record<string, string>
86
+ );
87
+
88
+ export default highlightedFixtures;
@@ -0,0 +1,20 @@
1
+ import { defaultOptions, runComponentTests } from "../../test/test-utils";
2
+ import highlightedFixtures from "./code-block.fixtures";
3
+ import "../../index";
4
+
5
+ describe("code block", () => {
6
+ Object.keys(highlightedFixtures).forEach((language) => {
7
+ runComponentTests({
8
+ type: "visual",
9
+ tag: "pre",
10
+ baseClass: `s-code-block language-${language}`,
11
+ children: {
12
+ default: highlightedFixtures[language],
13
+ },
14
+ options: {
15
+ ...defaultOptions,
16
+ includeNullModifier: false,
17
+ },
18
+ });
19
+ });
20
+ });
@@ -0,0 +1,105 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ // TODO note: all accessibility tests here are skipped currently. Revisit in Stacks v2
6
+
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ const template = ({ component, testid, classes = "", icon }: any) => html`
9
+ <div data-testid="${testid}" class="p8 ws4 ${classes}">
10
+ ${component}${icon}
11
+ </div>
12
+ `;
13
+
14
+ const customAttributes = [
15
+ {
16
+ placeholder: "Enter your text here",
17
+ },
18
+ {
19
+ readonly: "",
20
+ },
21
+ {
22
+ disabled: "",
23
+ },
24
+ ];
25
+
26
+ const states = ["has-error", "has-warning", "has-success", "is-readonly"];
27
+ const sizes = ["sm", "md", "lg", "xl"];
28
+ const otherModifiers = ["creditcard", "search"];
29
+
30
+ ["input", "textarea"].map((type) => {
31
+ const children =
32
+ type === "textarea" ? { default: "Enter your text here" } : undefined;
33
+
34
+ describe(type, () => {
35
+ // Base styles w/ value, modifiers
36
+ runComponentTests({
37
+ type: "a11y",
38
+ baseClass: `s-${type}`,
39
+ modifiers: {
40
+ primary: [...sizes, ...otherModifiers],
41
+ },
42
+ tag: type,
43
+ attributes:
44
+ type === "input"
45
+ ? {
46
+ type: "text",
47
+ value: "Text input value",
48
+ }
49
+ : {},
50
+ children,
51
+ template,
52
+ // TODO Stacks v2 should resolve most issues
53
+ skippedTestids: [/s-input/, /s-textarea/],
54
+ });
55
+
56
+ // Base styles w/o value; w/ readonly attr; w/ disabled attr
57
+ customAttributes.forEach((attributes) => {
58
+ const attrString = Object.keys(attributes).sort().join("-");
59
+
60
+ runComponentTests({
61
+ type: "a11y",
62
+ baseClass: `s-${type} ${attrString}`,
63
+ tag: type,
64
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
65
+ // @ts-ignore
66
+ attributes:
67
+ type === "input"
68
+ ? {
69
+ type: "text",
70
+ value: attributes.placeholder
71
+ ? null
72
+ : "Text input value",
73
+ ...attributes,
74
+ }
75
+ : attributes,
76
+ children,
77
+ template,
78
+ // TODO Stacks v2 should resolve most issues
79
+ skippedTestids: [/s-input/, /s-textarea/],
80
+ });
81
+ });
82
+
83
+ // w/ state classes; .is-readonly
84
+ states.forEach((state) => {
85
+ runComponentTests({
86
+ type: "a11y",
87
+ baseClass: `s-${type} state-${state}`,
88
+ tag: type,
89
+ attributes:
90
+ type === "input"
91
+ ? {
92
+ type: "text",
93
+ value: "Text input value",
94
+ }
95
+ : {},
96
+ children,
97
+ template: ({ component, testid }) =>
98
+ template({ component, testid, classes: state }),
99
+ // TODO Stacks v2 should resolve most issues
100
+ skippedTestids: [/s-input/, /s-textarea/],
101
+ });
102
+ });
103
+ // TODO interaction (focus) states?
104
+ });
105
+ });
@@ -0,0 +1,98 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ const template = ({ component, testid, classes = "", icon }: any) => html`
7
+ <div data-testid="${testid}" class="p8 ws4 ${classes}">
8
+ ${component}${icon}
9
+ </div>
10
+ `;
11
+
12
+ const customAttributes = [
13
+ {
14
+ placeholder: "Enter your text here",
15
+ },
16
+ {
17
+ readonly: "",
18
+ },
19
+ {
20
+ disabled: "",
21
+ },
22
+ ] as Record<string, string>[];
23
+
24
+ const states = ["has-error", "has-warning", "has-success", "is-readonly"];
25
+ const sizes = ["sm", "md", "lg", "xl"];
26
+ const otherModifiers = ["creditcard", "search"];
27
+
28
+ ["input", "textarea"].map((type) => {
29
+ const children =
30
+ type === "textarea" ? { default: "Enter your text here" } : undefined;
31
+
32
+ describe(type, () => {
33
+ // Base styles w/ value, modifiers
34
+ runComponentTests({
35
+ type: "visual",
36
+ baseClass: `s-${type}`,
37
+ modifiers: {
38
+ primary: [...sizes, ...otherModifiers],
39
+ },
40
+ tag: type,
41
+ attributes:
42
+ type === "input"
43
+ ? {
44
+ type: "text",
45
+ value: "Text input value",
46
+ }
47
+ : {},
48
+ children,
49
+ template,
50
+ });
51
+
52
+ // Base styles w/o value; w/ readonly attr; w/ disabled attr
53
+ customAttributes.forEach((attributes) => {
54
+ const attrString = Object.keys(attributes).sort().join("-");
55
+ let attr = attributes;
56
+ if (type === "input") {
57
+ attr = {
58
+ type: "text",
59
+ ...attributes,
60
+ };
61
+ if (!attributes.placeholder) {
62
+ attr = {
63
+ value: "Text input value",
64
+ ...attr,
65
+ };
66
+ }
67
+ }
68
+ runComponentTests({
69
+ type: "visual",
70
+ baseClass: `s-${type} ${attrString}`,
71
+ tag: type,
72
+ attributes: attr,
73
+ children,
74
+ template,
75
+ });
76
+ });
77
+
78
+ // w/ state classes; .is-readonly
79
+ states.forEach((state) => {
80
+ runComponentTests({
81
+ type: "visual",
82
+ baseClass: `s-${type} state-${state}`,
83
+ tag: type,
84
+ attributes:
85
+ type === "input"
86
+ ? {
87
+ type: "text",
88
+ value: "Text input value",
89
+ }
90
+ : {},
91
+ children,
92
+ template: ({ component, testid }) =>
93
+ template({ component, testid, classes: state }),
94
+ });
95
+ });
96
+ // TODO interaction (focus) states?
97
+ });
98
+ });
@@ -93,6 +93,7 @@
93
93
  font-weight: normal;
94
94
  line-height: var(--lh-sm);
95
95
  margin-bottom: var(--su16);
96
+ margin-right: var(--su24);
96
97
  }
97
98
 
98
99
  background-color: var(--_mo-bg);
@@ -0,0 +1,80 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ const items = [
6
+ {
7
+ label: "Group 1",
8
+ title: true,
9
+ },
10
+ {
11
+ label: "Product",
12
+ selected: true,
13
+ },
14
+ {
15
+ label: "Email",
16
+ },
17
+ {
18
+ label: "Group 2",
19
+ title: true,
20
+ },
21
+ {
22
+ label: "Content",
23
+ },
24
+ {
25
+ label: "Brand",
26
+ },
27
+ {
28
+ label: "Marketing",
29
+ },
30
+ {
31
+ label: "More selected",
32
+ dropdown: true,
33
+ selected: true,
34
+ },
35
+ {
36
+ label: "More",
37
+ dropdown: true,
38
+ },
39
+ ];
40
+
41
+ const getChildren = (includeTitles = false): string =>
42
+ items
43
+ .map((item) => {
44
+ if (item.title) {
45
+ return includeTitles
46
+ ? `<li class="s-navigation--title">${item.label}</li>`
47
+ : "";
48
+ }
49
+ const classes = `s-navigation--item${
50
+ item.selected ? " is-selected" : ""
51
+ }${item.dropdown ? " s-navigation--item__dropdown" : ""}`;
52
+ return `<li><a href="#" class="${classes}">${item.label}</a></li>`;
53
+ })
54
+ .join("");
55
+
56
+ describe("navigation", () => {
57
+ runComponentTests({
58
+ type: "a11y",
59
+ baseClass: "s-navigation",
60
+ variants: ["vertical", "muted"],
61
+ modifiers: {
62
+ primary: ["scroll", "sm"],
63
+ },
64
+ tag: "ul",
65
+ children: {
66
+ default: getChildren(true),
67
+ },
68
+ template: ({ component, testid }) => html`
69
+ <nav
70
+ class="d-inline-block p8 wmx3"
71
+ aria-label="example-navigation"
72
+ data-testid="${testid}"
73
+ >
74
+ ${component}
75
+ </nav>
76
+ `,
77
+ // TODO new colors should resolve the `.is-selected` failures
78
+ skippedTestids: [/s-navigation/],
79
+ });
80
+ });
@@ -0,0 +1,101 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { defaultOptions, runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ const items = [
6
+ {
7
+ label: "Group 1",
8
+ title: true,
9
+ },
10
+ {
11
+ label: "Product",
12
+ selected: true,
13
+ },
14
+ {
15
+ label: "Email",
16
+ },
17
+ {
18
+ label: "Group 2",
19
+ title: true,
20
+ },
21
+ {
22
+ label: "Content",
23
+ },
24
+ {
25
+ label: "Brand",
26
+ },
27
+ {
28
+ label: "Marketing",
29
+ },
30
+ {
31
+ label: "More selected",
32
+ dropdown: true,
33
+ selected: true,
34
+ },
35
+ {
36
+ label: "More",
37
+ dropdown: true,
38
+ },
39
+ ];
40
+
41
+ const getChildren = (includeTitles = false): string =>
42
+ items
43
+ .map((item) => {
44
+ if (item.title) {
45
+ return includeTitles
46
+ ? `<li class="s-navigation--title">${item.label}</li>`
47
+ : "";
48
+ }
49
+ const classes = `s-navigation--item${
50
+ item.selected ? " is-selected" : ""
51
+ }${item.dropdown ? " s-navigation--item__dropdown" : ""}`;
52
+ return `<li><a href="#" class="${classes}">${item.label}</a></li>`;
53
+ })
54
+ .join("");
55
+
56
+ describe("navigation", () => {
57
+ runComponentTests({
58
+ type: "visual",
59
+ baseClass: "s-navigation",
60
+ variants: ["muted"],
61
+ modifiers: {
62
+ primary: ["scroll", "sm"],
63
+ },
64
+ tag: "ul",
65
+ children: {
66
+ default: getChildren(),
67
+ },
68
+ template: ({ component, testid }) => html`
69
+ <nav
70
+ class="d-inline-block p8 wmx3"
71
+ aria-label="example-navigation"
72
+ data-testid="${testid}"
73
+ >
74
+ ${component}
75
+ </nav>
76
+ `,
77
+ });
78
+
79
+ runComponentTests({
80
+ type: "visual",
81
+ baseClass: "s-navigation",
82
+ variants: ["vertical"],
83
+ tag: "ul",
84
+ children: {
85
+ default: getChildren(true),
86
+ },
87
+ template: ({ component, testid }) => html`
88
+ <nav
89
+ class="d-inline-block p8 ws2"
90
+ aria-label="example-navigation"
91
+ data-testid="${testid}"
92
+ >
93
+ ${component}
94
+ </nav>
95
+ `,
96
+ options: {
97
+ ...defaultOptions,
98
+ includeNullVariant: false,
99
+ },
100
+ });
101
+ });
@@ -0,0 +1,22 @@
1
+ import { runComponentTests } from "../../test/test-utils";
2
+ import "../../index";
3
+
4
+ describe("notice", () => {
5
+ runComponentTests({
6
+ type: "a11y",
7
+ baseClass: "s-notice",
8
+ variants: ["info", "success", "warning", "danger"],
9
+ modifiers: {
10
+ primary: ["important"],
11
+ },
12
+ children: {
13
+ default: `Test notice`,
14
+ },
15
+ tag: "aside",
16
+ skippedTestids: [
17
+ /s-notice-dark/,
18
+ "s-notice-light-success-important",
19
+ "s-notice-light-warning-important",
20
+ ],
21
+ });
22
+ });
@@ -0,0 +1,26 @@
1
+ import { runComponentTests } from "../../test/test-utils";
2
+ import { html } from "@open-wc/testing";
3
+ import "../../index";
4
+
5
+ describe("notice", () => {
6
+ runComponentTests({
7
+ type: "visual",
8
+ baseClass: "s-notice",
9
+ variants: ["info", "success", "warning", "danger"],
10
+ modifiers: {
11
+ primary: ["important"],
12
+ },
13
+ attributes: {
14
+ ariaHidden: "false",
15
+ },
16
+ children: {
17
+ default: `Test notice`,
18
+ },
19
+ tag: "aside",
20
+ template: ({ component, testid }) => html`
21
+ <div class="d-inline-block p8" data-testid="${testid}">
22
+ ${component}
23
+ </div>
24
+ `,
25
+ });
26
+ });
@@ -0,0 +1,31 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ describe("page title", () => {
6
+ runComponentTests({
7
+ type: "a11y",
8
+ baseClass: "s-page-title",
9
+ children: {
10
+ default: `
11
+ <div class="s-page-title--text">
12
+ <nav class="s-breadcrumbs" aria-label="example-breadcrumbs">…</nav>
13
+ <h1 class="s-page-title--header">Page title</h1>
14
+ <p class="s-page-title--description">
15
+ Optional description de Finibus Bonorum et Malorum
16
+ </p>
17
+ </div>
18
+ <div class="s-page-title--actions">
19
+ <button class="s-btn s-btn__filled" type="button">Action</button>
20
+ </div>
21
+ `,
22
+ },
23
+ template: ({ component, testid }) => html`
24
+ <div class="d-block p8 ws6" data-testid="${testid}">
25
+ ${component}
26
+ </div>
27
+ `,
28
+ // TODO new colors should resolve this issue
29
+ skippedTestids: [/s-page-title-dark/, /s-page-title-light/],
30
+ });
31
+ });
@@ -0,0 +1,59 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ const postTitleTemplate = ({ component, testid }: any) => html`
7
+ <div class="d-block p8 ws6" data-testid="${testid}">${component}</div>
8
+ `;
9
+
10
+ const getChildren = ({
11
+ showEverything = false,
12
+ }: {
13
+ showEverything: boolean;
14
+ }) => `
15
+ <div class="s-page-title--text">
16
+ ${
17
+ showEverything
18
+ ? `
19
+ <nav class="s-breadcrumbs" aria-label="example-breadcrumbs">
20
+ <div class="s-breadcrumbs--item">
21
+ <a class="s-breadcrumbs--link">Stack Overflow</a>
22
+ </div>
23
+ </nav>
24
+ `
25
+ : ""
26
+ }
27
+ <h1 class="s-page-title--header">Page title</h1>
28
+ ${
29
+ showEverything
30
+ ? `
31
+ <p class="s-page-title--description">
32
+ Optional description de Finibus Bonorum et Malorum
33
+ </p>
34
+ `
35
+ : ""
36
+ }
37
+ </div>
38
+ ${
39
+ showEverything
40
+ ? `
41
+ <div class="s-page-title--actions">
42
+ <button class="s-btn s-btn__filled" type="button">Action</button>
43
+ </div>
44
+ `
45
+ : ""
46
+ }
47
+ `;
48
+
49
+ describe("page title", () => {
50
+ runComponentTests({
51
+ type: "visual",
52
+ baseClass: "s-page-title",
53
+ children: {
54
+ default: getChildren({ showEverything: false }),
55
+ complete: getChildren({ showEverything: true }),
56
+ },
57
+ template: postTitleTemplate,
58
+ });
59
+ });