@noctuatech/uswds 0.0.21 → 0.0.23
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/assets/uswds.min.js +1 -1
- package/package.json +20 -50
- package/src/lib/accordion/accordion.test.ts +16 -16
- package/src/lib/alert/alert-types.ts +1 -1
- package/src/lib/alert/alert.element.ts +5 -1
- package/src/lib/alert/alert.test.ts +2 -2
- package/src/lib/button/button.element.ts +1 -8
- package/src/lib/button/button.stories.ts +3 -4
- package/src/lib/button/button.test.ts +3 -3
- package/src/lib/card/card.test.ts +2 -2
- package/src/lib/checkbox/checkbox.element.ts +27 -16
- package/src/lib/checkbox/checkbox.stories.ts +1 -1
- package/src/lib/checkbox/checkbox.test.ts +21 -4
- package/src/lib/config/config.element.ts +7 -25
- package/src/lib/config/config.test.ts +2 -2
- package/src/lib/description/description.test.ts +2 -2
- package/src/lib/file-input/file-input-preview/file-input-preview.element.ts +18 -7
- package/src/lib/file-input/file-input-preview/file-input-preview.test.ts +4 -4
- package/src/lib/file-input/file-input.element.ts +3 -3
- package/src/lib/file-input/file-input.test.ts +2 -2
- package/src/lib/icon/icon.element.ts +5 -7
- package/src/lib/icon/icon.stories.ts +3 -3
- package/src/lib/input/input.element.ts +76 -20
- package/src/lib/input/input.stories.ts +3 -1
- package/src/lib/input/input.test.ts +20 -5
- package/src/lib/input-mask/format.ts +1 -1
- package/src/lib/input-mask/input-mask.element.ts +11 -14
- package/src/lib/input-mask/input-mask.stories.ts +0 -1
- package/src/lib/input-mask/input-mask.test.ts +17 -13
- package/src/lib/input-mask/maskable.element.ts +1 -1
- package/src/lib/modal/modal-close/modal-close.test.ts +2 -2
- package/src/lib/modal/modal-heading/modal-heading.test.ts +2 -2
- package/src/lib/modal/modal.test.ts +2 -2
- package/src/lib/radio/context.ts +9 -0
- package/src/lib/radio/radio-option/radio-option.element.ts +45 -26
- package/src/lib/radio/radio-option/radio-option.test.ts +1 -1
- package/src/lib/radio/radio.element.ts +42 -31
- package/src/lib/radio/radio.stories.ts +2 -2
- package/src/lib/radio/radio.test.ts +16 -16
- package/src/lib/select/context.ts +10 -0
- package/src/lib/select/select-option/select-option.element.ts +26 -4
- package/src/lib/select/select.element.ts +37 -18
- package/src/lib/select/select.stories.ts +1 -1
- package/src/lib/select/select.test.ts +32 -13
- package/src/lib/services/icon.service.test.ts +30 -22
- package/src/lib/services/icon.service.ts +11 -3
- package/src/lib/side-nav/side-nav.element.ts +1 -1
- package/src/lib/side-nav/side-nav.test.ts +6 -6
- package/src/lib/step-indicator/step-indicator.test.ts +2 -2
- package/src/lib/summary-box/summary-box.element.ts +0 -7
- package/src/lib/summary-box/summary-box.stories.ts +1 -1
- package/src/lib/summary-box/summary-box.test.ts +2 -2
- package/src/lib/tag/tag.element.ts +0 -7
- package/src/lib/tag/tag.test.ts +2 -2
- package/target/lib/accordion/accordion.test.js +5 -5
- package/target/lib/accordion/accordion.test.js.map +1 -1
- package/target/lib/alert/alert-types.d.ts +1 -1
- package/target/lib/alert/alert.element.d.ts +1 -1
- package/target/lib/alert/alert.element.js +4 -0
- package/target/lib/alert/alert.element.js.map +1 -1
- package/target/lib/alert/alert.test.js +2 -2
- package/target/lib/alert/alert.test.js.map +1 -1
- package/target/lib/button/button.element.js +1 -8
- package/target/lib/button/button.element.js.map +1 -1
- package/target/lib/button/button.stories.js +1 -4
- package/target/lib/button/button.stories.js.map +1 -1
- package/target/lib/button/button.test.js +2 -2
- package/target/lib/button/button.test.js.map +1 -1
- package/target/lib/card/card.test.js +1 -1
- package/target/lib/card/card.test.js.map +1 -1
- package/target/lib/checkbox/checkbox.element.d.ts +1 -0
- package/target/lib/checkbox/checkbox.element.js +24 -16
- package/target/lib/checkbox/checkbox.element.js.map +1 -1
- package/target/lib/checkbox/checkbox.test.js +17 -3
- package/target/lib/checkbox/checkbox.test.js.map +1 -1
- package/target/lib/config/config.element.d.ts +0 -2
- package/target/lib/config/config.element.js +9 -22
- package/target/lib/config/config.element.js.map +1 -1
- package/target/lib/config/config.test.js +1 -1
- package/target/lib/config/config.test.js.map +1 -1
- package/target/lib/description/description.test.js +1 -1
- package/target/lib/description/description.test.js.map +1 -1
- package/target/lib/file-input/file-input-preview/file-input-preview.element.d.ts +1 -0
- package/target/lib/file-input/file-input-preview/file-input-preview.element.js +14 -6
- package/target/lib/file-input/file-input-preview/file-input-preview.element.js.map +1 -1
- package/target/lib/file-input/file-input-preview/file-input-preview.test.js +3 -3
- package/target/lib/file-input/file-input-preview/file-input-preview.test.js.map +1 -1
- package/target/lib/file-input/file-input.element.js +3 -3
- package/target/lib/file-input/file-input.element.js.map +1 -1
- package/target/lib/file-input/file-input.test.js +1 -1
- package/target/lib/file-input/file-input.test.js.map +1 -1
- package/target/lib/icon/icon.element.d.ts +1 -1
- package/target/lib/icon/icon.element.js +4 -5
- package/target/lib/icon/icon.element.js.map +1 -1
- package/target/lib/icon/icon.stories.js.map +1 -1
- package/target/lib/input/input.element.d.ts +8 -4
- package/target/lib/input/input.element.js +92 -17
- package/target/lib/input/input.element.js.map +1 -1
- package/target/lib/input/input.stories.js +3 -1
- package/target/lib/input/input.stories.js.map +1 -1
- package/target/lib/input/input.test.js +16 -4
- package/target/lib/input/input.test.js.map +1 -1
- package/target/lib/input-mask/format.js +1 -1
- package/target/lib/input-mask/input-mask.element.d.ts +1 -1
- package/target/lib/input-mask/input-mask.element.js +10 -11
- package/target/lib/input-mask/input-mask.element.js.map +1 -1
- package/target/lib/input-mask/input-mask.stories.js +0 -1
- package/target/lib/input-mask/input-mask.stories.js.map +1 -1
- package/target/lib/input-mask/input-mask.test.js +12 -8
- package/target/lib/input-mask/input-mask.test.js.map +1 -1
- package/target/lib/input-mask/maskable.element.d.ts +1 -1
- package/target/lib/modal/modal-close/modal-close.test.js +1 -1
- package/target/lib/modal/modal-close/modal-close.test.js.map +1 -1
- package/target/lib/modal/modal-heading/modal-heading.test.js +1 -1
- package/target/lib/modal/modal-heading/modal-heading.test.js.map +1 -1
- package/target/lib/modal/modal.test.js +1 -1
- package/target/lib/modal/modal.test.js.map +1 -1
- package/target/lib/radio/context.d.ts +7 -0
- package/target/lib/radio/context.js +3 -0
- package/target/lib/radio/context.js.map +1 -0
- package/target/lib/radio/radio-option/radio-option.element.d.ts +1 -5
- package/target/lib/radio/radio-option/radio-option.element.js +45 -35
- package/target/lib/radio/radio-option/radio-option.element.js.map +1 -1
- package/target/lib/radio/radio.element.d.ts +5 -5
- package/target/lib/radio/radio.element.js +39 -29
- package/target/lib/radio/radio.element.js.map +1 -1
- package/target/lib/radio/radio.stories.js.map +1 -1
- package/target/lib/radio/radio.test.js +9 -13
- package/target/lib/radio/radio.test.js.map +1 -1
- package/target/lib/select/context.d.ts +6 -0
- package/target/lib/select/context.js +3 -0
- package/target/lib/select/context.js.map +1 -0
- package/target/lib/select/select-option/select-option.element.d.ts +2 -1
- package/target/lib/select/select-option/select-option.element.js +20 -3
- package/target/lib/select/select-option/select-option.element.js.map +1 -1
- package/target/lib/select/select.element.d.ts +5 -2
- package/target/lib/select/select.element.js +33 -18
- package/target/lib/select/select.element.js.map +1 -1
- package/target/lib/select/select.stories.js +1 -1
- package/target/lib/select/select.test.js +24 -8
- package/target/lib/select/select.test.js.map +1 -1
- package/target/lib/services/icon.service.js +7 -1
- package/target/lib/services/icon.service.js.map +1 -1
- package/target/lib/services/icon.service.test.js +30 -22
- package/target/lib/services/icon.service.test.js.map +1 -1
- package/target/lib/side-nav/side-nav.element.js +1 -1
- package/target/lib/side-nav/side-nav.element.js.map +1 -1
- package/target/lib/side-nav/side-nav.test.js +1 -1
- package/target/lib/side-nav/side-nav.test.js.map +1 -1
- package/target/lib/step-indicator/step-indicator.test.js +1 -1
- package/target/lib/step-indicator/step-indicator.test.js.map +1 -1
- package/target/lib/summary-box/summary-box.element.js +0 -7
- package/target/lib/summary-box/summary-box.element.js.map +1 -1
- package/target/lib/summary-box/summary-box.stories.js +1 -1
- package/target/lib/summary-box/summary-box.stories.js.map +1 -1
- package/target/lib/summary-box/summary-box.test.js +1 -1
- package/target/lib/summary-box/summary-box.test.js.map +1 -1
- package/target/lib/tag/tag.element.js +0 -7
- package/target/lib/tag/tag.element.js.map +1 -1
- package/target/lib/tag/tag.test.js +1 -1
- package/target/lib/tag/tag.test.js.map +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { attr, css, element, html, listen } from "@joist/element";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { PATTERN_CHARS, PatternChar, REG_EXPS, format } from "./format.js";
|
|
4
|
+
import type { MaskableElement } from "./maskable.element.js";
|
|
5
5
|
|
|
6
6
|
declare global {
|
|
7
7
|
interface HTMLElementTagNameMap {
|
|
@@ -25,15 +25,17 @@ export class USAInputMaskElement extends HTMLElement {
|
|
|
25
25
|
accessor mask = "";
|
|
26
26
|
|
|
27
27
|
connectedCallback() {
|
|
28
|
-
for (
|
|
28
|
+
for (const input of this.querySelectorAll<MaskableElement>("[mask]")) {
|
|
29
29
|
const { formatted } = format(input.value, this.#getMaskFor(input));
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
if (formatted) {
|
|
32
|
+
input.value = formatted;
|
|
33
|
+
}
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
@listen("input")
|
|
36
|
-
|
|
38
|
+
onInput(e: Event) {
|
|
37
39
|
const input = e.target as MaskableElement;
|
|
38
40
|
const selectionStart = input.selectionStart || 0;
|
|
39
41
|
const prev = input.value;
|
|
@@ -46,18 +48,13 @@ export class USAInputMaskElement extends HTMLElement {
|
|
|
46
48
|
const offset = input.value.length - prev.length;
|
|
47
49
|
const maskChar = mask[selectionStart - 1] as PatternChar | undefined;
|
|
48
50
|
|
|
49
|
-
// This is a hack to make sure that changes are propagated appropriately
|
|
50
|
-
await Promise.resolve();
|
|
51
|
-
|
|
52
51
|
// check if the current value is not a space for characters and has an offset greater then 0
|
|
53
52
|
if (maskChar && !PATTERN_CHARS.includes(maskChar) && offset > 0) {
|
|
54
|
-
input.
|
|
53
|
+
input.selectionStart = selectionStart + offset;
|
|
54
|
+
input.selectionEnd = selectionStart + offset;
|
|
55
55
|
} else {
|
|
56
|
-
input.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (prev !== input.value) {
|
|
60
|
-
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
56
|
+
input.selectionStart = selectionStart;
|
|
57
|
+
input.selectionEnd = selectionStart;
|
|
61
58
|
}
|
|
62
59
|
}
|
|
63
60
|
|
|
@@ -4,7 +4,7 @@ import "../input/input.element.js";
|
|
|
4
4
|
import { assert, fixture, html } from "@open-wc/testing";
|
|
5
5
|
|
|
6
6
|
import { format } from "./format.js";
|
|
7
|
-
import { USAInputMaskElement } from "./input-mask.element.js";
|
|
7
|
+
import type { USAInputMaskElement } from "./input-mask.element.js";
|
|
8
8
|
|
|
9
9
|
describe("format", () => {
|
|
10
10
|
it("should retrn the correct raw value", () => {
|
|
@@ -51,9 +51,9 @@ describe("usa-input-mask", () => {
|
|
|
51
51
|
</usa-input-mask>
|
|
52
52
|
`);
|
|
53
53
|
|
|
54
|
-
const input = el.querySelector("input")
|
|
54
|
+
const input = el.querySelector("input");
|
|
55
55
|
|
|
56
|
-
assert.equal(input
|
|
56
|
+
assert.equal(input?.value, "(123) 456-7890");
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
it("should update value when on input event", async () => {
|
|
@@ -63,12 +63,14 @@ describe("usa-input-mask", () => {
|
|
|
63
63
|
</usa-input-mask>
|
|
64
64
|
`);
|
|
65
65
|
|
|
66
|
-
const input = el.querySelector("input")
|
|
66
|
+
const input = el.querySelector("input");
|
|
67
67
|
|
|
68
|
-
input
|
|
69
|
-
|
|
68
|
+
if (input) {
|
|
69
|
+
input.value = "8888888888";
|
|
70
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
71
|
+
}
|
|
70
72
|
|
|
71
|
-
assert.equal(input
|
|
73
|
+
assert.equal(input?.value, "(888) 888-8888");
|
|
72
74
|
});
|
|
73
75
|
});
|
|
74
76
|
|
|
@@ -80,9 +82,9 @@ describe("usa-input-mask with usa-input", () => {
|
|
|
80
82
|
</usa-input-mask>
|
|
81
83
|
`);
|
|
82
84
|
|
|
83
|
-
const input = el.querySelector("usa-input")
|
|
85
|
+
const input = el.querySelector("usa-input");
|
|
84
86
|
|
|
85
|
-
assert.equal(input
|
|
87
|
+
assert.equal(input?.value, "(123) 456-7890");
|
|
86
88
|
});
|
|
87
89
|
|
|
88
90
|
it("should update value when on input event", async () => {
|
|
@@ -96,11 +98,13 @@ describe("usa-input-mask with usa-input", () => {
|
|
|
96
98
|
</usa-input-mask>
|
|
97
99
|
`);
|
|
98
100
|
|
|
99
|
-
const input = el.querySelector("usa-input")
|
|
101
|
+
const input = el.querySelector("usa-input");
|
|
100
102
|
|
|
101
|
-
input
|
|
102
|
-
|
|
103
|
+
if (input) {
|
|
104
|
+
input.value = "8888888888";
|
|
105
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
106
|
+
}
|
|
103
107
|
|
|
104
|
-
assert.equal(input
|
|
108
|
+
assert.equal(input?.value, "(888) 888-8888");
|
|
105
109
|
});
|
|
106
110
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./modal-close.element.js";
|
|
2
2
|
|
|
3
|
-
import { fixture, html
|
|
3
|
+
import { assert, fixture, html } from "@open-wc/testing";
|
|
4
4
|
|
|
5
|
-
import { USAModalCloseElement } from "./modal-close.element.js";
|
|
5
|
+
import type { USAModalCloseElement } from "./modal-close.element.js";
|
|
6
6
|
|
|
7
7
|
describe("usa-modal-close", () => {
|
|
8
8
|
it("should be accessible", async () => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./modal-heading.element.js";
|
|
2
2
|
|
|
3
|
-
import { fixture, html
|
|
3
|
+
import { assert, fixture, html } from "@open-wc/testing";
|
|
4
4
|
|
|
5
|
-
import { USAModalHeadingElement } from "./modal-heading.element.js";
|
|
5
|
+
import type { USAModalHeadingElement } from "./modal-heading.element.js";
|
|
6
6
|
|
|
7
7
|
describe("usa-modal-heading", () => {
|
|
8
8
|
it("should be accessible", async () => {
|
|
@@ -2,9 +2,9 @@ import "./modal.element.js";
|
|
|
2
2
|
import "./modal-heading/modal-heading.element.js";
|
|
3
3
|
import "./modal-close/modal-close.element.js";
|
|
4
4
|
|
|
5
|
-
import { fixture, html
|
|
5
|
+
import { assert, fixture, html } from "@open-wc/testing";
|
|
6
6
|
|
|
7
|
-
import { USAModalElement } from "./modal.element.js";
|
|
7
|
+
import type { USAModalElement } from "./modal.element.js";
|
|
8
8
|
|
|
9
9
|
describe("usa-modal", () => {
|
|
10
10
|
it("should be accessible", async () => {
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { attr, css, element, html } from "@joist/element";
|
|
1
|
+
import { attr, css, element, html, query } from "@joist/element";
|
|
2
|
+
|
|
3
|
+
import { inject, injectable, injected } from "@joist/di";
|
|
4
|
+
import { RADIO_CTX } from "../context.js";
|
|
2
5
|
|
|
3
6
|
declare global {
|
|
4
7
|
interface HTMLElementTagNameMap {
|
|
@@ -6,6 +9,9 @@ declare global {
|
|
|
6
9
|
}
|
|
7
10
|
}
|
|
8
11
|
|
|
12
|
+
@injectable({
|
|
13
|
+
name: "usa-radio-option-ctx",
|
|
14
|
+
})
|
|
9
15
|
@element({
|
|
10
16
|
tagName: "usa-radio-option",
|
|
11
17
|
shadowDom: [
|
|
@@ -16,49 +22,62 @@ declare global {
|
|
|
16
22
|
margin-top: 0.05rem;
|
|
17
23
|
}
|
|
18
24
|
`,
|
|
19
|
-
html
|
|
25
|
+
html`
|
|
26
|
+
<!-- This label will be moved to the shadow dom of its parent -->
|
|
27
|
+
<label>
|
|
28
|
+
<input type="radio" tabindex="0" />
|
|
29
|
+
<slot name="reserved"></slot>
|
|
30
|
+
</label>
|
|
31
|
+
|
|
32
|
+
<slot></slot>
|
|
33
|
+
`,
|
|
20
34
|
],
|
|
21
35
|
})
|
|
22
36
|
export class USARadioOptionElement extends HTMLElement {
|
|
23
37
|
@attr()
|
|
24
38
|
accessor value = "";
|
|
25
39
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
accessor checked = false;
|
|
40
|
+
#label = query("label");
|
|
41
|
+
#input = query("input");
|
|
42
|
+
#slot = query("slot");
|
|
43
|
+
#radio = inject(RADIO_CTX);
|
|
31
44
|
|
|
32
|
-
|
|
45
|
+
#observer = new MutationObserver(() => {
|
|
46
|
+
const input = this.#input();
|
|
47
|
+
const radio = this.#radio();
|
|
33
48
|
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
input.name = radio.name;
|
|
50
|
+
input.checked = radio.value === this.value;
|
|
51
|
+
});
|
|
36
52
|
|
|
37
|
-
|
|
38
|
-
|
|
53
|
+
attributeChangedCallback() {
|
|
54
|
+
const input = this.#input();
|
|
55
|
+
const slot = this.#slot();
|
|
39
56
|
|
|
40
|
-
this
|
|
57
|
+
this.slot = this.value;
|
|
41
58
|
|
|
42
|
-
|
|
59
|
+
slot.name = this.value;
|
|
60
|
+
input.value = this.value;
|
|
43
61
|
}
|
|
44
62
|
|
|
45
|
-
|
|
46
|
-
|
|
63
|
+
@injected()
|
|
64
|
+
onInjected() {
|
|
65
|
+
const input = this.#input();
|
|
66
|
+
const radio = this.#radio();
|
|
47
67
|
|
|
48
|
-
this.#
|
|
49
|
-
this.#input.value = this.value;
|
|
50
|
-
this.#input.checked = this.checked;
|
|
68
|
+
radio.addRadioOption(this.#label());
|
|
51
69
|
|
|
52
|
-
|
|
53
|
-
|
|
70
|
+
input.name = radio.name;
|
|
71
|
+
input.checked = radio.value === this.value;
|
|
54
72
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
);
|
|
73
|
+
this.#observer.observe(radio, {
|
|
74
|
+
attributeFilter: ["value", "name"],
|
|
75
|
+
});
|
|
59
76
|
}
|
|
60
77
|
|
|
61
78
|
disconnectedCallback() {
|
|
62
|
-
this.
|
|
79
|
+
this.#label().remove();
|
|
80
|
+
|
|
81
|
+
this.#observer.disconnect();
|
|
63
82
|
}
|
|
64
83
|
}
|
|
@@ -3,7 +3,7 @@ import "./radio-option.element.js";
|
|
|
3
3
|
|
|
4
4
|
import { assert, fixture, html } from "@open-wc/testing";
|
|
5
5
|
|
|
6
|
-
import { USARadioOptionElement } from "./radio-option.element.js";
|
|
6
|
+
import type { USARadioOptionElement } from "./radio-option.element.js";
|
|
7
7
|
|
|
8
8
|
describe("usa-radio-option", () => {
|
|
9
9
|
it("should map value to slot", async () => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { injectable } from "@joist/di";
|
|
2
|
+
import { attr, css, element, html, listen, query } from "@joist/element";
|
|
2
3
|
|
|
3
|
-
import type
|
|
4
|
+
import { RADIO_CTX, type RadioContainer } from "./context.js";
|
|
4
5
|
|
|
5
6
|
declare global {
|
|
6
7
|
interface HTMLElementTagNameMap {
|
|
@@ -8,6 +9,10 @@ declare global {
|
|
|
8
9
|
}
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
@injectable({
|
|
13
|
+
name: "usa-radio-ctx",
|
|
14
|
+
provideSelfAs: [RADIO_CTX],
|
|
15
|
+
})
|
|
11
16
|
@element({
|
|
12
17
|
tagName: "usa-radio",
|
|
13
18
|
shadowDom: [
|
|
@@ -24,12 +29,11 @@ declare global {
|
|
|
24
29
|
display: flex;
|
|
25
30
|
cursor: pointer;
|
|
26
31
|
gap: 0.5rem;
|
|
32
|
+
position: relative;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
input {
|
|
30
36
|
position: absolute;
|
|
31
|
-
left: -999em;
|
|
32
|
-
right: auto;
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
label::before {
|
|
@@ -42,6 +46,8 @@ declare global {
|
|
|
42
46
|
background: #fff;
|
|
43
47
|
box-shadow: 0 0 0 2px #1b1b1b;
|
|
44
48
|
flex: 0 0 1.25rem;
|
|
49
|
+
position: relative;
|
|
50
|
+
z-index: 1000;
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
label:has(input:checked)::before {
|
|
@@ -77,10 +83,14 @@ declare global {
|
|
|
77
83
|
display: flex;
|
|
78
84
|
}
|
|
79
85
|
`,
|
|
80
|
-
html
|
|
86
|
+
html`
|
|
87
|
+
<slot name="legend" id="legend" tabindex="-1"></slot>
|
|
88
|
+
|
|
89
|
+
<slot></slot>
|
|
90
|
+
`,
|
|
81
91
|
],
|
|
82
92
|
})
|
|
83
|
-
export class USARadioElement extends HTMLElement {
|
|
93
|
+
export class USARadioElement extends HTMLElement implements RadioContainer {
|
|
84
94
|
static formAssociated = true;
|
|
85
95
|
|
|
86
96
|
@attr()
|
|
@@ -89,49 +99,50 @@ export class USARadioElement extends HTMLElement {
|
|
|
89
99
|
@attr()
|
|
90
100
|
accessor name = "";
|
|
91
101
|
|
|
102
|
+
@attr()
|
|
103
|
+
accessor required = false;
|
|
104
|
+
|
|
92
105
|
@attr({
|
|
93
106
|
observed: false,
|
|
94
107
|
})
|
|
95
108
|
accessor tiled = false;
|
|
96
109
|
|
|
97
|
-
|
|
98
|
-
|
|
110
|
+
#internals = this.attachInternals();
|
|
111
|
+
#legend = query("#legend");
|
|
112
|
+
|
|
113
|
+
connectedCallback() {
|
|
114
|
+
this.#syncFormState();
|
|
99
115
|
}
|
|
100
116
|
|
|
101
|
-
|
|
117
|
+
addRadioOption(el: HTMLElement) {
|
|
118
|
+
this.shadowRoot?.append(el);
|
|
119
|
+
|
|
120
|
+
this.#syncFormState();
|
|
121
|
+
}
|
|
102
122
|
|
|
103
123
|
@listen("change")
|
|
104
124
|
onChange(e: Event) {
|
|
105
125
|
if (e.target instanceof HTMLInputElement) {
|
|
106
126
|
if (e.target.checked) {
|
|
107
127
|
this.value = e.target.value;
|
|
108
|
-
this.#internals.setFormValue(e.target.value);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
connectedCallback() {
|
|
114
|
-
if (this.value) {
|
|
115
|
-
this.#internals.setFormValue(this.value);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
128
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
radio.checked = radio.value === this.value;
|
|
122
|
-
radio.name = this.name;
|
|
129
|
+
this.#syncFormState();
|
|
130
|
+
}
|
|
123
131
|
}
|
|
124
132
|
}
|
|
125
133
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
#syncFormState() {
|
|
135
|
+
this.#internals.setFormValue(this.value);
|
|
136
|
+
this.#internals.setValidity({});
|
|
129
137
|
|
|
130
|
-
|
|
138
|
+
if (this.required && !this.value) {
|
|
139
|
+
const input = this.shadowRoot?.querySelector("input");
|
|
131
140
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
141
|
+
this.#internals.setValidity(
|
|
142
|
+
{ valueMissing: true },
|
|
143
|
+
"Please select an option if you want to proceed",
|
|
144
|
+
input ?? this.#legend(),
|
|
145
|
+
);
|
|
146
|
+
}
|
|
136
147
|
}
|
|
137
148
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@storybook/web-components";
|
|
2
2
|
import { html } from "lit";
|
|
3
3
|
|
|
4
|
-
import type { USARadioElement } from "./radio.element.js";
|
|
5
4
|
import { when } from "lit/directives/when.js";
|
|
5
|
+
import type { USARadioElement } from "./radio.element.js";
|
|
6
6
|
|
|
7
7
|
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
|
|
8
8
|
const meta = {
|
|
@@ -25,7 +25,7 @@ const meta = {
|
|
|
25
25
|
Frederick Douglass
|
|
26
26
|
${when(
|
|
27
27
|
args.description,
|
|
28
|
-
() => html`<usa-description>${args.description}</usa-description
|
|
28
|
+
() => html`<usa-description>${args.description}</usa-description>`,
|
|
29
29
|
)}
|
|
30
30
|
</usa-radio-option>
|
|
31
31
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "./radio.element.js";
|
|
2
2
|
import "./radio-option/radio-option.element.js";
|
|
3
3
|
|
|
4
|
-
import { fixture, html
|
|
4
|
+
import { assert, fixture, html } from "@open-wc/testing";
|
|
5
5
|
|
|
6
|
-
import { USARadioElement } from "./radio.element.js";
|
|
6
|
+
import type { USARadioElement } from "./radio.element.js";
|
|
7
7
|
|
|
8
8
|
describe("usa-radio", () => {
|
|
9
9
|
it("should be accessible", async () => {
|
|
@@ -53,9 +53,9 @@ describe("usa-radio", () => {
|
|
|
53
53
|
</form>
|
|
54
54
|
`);
|
|
55
55
|
|
|
56
|
-
const nativeInputs =
|
|
57
|
-
.querySelector("usa-radio")
|
|
58
|
-
|
|
56
|
+
const nativeInputs =
|
|
57
|
+
form.querySelector("usa-radio")?.shadowRoot?.querySelectorAll("input") ??
|
|
58
|
+
[];
|
|
59
59
|
|
|
60
60
|
assert.deepEqual(
|
|
61
61
|
Array.from(nativeInputs).map((input) => input.value),
|
|
@@ -64,7 +64,7 @@ describe("usa-radio", () => {
|
|
|
64
64
|
"frederick-douglass",
|
|
65
65
|
"booker-t-washington",
|
|
66
66
|
"george-washington-carver",
|
|
67
|
-
]
|
|
67
|
+
],
|
|
68
68
|
);
|
|
69
69
|
});
|
|
70
70
|
|
|
@@ -95,13 +95,13 @@ describe("usa-radio", () => {
|
|
|
95
95
|
|
|
96
96
|
options[2].remove();
|
|
97
97
|
|
|
98
|
-
const nativeInputs =
|
|
99
|
-
.querySelector("usa-radio")
|
|
100
|
-
|
|
98
|
+
const nativeInputs =
|
|
99
|
+
form.querySelector("usa-radio")?.shadowRoot?.querySelectorAll("input") ??
|
|
100
|
+
[];
|
|
101
101
|
|
|
102
102
|
assert.deepEqual(
|
|
103
103
|
Array.from(nativeInputs).map((input) => input.value),
|
|
104
|
-
["sojourner-truth", "frederick-douglass", "george-washington-carver"]
|
|
104
|
+
["sojourner-truth", "frederick-douglass", "george-washington-carver"],
|
|
105
105
|
);
|
|
106
106
|
});
|
|
107
107
|
|
|
@@ -130,9 +130,9 @@ describe("usa-radio", () => {
|
|
|
130
130
|
|
|
131
131
|
const value = new FormData(form);
|
|
132
132
|
|
|
133
|
-
const nativeInputs =
|
|
134
|
-
.querySelector("usa-radio")
|
|
135
|
-
|
|
133
|
+
const nativeInputs =
|
|
134
|
+
form.querySelector("usa-radio")?.shadowRoot?.querySelectorAll("input") ??
|
|
135
|
+
[];
|
|
136
136
|
|
|
137
137
|
assert.equal(nativeInputs[1].checked, true);
|
|
138
138
|
assert.equal(value.get("historical-figures"), "frederick-douglass");
|
|
@@ -161,9 +161,9 @@ describe("usa-radio", () => {
|
|
|
161
161
|
</form>
|
|
162
162
|
`);
|
|
163
163
|
|
|
164
|
-
const nativeInputs =
|
|
165
|
-
.querySelector("usa-radio")
|
|
166
|
-
|
|
164
|
+
const nativeInputs =
|
|
165
|
+
form.querySelector("usa-radio")?.shadowRoot?.querySelectorAll("input") ??
|
|
166
|
+
[];
|
|
167
167
|
|
|
168
168
|
nativeInputs[3].click();
|
|
169
169
|
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { attr, css, element, html, listen } from "@joist/element";
|
|
2
2
|
|
|
3
|
+
import { inject, injectable, injected } from "@joist/di";
|
|
4
|
+
import { SELECT_CONTEXT } from "../context.js";
|
|
5
|
+
|
|
3
6
|
declare global {
|
|
4
7
|
interface HTMLElementTagNameMap {
|
|
5
8
|
"usa-select-option": USASelecOptionElement;
|
|
@@ -17,20 +20,37 @@ declare global {
|
|
|
17
20
|
html`<slot></slot>`,
|
|
18
21
|
],
|
|
19
22
|
})
|
|
23
|
+
@injectable()
|
|
20
24
|
export class USASelecOptionElement extends HTMLElement {
|
|
21
25
|
@attr()
|
|
22
26
|
accessor value = "";
|
|
23
27
|
|
|
24
28
|
readonly option = document.createElement("option");
|
|
25
29
|
|
|
30
|
+
#select = inject(SELECT_CONTEXT);
|
|
31
|
+
|
|
32
|
+
#observer = new MutationObserver(() => {
|
|
33
|
+
const { value } = this.#select();
|
|
34
|
+
|
|
35
|
+
this.option.selected = value === this.value;
|
|
36
|
+
});
|
|
37
|
+
|
|
26
38
|
attributeChangedCallback() {
|
|
27
39
|
this.option.value = this.value;
|
|
28
40
|
}
|
|
29
41
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
@injected()
|
|
43
|
+
onInjected() {
|
|
44
|
+
const select = this.#select();
|
|
45
|
+
|
|
46
|
+
this.option.selected = select.value === this.value;
|
|
47
|
+
|
|
48
|
+
select.addSelectOption(this.option);
|
|
49
|
+
|
|
50
|
+
this.#observer.observe(select, {
|
|
51
|
+
attributes: true,
|
|
52
|
+
attributeFilter: ["value"],
|
|
53
|
+
});
|
|
34
54
|
}
|
|
35
55
|
|
|
36
56
|
@listen("slotchange")
|
|
@@ -39,6 +59,8 @@ export class USASelecOptionElement extends HTMLElement {
|
|
|
39
59
|
}
|
|
40
60
|
|
|
41
61
|
disconnectedCallback() {
|
|
62
|
+
this.#observer.disconnect();
|
|
63
|
+
|
|
42
64
|
this.option.remove();
|
|
43
65
|
}
|
|
44
66
|
}
|