@stackoverflow/stacks 2.0.5 → 2.0.7
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/dist/components/modal/modal.d.ts +2 -2
- package/dist/components/table/table.d.ts +2 -2
- package/dist/components/uploader/uploader.d.ts +3 -3
- package/dist/css/stacks.css +10 -10
- package/dist/css/stacks.min.css +1 -1
- package/dist/js/stacks.js +4 -1
- package/dist/js/stacks.min.js +1 -1
- package/lib/components/modal/modal.test.ts +155 -0
- package/lib/components/modal/modal.ts +7 -3
- package/lib/components/navigation/navigation.a11y.test.ts +4 -0
- package/lib/components/pagination/pagination.a11y.test.ts +2 -0
- package/lib/components/table/table.ts +2 -2
- package/lib/components/uploader/uploader.ts +4 -3
- package/lib/exports/__snapshots__/color-mixins.less.test.ts.snap +6 -6
- package/lib/exports/__snapshots__/color.less.test.ts.snap +10 -10
- package/lib/exports/color-sets.less +10 -10
- package/lib/test/assertions.ts +29 -0
- package/lib/test/test-utils.ts +23 -0
- package/package.json +15 -13
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { html, fixture, expect } from "@open-wc/testing";
|
|
2
|
+
import { screen, waitFor } from "@testing-library/dom";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import "../../index";
|
|
5
|
+
|
|
6
|
+
const user = userEvent.setup();
|
|
7
|
+
|
|
8
|
+
const createModal = ({
|
|
9
|
+
hidden = true,
|
|
10
|
+
initialFocusEl,
|
|
11
|
+
}: { hidden?: boolean; initialFocusEl?: ReturnType<typeof html> } = {}) => html`
|
|
12
|
+
<div data-controller="s-modal">
|
|
13
|
+
<button
|
|
14
|
+
class="s-btn"
|
|
15
|
+
data-action="s-modal#show"
|
|
16
|
+
data-testid="trigger">
|
|
17
|
+
Show Modal
|
|
18
|
+
</button>
|
|
19
|
+
|
|
20
|
+
<aside
|
|
21
|
+
class="s-modal"
|
|
22
|
+
id="modal-base"
|
|
23
|
+
tabindex="-1"
|
|
24
|
+
role="dialog"
|
|
25
|
+
aria-labelledby="modal-base-title"
|
|
26
|
+
aria-describedby="modal-base-description"
|
|
27
|
+
aria-hidden="${hidden}"
|
|
28
|
+
data-s-modal-target="modal"
|
|
29
|
+
data-testid="modal">
|
|
30
|
+
<div class="s-modal--dialog" role="document">
|
|
31
|
+
<h1 class="s-modal--header" id="modal-base-title">Title</h1>
|
|
32
|
+
|
|
33
|
+
<p class="s-modal--body">
|
|
34
|
+
<span id="modal-base-description">Description</span>
|
|
35
|
+
<form>
|
|
36
|
+
<input type="text" data-testid="first-focusable-element" />
|
|
37
|
+
${initialFocusEl}
|
|
38
|
+
</form>
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
<div class="d-flex gx8 s-modal--footer">
|
|
42
|
+
<button class="flex--item s-btn s-btn__primary" type="button">Save changes</button>
|
|
43
|
+
<button class="flex--item s-btn" type="button" data-action="s-modal#hide">Cancel</button>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<button
|
|
47
|
+
class="s-btn s-btn__muted s-modal--close"
|
|
48
|
+
type="button"
|
|
49
|
+
aria-label="Close"
|
|
50
|
+
data-action="s-modal#hide"
|
|
51
|
+
data-testid="close-btn">
|
|
52
|
+
Close
|
|
53
|
+
</button>
|
|
54
|
+
</div>
|
|
55
|
+
</aside>
|
|
56
|
+
</div>
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
describe("modal", () => {
|
|
60
|
+
it("should make the modal visible when toggle button is clicked", async () => {
|
|
61
|
+
await fixture(createModal());
|
|
62
|
+
|
|
63
|
+
const modal = await screen.findByTestId("modal");
|
|
64
|
+
const trigger = await screen.findByTestId("trigger");
|
|
65
|
+
|
|
66
|
+
expect(modal).not.to.be.visible;
|
|
67
|
+
|
|
68
|
+
await user.click(trigger);
|
|
69
|
+
|
|
70
|
+
expect(modal).to.be.visible;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should hide the modal when the close button is clicked", async () => {
|
|
74
|
+
await fixture(createModal({ hidden: false }));
|
|
75
|
+
|
|
76
|
+
const modal = await screen.findByTestId("modal");
|
|
77
|
+
const closeBtn = await screen.findByTestId("close-btn");
|
|
78
|
+
|
|
79
|
+
expect(modal).to.be.visible;
|
|
80
|
+
|
|
81
|
+
await user.click(closeBtn);
|
|
82
|
+
|
|
83
|
+
await waitFor(() => expect(modal).not.to.be.visible);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should focus on the first element with `data-s-modal-target"initialFocus"` when modal is shown', async () => {
|
|
87
|
+
await fixture(
|
|
88
|
+
createModal({
|
|
89
|
+
initialFocusEl: html`<input
|
|
90
|
+
type="text"
|
|
91
|
+
data-testid="initialFocus"
|
|
92
|
+
data-s-modal-target="initialFocus"
|
|
93
|
+
/>`,
|
|
94
|
+
})
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const modal = await screen.findByTestId("modal");
|
|
98
|
+
const trigger = await screen.findByTestId("trigger");
|
|
99
|
+
const initialFocusEl = await screen.findByTestId("initialFocus");
|
|
100
|
+
|
|
101
|
+
expect(modal).not.to.be.visible;
|
|
102
|
+
|
|
103
|
+
await user.click(trigger);
|
|
104
|
+
expect(modal).to.be.visible;
|
|
105
|
+
|
|
106
|
+
await waitFor(() => expect(initialFocusEl).to.have.focus);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should focus on the first focusable element when modal is shown and no initialFocus is specified", async () => {
|
|
110
|
+
await fixture(createModal());
|
|
111
|
+
|
|
112
|
+
const modal = await screen.findByTestId("modal");
|
|
113
|
+
const trigger = await screen.findByTestId("trigger");
|
|
114
|
+
const focusableEl = await screen.findByTestId(
|
|
115
|
+
"first-focusable-element"
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
expect(modal).not.to.be.visible;
|
|
119
|
+
expect(focusableEl).not.to.have.focus;
|
|
120
|
+
|
|
121
|
+
await user.click(trigger);
|
|
122
|
+
expect(modal).to.be.visible;
|
|
123
|
+
|
|
124
|
+
await waitFor(() => expect(focusableEl).to.have.focus);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should not change set focus when an element within the modal is already focused", async () => {
|
|
128
|
+
await fixture(createModal());
|
|
129
|
+
|
|
130
|
+
const modal = await screen.findByTestId("modal");
|
|
131
|
+
const trigger = await screen.findByTestId("trigger");
|
|
132
|
+
const firstFocusableEl = await screen.findByTestId(
|
|
133
|
+
"first-focusable-element"
|
|
134
|
+
);
|
|
135
|
+
const closeButton = await screen.findByTestId("close-btn");
|
|
136
|
+
|
|
137
|
+
expect(modal).not.to.be.visible;
|
|
138
|
+
expect(firstFocusableEl).not.to.have.focus;
|
|
139
|
+
|
|
140
|
+
await user.click(trigger);
|
|
141
|
+
expect(modal).to.be.visible;
|
|
142
|
+
|
|
143
|
+
// manually focus on an element within the modal
|
|
144
|
+
closeButton.focus();
|
|
145
|
+
|
|
146
|
+
// wait for s-modal:shown css transition to complete
|
|
147
|
+
await new Promise((resolve) =>
|
|
148
|
+
modal.addEventListener("s-modal:shown", resolve)
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// check that focus stayed on the manually focused element and
|
|
152
|
+
// has not changed to the first focusable element
|
|
153
|
+
expect(closeButton).to.have.focus;
|
|
154
|
+
});
|
|
155
|
+
});
|
|
@@ -3,8 +3,8 @@ import * as Stacks from "../../stacks";
|
|
|
3
3
|
export class ModalController extends Stacks.StacksController {
|
|
4
4
|
static targets = ["modal", "initialFocus"];
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
declare readonly modalTarget: HTMLElement;
|
|
7
|
+
declare readonly initialFocusTargets: HTMLElement[];
|
|
8
8
|
|
|
9
9
|
private _boundClickFn!: (event: MouseEvent) => void;
|
|
10
10
|
private _boundKeypressFn!: (event: KeyboardEvent) => void;
|
|
@@ -228,7 +228,11 @@ export class ModalController extends Stacks.StacksController {
|
|
|
228
228
|
const initialFocus =
|
|
229
229
|
this.firstVisible(this.initialFocusTargets) ??
|
|
230
230
|
this.firstVisible(this.getAllTabbables());
|
|
231
|
-
|
|
231
|
+
|
|
232
|
+
// Only set focus if focus is not already set on an element within the modal
|
|
233
|
+
if (!this.modalTarget.contains(document.activeElement)) {
|
|
234
|
+
initialFocus?.focus();
|
|
235
|
+
}
|
|
232
236
|
},
|
|
233
237
|
{ once: true }
|
|
234
238
|
);
|
|
@@ -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
|
});
|
|
@@ -12,8 +12,8 @@ export enum SortOrder {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export class TableController extends Stacks.StacksController {
|
|
15
|
-
declare columnTarget: HTMLTableCellElement;
|
|
16
|
-
declare columnTargets: HTMLTableCellElement[];
|
|
15
|
+
declare readonly columnTarget: HTMLTableCellElement;
|
|
16
|
+
declare readonly columnTargets: HTMLTableCellElement[];
|
|
17
17
|
|
|
18
18
|
static targets = ["column"];
|
|
19
19
|
|
|
@@ -8,9 +8,10 @@ interface FilePreview {
|
|
|
8
8
|
|
|
9
9
|
export class UploaderController extends Stacks.StacksController {
|
|
10
10
|
static targets = ["input", "previews", "uploader"];
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
|
|
12
|
+
declare readonly inputTarget: HTMLInputElement;
|
|
13
|
+
declare readonly previewsTarget: HTMLElement;
|
|
14
|
+
declare readonly uploaderTarget: HTMLElement;
|
|
14
15
|
|
|
15
16
|
private boundDragEnter!: () => void;
|
|
16
17
|
private boundDragLeave!: () => void;
|
|
@@ -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,
|
|
300
|
-
--orange-200: hsl(27,
|
|
301
|
-
--orange-300: hsl(27,
|
|
302
|
-
--orange-400: hsl(27,
|
|
303
|
-
--orange-500: hsl(27,
|
|
304
|
-
--orange-600: hsl(27,
|
|
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,
|
|
88
|
-
--orange-200: hsl(27,
|
|
89
|
-
--orange-300: hsl(27,
|
|
90
|
-
--orange-400: hsl(27,
|
|
91
|
-
--orange-500: hsl(27,
|
|
92
|
-
--orange-600: hsl(27,
|
|
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,
|
|
467
|
-
--orange-400: hsl(27,
|
|
468
|
-
--orange-500: hsl(27,
|
|
469
|
-
--orange-600: hsl(27,
|
|
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,
|
|
90
|
-
200: hsl(27,
|
|
91
|
-
300: hsl(27,
|
|
92
|
-
400: hsl(27,
|
|
93
|
-
500: hsl(27,
|
|
94
|
-
600: hsl(27,
|
|
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,
|
|
108
|
-
400: hsl(27,
|
|
109
|
-
500: hsl(27,
|
|
110
|
-
600: hsl(27,
|
|
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
|
+
};
|
package/lib/test/test-utils.ts
CHANGED
|
@@ -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.
|
|
8
|
+
"version": "2.0.7",
|
|
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": "^
|
|
48
|
+
"@open-wc/testing": "^4.0.0",
|
|
49
49
|
"@rollup/plugin-commonjs": "^25.0.7",
|
|
50
50
|
"@rollup/plugin-replace": "^5.0.5",
|
|
51
|
-
"@stackoverflow/stacks-editor": "^0.9.
|
|
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
|
-
"@types/cssbeautify": "^0.3.
|
|
55
|
+
"@types/cssbeautify": "^0.3.5",
|
|
56
56
|
"@types/less": "^3.0.5",
|
|
57
|
-
"@
|
|
58
|
-
"@typescript-eslint/
|
|
59
|
-
"@
|
|
60
|
-
"@web/dev-server-
|
|
61
|
-
"@web/
|
|
62
|
-
"@web/test-runner
|
|
63
|
-
"@web/test-runner-
|
|
57
|
+
"@types/mocha": "^10.0.4",
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^6.10.0",
|
|
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.
|
|
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",
|
|
@@ -79,7 +81,7 @@
|
|
|
79
81
|
"mini-css-extract-plugin": "^2.7.6",
|
|
80
82
|
"postcss-less": "^6.0.0",
|
|
81
83
|
"postcss-loader": "^7.3.3",
|
|
82
|
-
"prettier": "^3.0
|
|
84
|
+
"prettier": "^3.1.0",
|
|
83
85
|
"rollup-plugin-postcss": "^4.0.2",
|
|
84
86
|
"stylelint": "^15.11.0",
|
|
85
87
|
"stylelint-config-recommended": "^13.0.0",
|