@noctuatech/uswds 0.0.22 → 0.0.24
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 +4 -8
- 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 +69 -12
- 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 +7 -9
- package/src/lib/input-mask/input-mask.test.ts +17 -13
- 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.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/step.element.ts +27 -29
- package/src/lib/step-indicator/step-indicator.element.ts +1 -1
- package/src/lib/step-indicator/step-indicator.stories.ts +9 -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 +4 -10
- 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 +6 -2
- package/target/lib/input/input.element.js +73 -10
- 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 +6 -7
- package/target/lib/input-mask/input-mask.element.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/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/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/step.element.js +27 -29
- package/target/lib/step-indicator/step/step.element.js.map +1 -1
- package/target/lib/step-indicator/step-indicator.element.js +1 -1
- package/target/lib/step-indicator/step-indicator.stories.d.ts +1 -1
- package/target/lib/step-indicator/step-indicator.stories.js +9 -6
- package/target/lib/step-indicator/step-indicator.stories.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,11 +1,11 @@
|
|
|
1
1
|
import "./button.element.js";
|
|
2
2
|
|
|
3
|
-
import { fixture, html
|
|
3
|
+
import { assert, fixture, html } from "@open-wc/testing";
|
|
4
4
|
|
|
5
|
-
import { BUTTON_VARIANTS, USAButtonElement } from "./button.element.js";
|
|
5
|
+
import { BUTTON_VARIANTS, type USAButtonElement } from "./button.element.js";
|
|
6
6
|
|
|
7
7
|
describe("usa-button", () => {
|
|
8
|
-
for (
|
|
8
|
+
for (const variant of BUTTON_VARIANTS) {
|
|
9
9
|
it("should be accessible", async () => {
|
|
10
10
|
const button = await fixture<USAButtonElement>(html`
|
|
11
11
|
<usa-button variant=${variant}>Hello World</usa-button>
|
|
@@ -5,9 +5,9 @@ import "./card-group/card-group.element.js";
|
|
|
5
5
|
import "./card-header/card-header.element.js";
|
|
6
6
|
import "./card-media/card-media.element.js";
|
|
7
7
|
|
|
8
|
-
import { fixture, html
|
|
8
|
+
import { assert, fixture, html } from "@open-wc/testing";
|
|
9
9
|
|
|
10
|
-
import { USACardElement } from "./card.element.js";
|
|
10
|
+
import type { USACardElement } from "./card.element.js";
|
|
11
11
|
|
|
12
12
|
describe("usa-card", () => {
|
|
13
13
|
it("should be accessible", async () => {
|
|
@@ -16,14 +16,8 @@ declare global {
|
|
|
16
16
|
|
|
17
17
|
:host {
|
|
18
18
|
display: inline-block;
|
|
19
|
-
font-family:
|
|
20
|
-
Source Sans Pro Web,
|
|
21
|
-
Helvetica Neue,
|
|
22
|
-
Helvetica,
|
|
23
|
-
Roboto,
|
|
24
|
-
Arial,
|
|
25
|
-
sans-serif;
|
|
26
19
|
max-width: 30rem;
|
|
20
|
+
position: relative;
|
|
27
21
|
}
|
|
28
22
|
|
|
29
23
|
:host([tiled]) label {
|
|
@@ -71,11 +65,7 @@ declare global {
|
|
|
71
65
|
}
|
|
72
66
|
|
|
73
67
|
input {
|
|
74
|
-
height: 0;
|
|
75
|
-
width: 0;
|
|
76
68
|
position: absolute;
|
|
77
|
-
left: -999em;
|
|
78
|
-
right: auto;
|
|
79
69
|
}
|
|
80
70
|
|
|
81
71
|
input:focus + .checkbox {
|
|
@@ -107,7 +97,7 @@ declare global {
|
|
|
107
97
|
`,
|
|
108
98
|
html`
|
|
109
99
|
<label>
|
|
110
|
-
<input type="checkbox" />
|
|
100
|
+
<input type="checkbox" tabindex="0"/>
|
|
111
101
|
|
|
112
102
|
<div class="checkbox"></div>
|
|
113
103
|
|
|
@@ -130,23 +120,25 @@ export class USACheckboxElement extends HTMLElement {
|
|
|
130
120
|
@attr()
|
|
131
121
|
accessor value = "";
|
|
132
122
|
|
|
123
|
+
@attr()
|
|
124
|
+
accessor required = false;
|
|
125
|
+
|
|
133
126
|
@attr({
|
|
134
127
|
observed: false,
|
|
135
128
|
})
|
|
136
129
|
accessor tiled = false;
|
|
137
130
|
|
|
138
131
|
#checkbox = query("input");
|
|
132
|
+
|
|
139
133
|
#internals = this.attachInternals();
|
|
140
134
|
|
|
141
135
|
connectedCallback() {
|
|
142
136
|
const checkbox = this.#checkbox();
|
|
143
137
|
|
|
144
|
-
if (this.checked) {
|
|
145
|
-
this.#internals.setFormValue(this.value);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
138
|
checkbox.checked = this.checked;
|
|
149
139
|
checkbox.name = this.name;
|
|
140
|
+
|
|
141
|
+
this.#syncFormState();
|
|
150
142
|
}
|
|
151
143
|
|
|
152
144
|
attributeChangedCallback() {
|
|
@@ -154,16 +146,35 @@ export class USACheckboxElement extends HTMLElement {
|
|
|
154
146
|
|
|
155
147
|
checkbox.checked = this.checked;
|
|
156
148
|
checkbox.name = this.name;
|
|
149
|
+
|
|
150
|
+
this.#syncFormState();
|
|
157
151
|
}
|
|
158
152
|
|
|
159
153
|
@listen("change", "input[type=checkbox]")
|
|
160
154
|
onCheckboxChange() {
|
|
161
155
|
const checkbox = this.#checkbox();
|
|
156
|
+
this.checked = checkbox.checked;
|
|
157
|
+
|
|
158
|
+
this.#syncFormState();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
#syncFormState() {
|
|
162
|
+
const checkbox = this.#checkbox();
|
|
162
163
|
|
|
163
164
|
if (checkbox.checked) {
|
|
164
165
|
this.#internals.setFormValue(this.value);
|
|
165
166
|
} else {
|
|
166
167
|
this.#internals.setFormValue(null);
|
|
167
168
|
}
|
|
169
|
+
|
|
170
|
+
if (this.required && !checkbox.checked) {
|
|
171
|
+
this.#internals.setValidity(
|
|
172
|
+
{ valueMissing: true },
|
|
173
|
+
"Please check this box if you want to proceed",
|
|
174
|
+
this.#checkbox(),
|
|
175
|
+
);
|
|
176
|
+
} else {
|
|
177
|
+
this.#internals.setValidity({});
|
|
178
|
+
}
|
|
168
179
|
}
|
|
169
180
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./checkbox.element.js";
|
|
2
2
|
|
|
3
|
-
import { fixture, html
|
|
3
|
+
import { assert, fixture, html } from "@open-wc/testing";
|
|
4
4
|
|
|
5
5
|
describe("usa-checkbox", () => {
|
|
6
6
|
it("should be accessible", async () => {
|
|
@@ -36,12 +36,29 @@ describe("usa-checkbox", () => {
|
|
|
36
36
|
</form>
|
|
37
37
|
`);
|
|
38
38
|
|
|
39
|
-
const checkbox = form.querySelector("usa-checkbox")
|
|
40
|
-
const nativeInput = checkbox
|
|
41
|
-
|
|
39
|
+
const checkbox = form.querySelector("usa-checkbox");
|
|
40
|
+
const nativeInput = checkbox?.shadowRoot?.querySelector("input");
|
|
41
|
+
|
|
42
|
+
if (nativeInput) {
|
|
43
|
+
nativeInput.click();
|
|
44
|
+
}
|
|
42
45
|
|
|
43
46
|
const value = new FormData(form);
|
|
44
47
|
|
|
45
48
|
assert.equal(value.get("enabled"), "test");
|
|
46
49
|
});
|
|
50
|
+
|
|
51
|
+
it("should not submit when not valid", async () => {
|
|
52
|
+
const form = await fixture<HTMLFormElement>(html`
|
|
53
|
+
<form>
|
|
54
|
+
<usa-checkbox name="enabled" value="test" required>
|
|
55
|
+
Hello World
|
|
56
|
+
</usa-checkbox>
|
|
57
|
+
|
|
58
|
+
<button>Submit</button>
|
|
59
|
+
</form>
|
|
60
|
+
`);
|
|
61
|
+
|
|
62
|
+
assert.equal(form.checkValidity(), false);
|
|
63
|
+
});
|
|
47
64
|
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { injectable } from "@joist/di";
|
|
2
2
|
import { attr, css, element, html } from "@joist/element";
|
|
3
3
|
|
|
4
4
|
export class USAConfig {
|
|
5
|
-
iconPath
|
|
5
|
+
iconPath = "";
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
@injectable({
|
|
9
|
-
name: "
|
|
9
|
+
name: "usa-config-ctx",
|
|
10
|
+
provideSelfAs: [USAConfig],
|
|
10
11
|
})
|
|
11
12
|
@element({
|
|
12
13
|
tagName: "usa-config",
|
|
@@ -24,9 +25,4 @@ export class USAConfigElement extends HTMLElement {
|
|
|
24
25
|
name: "icon-path",
|
|
25
26
|
})
|
|
26
27
|
accessor iconPath = "/assets/usa-icons/";
|
|
27
|
-
|
|
28
|
-
@created()
|
|
29
|
-
onInjectorCreated({ providers }: Injector) {
|
|
30
|
-
providers.set(USAConfig, { factory: () => this });
|
|
31
|
-
}
|
|
32
28
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./config.element.js";
|
|
2
2
|
|
|
3
|
-
import { fixture, html
|
|
3
|
+
import { assert, fixture, html } from "@open-wc/testing";
|
|
4
4
|
|
|
5
|
-
import { USAConfigElement } from "./config.element.js";
|
|
5
|
+
import type { USAConfigElement } from "./config.element.js";
|
|
6
6
|
|
|
7
7
|
describe("usa-config", () => {
|
|
8
8
|
it("should be accessible", async () => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./description.element.js";
|
|
2
2
|
|
|
3
|
-
import { fixture, html
|
|
3
|
+
import { assert, fixture, html } from "@open-wc/testing";
|
|
4
4
|
|
|
5
|
-
import { USADescriptionElement } from "./description.element.js";
|
|
5
|
+
import type { USADescriptionElement } from "./description.element.js";
|
|
6
6
|
|
|
7
7
|
describe("usa-description", () => {
|
|
8
8
|
it("should be accessible", async () => {
|
|
@@ -83,16 +83,24 @@ export class USAFileInputPreviewElement extends HTMLElement {
|
|
|
83
83
|
this.onChange();
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
get shadow() {
|
|
87
|
+
if (!this.shadowRoot) {
|
|
88
|
+
throw new Error("no shadow root");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return this.shadowRoot;
|
|
92
|
+
}
|
|
93
|
+
|
|
86
94
|
@effect()
|
|
87
95
|
onChange() {
|
|
88
96
|
const template = this.#template();
|
|
89
97
|
|
|
90
|
-
if (this.files
|
|
98
|
+
if (this.files?.length) {
|
|
91
99
|
this.hidden = false;
|
|
92
100
|
|
|
93
|
-
|
|
101
|
+
const names = new Set<string>();
|
|
94
102
|
|
|
95
|
-
for (
|
|
103
|
+
for (const file of this.files) {
|
|
96
104
|
names.add(file.name);
|
|
97
105
|
|
|
98
106
|
if (!this.#items.has(file.name)) {
|
|
@@ -102,16 +110,19 @@ export class USAFileInputPreviewElement extends HTMLElement {
|
|
|
102
110
|
item.id = file.name;
|
|
103
111
|
item.append(document.createTextNode(file.name));
|
|
104
112
|
|
|
105
|
-
const img = item.querySelector("img")
|
|
106
|
-
|
|
113
|
+
const img = item.querySelector("img");
|
|
114
|
+
|
|
115
|
+
if (img) {
|
|
116
|
+
img.src = URL.createObjectURL(file);
|
|
117
|
+
}
|
|
107
118
|
|
|
108
|
-
this.
|
|
119
|
+
this.shadow.append(item);
|
|
109
120
|
|
|
110
121
|
this.#items.set(file.name, item);
|
|
111
122
|
}
|
|
112
123
|
}
|
|
113
124
|
|
|
114
|
-
for (
|
|
125
|
+
for (const [name, item] of this.#items) {
|
|
115
126
|
if (!names.has(name)) {
|
|
116
127
|
item.remove();
|
|
117
128
|
this.#items.delete(name);
|
|
@@ -3,7 +3,7 @@ import "../../link/link.element.js";
|
|
|
3
3
|
|
|
4
4
|
import { assert, fixture, html } from "@open-wc/testing";
|
|
5
5
|
|
|
6
|
-
import { USAFileInputPreviewElement } from "./file-input-preview.element.js";
|
|
6
|
+
import type { USAFileInputPreviewElement } from "./file-input-preview.element.js";
|
|
7
7
|
|
|
8
8
|
describe("usa-file-input-preview", () => {
|
|
9
9
|
it("should be accessible with no files", async () => {
|
|
@@ -42,7 +42,7 @@ describe("usa-file-input-preview", () => {
|
|
|
42
42
|
`);
|
|
43
43
|
|
|
44
44
|
const previewItems = Array.from(
|
|
45
|
-
shadowRoot
|
|
45
|
+
shadowRoot?.querySelectorAll(".preview-item") ?? [],
|
|
46
46
|
).map((item) => item.textContent?.trim());
|
|
47
47
|
|
|
48
48
|
assert.deepEqual(previewItems, ["image1.jpg", "image2.jpg"]);
|
|
@@ -68,7 +68,7 @@ describe("usa-file-input-preview", () => {
|
|
|
68
68
|
await Promise.resolve();
|
|
69
69
|
|
|
70
70
|
const previewItems = Array.from(
|
|
71
|
-
fileInputPreview.shadowRoot
|
|
71
|
+
fileInputPreview.shadowRoot?.querySelectorAll(".preview-item") ?? [],
|
|
72
72
|
).map((item) => item.textContent?.trim());
|
|
73
73
|
|
|
74
74
|
assert.deepEqual(previewItems, ["image1.jpg"]);
|
|
@@ -86,7 +86,7 @@ describe("usa-file-input-preview", () => {
|
|
|
86
86
|
`);
|
|
87
87
|
|
|
88
88
|
const [first, second] = Array.from(
|
|
89
|
-
shadowRoot
|
|
89
|
+
shadowRoot?.querySelectorAll<HTMLImageElement>(".preview-item img") ?? [],
|
|
90
90
|
).map((item) => item.src.substring(29));
|
|
91
91
|
|
|
92
92
|
// we are just testing that the two hashes are in fact different
|
|
@@ -74,7 +74,7 @@ declare global {
|
|
|
74
74
|
<slot class="label"></slot>
|
|
75
75
|
|
|
76
76
|
<div class="container">
|
|
77
|
-
<input type="file" />
|
|
77
|
+
<input type="file" tabindex="0"/>
|
|
78
78
|
|
|
79
79
|
<div class="box">
|
|
80
80
|
<slot name="description">
|
|
@@ -137,10 +137,10 @@ export class USAFileInputElement extends HTMLElement {
|
|
|
137
137
|
|
|
138
138
|
const formData = new FormData();
|
|
139
139
|
|
|
140
|
-
if (input.files
|
|
140
|
+
if (input.files?.length) {
|
|
141
141
|
box.style.display = "none";
|
|
142
142
|
|
|
143
|
-
for (
|
|
143
|
+
for (const file of input.files) {
|
|
144
144
|
formData.append(this.name, file);
|
|
145
145
|
}
|
|
146
146
|
} else {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./file-input.element.js";
|
|
2
2
|
|
|
3
|
-
import { fixture, html
|
|
3
|
+
import { assert, fixture, html } from "@open-wc/testing";
|
|
4
4
|
|
|
5
|
-
import { USAFileInputElement } from "./file-input.element.js";
|
|
5
|
+
import type { USAFileInputElement } from "./file-input.element.js";
|
|
6
6
|
|
|
7
7
|
describe("usa-file-input", () => {
|
|
8
8
|
it("should be accessible", async () => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { attr, css, element } from "@joist/element";
|
|
2
1
|
import { inject, injectable, injected } from "@joist/di";
|
|
2
|
+
import { attr, css, element } from "@joist/element";
|
|
3
3
|
|
|
4
|
-
import { USAIcon } from "./icon-types.js";
|
|
5
4
|
import { IconService } from "../services/icon.service.js";
|
|
5
|
+
import type { USAIcon } from "./icon-types.js";
|
|
6
6
|
|
|
7
7
|
declare global {
|
|
8
8
|
interface HTMLElementTagNameMap {
|
|
@@ -39,10 +39,6 @@ export class USAIconElement extends HTMLElement {
|
|
|
39
39
|
#icon = inject(IconService);
|
|
40
40
|
#injected = false;
|
|
41
41
|
|
|
42
|
-
get #shadow() {
|
|
43
|
-
return this.shadowRoot!;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
42
|
@injected()
|
|
47
43
|
onInjected() {
|
|
48
44
|
this.#injected = true;
|
|
@@ -58,6 +54,8 @@ export class USAIconElement extends HTMLElement {
|
|
|
58
54
|
async #updateIcon() {
|
|
59
55
|
const icon = this.#icon();
|
|
60
56
|
|
|
61
|
-
|
|
57
|
+
if (this.shadowRoot) {
|
|
58
|
+
this.shadowRoot.append(await icon.getIcon(this.icon));
|
|
59
|
+
}
|
|
62
60
|
}
|
|
63
61
|
}
|
|
@@ -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 { USAIconElement } from "./icon.element.js";
|
|
5
4
|
import { ICON_TYPES } from "./icon-types.js";
|
|
5
|
+
import type { USAIconElement } from "./icon.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 = {
|
|
@@ -24,7 +24,7 @@ export const AllIcons: Story = {
|
|
|
24
24
|
async function copyIcon(icon: string) {
|
|
25
25
|
try {
|
|
26
26
|
await navigator.clipboard.writeText(
|
|
27
|
-
`<usa-icon icon=${icon}></usa-icon
|
|
27
|
+
`<usa-icon icon=${icon}></usa-icon>`,
|
|
28
28
|
);
|
|
29
29
|
alert(`copied markup for ${icon}`);
|
|
30
30
|
} catch (err) {
|
|
@@ -43,7 +43,7 @@ export const AllIcons: Story = {
|
|
|
43
43
|
|
|
44
44
|
${icon}
|
|
45
45
|
</button>
|
|
46
|
-
|
|
46
|
+
`,
|
|
47
47
|
)}`}
|
|
48
48
|
</div>`;
|
|
49
49
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { attr, css, element, html, listen, query, ready } from "@joist/element";
|
|
2
|
-
import { effect, observe } from "@joist/observable";
|
|
2
|
+
import { type Changes, effect, observe } from "@joist/observable";
|
|
3
3
|
|
|
4
|
-
import { MaskableElement } from "../input-mask/maskable.element.js";
|
|
4
|
+
import type { MaskableElement } from "../input-mask/maskable.element.js";
|
|
5
5
|
|
|
6
6
|
declare global {
|
|
7
7
|
interface HTMLElementTagNameMap {
|
|
@@ -28,6 +28,7 @@ declare global {
|
|
|
28
28
|
font-weight: 400;
|
|
29
29
|
max-width: 30rem;
|
|
30
30
|
margin-bottom: 1.5rem;
|
|
31
|
+
position: relative;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
input {
|
|
@@ -49,12 +50,43 @@ declare global {
|
|
|
49
50
|
outline: 0.25rem solid #2491ff;
|
|
50
51
|
outline-offset: 0;
|
|
51
52
|
}
|
|
53
|
+
|
|
54
|
+
slot[name="detail"]::slotted(*) {
|
|
55
|
+
color: #757575;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
slot[name="detail"]::slotted(usa-icon) {
|
|
59
|
+
width: 1.5rem;
|
|
60
|
+
height: 1.5rem;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
slot[name="detail"] {
|
|
64
|
+
display: block;
|
|
65
|
+
position: absolute;
|
|
66
|
+
bottom: 0.21rem;
|
|
67
|
+
left: 0.5rem;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
:host([detail="pfx"]) input {
|
|
71
|
+
padding-left: 2.5rem;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
:host([detail="sfx"]) input {
|
|
75
|
+
padding-right: 2.5rem;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
:host([detail="sfx"]) slot[name="detail"] {
|
|
79
|
+
right: 0.5rem;
|
|
80
|
+
left: auto;
|
|
81
|
+
}
|
|
52
82
|
`,
|
|
53
83
|
html`
|
|
54
84
|
<label>
|
|
85
|
+
<slot name="detail"></slot>
|
|
86
|
+
|
|
55
87
|
<slot></slot>
|
|
56
88
|
|
|
57
|
-
<input />
|
|
89
|
+
<input tabindex="0" />
|
|
58
90
|
</label>
|
|
59
91
|
`,
|
|
60
92
|
],
|
|
@@ -74,6 +106,14 @@ export class USATextInputElement
|
|
|
74
106
|
@attr()
|
|
75
107
|
accessor placeholder = "";
|
|
76
108
|
|
|
109
|
+
@attr()
|
|
110
|
+
accessor required = false;
|
|
111
|
+
|
|
112
|
+
@attr({
|
|
113
|
+
observed: false,
|
|
114
|
+
})
|
|
115
|
+
accessor detail: "pfx" | "sfx" | "" = "";
|
|
116
|
+
|
|
77
117
|
@attr({
|
|
78
118
|
reflect: false,
|
|
79
119
|
})
|
|
@@ -95,13 +135,25 @@ export class USATextInputElement
|
|
|
95
135
|
input.autofocus = this.autofocus;
|
|
96
136
|
}
|
|
97
137
|
|
|
138
|
+
connectedCallback() {
|
|
139
|
+
this.#syncFormState();
|
|
140
|
+
}
|
|
141
|
+
|
|
98
142
|
@effect()
|
|
99
|
-
onChange() {
|
|
143
|
+
onChange(changes: Changes<this>) {
|
|
100
144
|
const input = this.#input();
|
|
101
145
|
|
|
102
146
|
input.value = this.value;
|
|
103
|
-
|
|
104
|
-
|
|
147
|
+
|
|
148
|
+
if (changes.has("selectionStart")) {
|
|
149
|
+
input.selectionStart = this.selectionStart;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (changes.has("selectionEnd")) {
|
|
153
|
+
input.selectionEnd = this.selectionEnd;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this.#syncFormState();
|
|
105
157
|
}
|
|
106
158
|
|
|
107
159
|
@listen("input")
|
|
@@ -111,8 +163,6 @@ export class USATextInputElement
|
|
|
111
163
|
this.value = input.value;
|
|
112
164
|
this.selectionStart = input.selectionStart;
|
|
113
165
|
this.selectionEnd = input.selectionEnd;
|
|
114
|
-
|
|
115
|
-
this.#internals.setFormValue(input.value);
|
|
116
166
|
}
|
|
117
167
|
|
|
118
168
|
attributeChangedCallback(attr: string) {
|
|
@@ -130,11 +180,18 @@ export class USATextInputElement
|
|
|
130
180
|
case "name":
|
|
131
181
|
input.name = this.name;
|
|
132
182
|
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
133
185
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
186
|
+
#syncFormState() {
|
|
187
|
+
const input = this.#input();
|
|
188
|
+
|
|
189
|
+
this.#internals.setFormValue(input.value);
|
|
190
|
+
|
|
191
|
+
if (this.required && !input.value) {
|
|
192
|
+
this.#internals.setValidity({ valueMissing: true }, "Required", input);
|
|
193
|
+
} else {
|
|
194
|
+
this.#internals.setValidity({});
|
|
138
195
|
}
|
|
139
196
|
}
|
|
140
197
|
}
|
|
@@ -10,7 +10,9 @@ const meta = {
|
|
|
10
10
|
render() {
|
|
11
11
|
return html`
|
|
12
12
|
<form>
|
|
13
|
-
<usa-input name="fname" value="Danny" autocomplete="off">
|
|
13
|
+
<usa-input name="fname" value="Danny" autocomplete="off" detail="pfx">
|
|
14
|
+
<usa-icon icon="credit_card" slot="detail"></usa-icon>
|
|
15
|
+
|
|
14
16
|
First name
|
|
15
17
|
</usa-input>
|
|
16
18
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./input.element.js";
|
|
2
2
|
|
|
3
|
-
import { fixture, html, assert } from "@open-wc/testing";
|
|
4
3
|
import { fireEvent } from "@noctuatech-uswds/testing";
|
|
4
|
+
import { assert, fixture, html } from "@open-wc/testing";
|
|
5
5
|
|
|
6
6
|
describe("usa-input", () => {
|
|
7
7
|
it("should be accessible", async () => {
|
|
@@ -35,14 +35,29 @@ describe("usa-input", () => {
|
|
|
35
35
|
</form>
|
|
36
36
|
`);
|
|
37
37
|
|
|
38
|
-
const input = form.querySelector("usa-input")
|
|
39
|
-
const nativeInput = input
|
|
40
|
-
nativeInput.value = "Bar";
|
|
38
|
+
const input = form.querySelector("usa-input");
|
|
39
|
+
const nativeInput = input?.shadowRoot?.querySelector("input");
|
|
41
40
|
|
|
42
|
-
|
|
41
|
+
if (nativeInput) {
|
|
42
|
+
nativeInput.value = "Bar";
|
|
43
|
+
|
|
44
|
+
await fireEvent.input(nativeInput, { bubbles: true });
|
|
45
|
+
}
|
|
43
46
|
|
|
44
47
|
const value = new FormData(form);
|
|
45
48
|
|
|
46
49
|
assert.equal(value.get("fname"), "Bar");
|
|
47
50
|
});
|
|
51
|
+
|
|
52
|
+
it("should not submit when not valid", async () => {
|
|
53
|
+
const form = await fixture<HTMLFormElement>(html`
|
|
54
|
+
<form>
|
|
55
|
+
<usa-input name="fname" required>Hello World</usa-input>
|
|
56
|
+
|
|
57
|
+
<button>Submit</button>
|
|
58
|
+
</form>
|
|
59
|
+
`);
|
|
60
|
+
|
|
61
|
+
assert.equal(form.checkValidity(), false);
|
|
62
|
+
});
|
|
48
63
|
});
|
|
@@ -23,7 +23,7 @@ export function format(value: string, pattern: string): FormattedResult {
|
|
|
23
23
|
let count = 0;
|
|
24
24
|
let formatted = "";
|
|
25
25
|
|
|
26
|
-
for (
|
|
26
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
27
27
|
const patternChar = pattern[i];
|
|
28
28
|
const char = chars[count];
|
|
29
29
|
|
|
@@ -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;
|
|
@@ -54,10 +56,6 @@ export class USAInputMaskElement extends HTMLElement {
|
|
|
54
56
|
input.selectionStart = selectionStart;
|
|
55
57
|
input.selectionEnd = selectionStart;
|
|
56
58
|
}
|
|
57
|
-
|
|
58
|
-
if (prev !== input.value) {
|
|
59
|
-
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
60
|
-
}
|
|
61
59
|
}
|
|
62
60
|
|
|
63
61
|
@listen("keydown")
|