@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,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,11 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { attr, css, element, html
|
|
1
|
+
import { injectable } from "@joist/di";
|
|
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
|
-
@injectable(
|
|
8
|
+
@injectable({
|
|
9
|
+
name: "usa-config-ctx",
|
|
10
|
+
provideSelfAs: [USAConfig],
|
|
11
|
+
})
|
|
9
12
|
@element({
|
|
10
13
|
tagName: "usa-config",
|
|
11
14
|
shadowDom: [
|
|
@@ -22,25 +25,4 @@ export class USAConfigElement extends HTMLElement {
|
|
|
22
25
|
name: "icon-path",
|
|
23
26
|
})
|
|
24
27
|
accessor iconPath = "/assets/usa-icons/";
|
|
25
|
-
|
|
26
|
-
#injector = inject(Injector);
|
|
27
|
-
|
|
28
|
-
@injected()
|
|
29
|
-
onInjected() {
|
|
30
|
-
const { providers } = this.#injector();
|
|
31
|
-
const config = this;
|
|
32
|
-
|
|
33
|
-
const usaConfig: Provider<USAConfig> = {
|
|
34
|
-
provide: USAConfig,
|
|
35
|
-
factory() {
|
|
36
|
-
return {
|
|
37
|
-
get iconPath() {
|
|
38
|
-
return config.iconPath;
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
providers.push(usaConfig);
|
|
45
|
-
}
|
|
46
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,46 +106,63 @@ 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
|
})
|
|
80
120
|
@observe()
|
|
81
121
|
accessor value = "";
|
|
82
122
|
|
|
83
|
-
|
|
84
|
-
|
|
123
|
+
@observe()
|
|
124
|
+
accessor selectionStart: number | null = null;
|
|
85
125
|
|
|
86
|
-
|
|
87
|
-
|
|
126
|
+
@observe()
|
|
127
|
+
accessor selectionEnd: number | null = null;
|
|
88
128
|
|
|
89
129
|
#internals = this.attachInternals();
|
|
90
130
|
#input = query("input");
|
|
91
131
|
|
|
92
|
-
setSelectionRange(start: number, end: number) {
|
|
93
|
-
const input = this.#input();
|
|
94
|
-
|
|
95
|
-
input.setSelectionRange(start, end);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
132
|
@ready()
|
|
99
133
|
onReady() {
|
|
100
134
|
const input = this.#input();
|
|
101
135
|
input.autofocus = this.autofocus;
|
|
102
136
|
}
|
|
103
137
|
|
|
138
|
+
connectedCallback() {
|
|
139
|
+
this.#syncFormState();
|
|
140
|
+
}
|
|
141
|
+
|
|
104
142
|
@effect()
|
|
105
|
-
onChange() {
|
|
143
|
+
onChange(changes: Changes<this>) {
|
|
106
144
|
const input = this.#input();
|
|
145
|
+
|
|
107
146
|
input.value = this.value;
|
|
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();
|
|
108
157
|
}
|
|
109
158
|
|
|
110
159
|
@listen("input")
|
|
111
160
|
onInputChange() {
|
|
112
161
|
const input = this.#input();
|
|
113
162
|
|
|
114
|
-
this.#internals.setFormValue(input.value);
|
|
115
|
-
|
|
116
163
|
this.value = input.value;
|
|
164
|
+
this.selectionStart = input.selectionStart;
|
|
165
|
+
this.selectionEnd = input.selectionEnd;
|
|
117
166
|
}
|
|
118
167
|
|
|
119
168
|
attributeChangedCallback(attr: string) {
|
|
@@ -131,11 +180,18 @@ export class USATextInputElement
|
|
|
131
180
|
case "name":
|
|
132
181
|
input.name = this.name;
|
|
133
182
|
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
134
185
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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({});
|
|
139
195
|
}
|
|
140
196
|
}
|
|
141
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
|
|