Skip to content

Commit 20c2938

Browse files
committed
Merge remote-tracking branch 'origin/main' into benelan/8000-form-validation-ui
* origin/main: build: update browserslist db (#8565) fix(input, input-number, input-text): restore focus on input after browser validation error is displayed and user continues typing (#8563) docs(various components): consistent api description refs (#8550)
2 parents eb96ae6 + 35cb235 commit 20c2938

File tree

20 files changed

+148
-47
lines changed

20 files changed

+148
-47
lines changed

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/calcite-components/src/components/accordion/accordion.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,13 @@ export class Accordion {
4040
@Prop({ reflect: true }) scale: Scale = "m";
4141

4242
/**
43-
* Specifies the selection mode - `"multiple"` (allow any number of open items), `"single"` (allow one open item),
44-
* or `"single-persist"` (allow and require one open item).
43+
* Specifies the selection mode of the component, where:
44+
*
45+
* `"multiple"` allows any number of selections,
46+
*
47+
* `"single"` allows only one selection, and
48+
*
49+
* `"single-persist"` allows one selection and prevents de-selection.
4550
*/
4651
@Prop({ reflect: true }) selectionMode: Extract<
4752
"single" | "single-persist" | "multiple",

packages/calcite-components/src/components/chip-group/chip-group.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,14 @@ export class ChipGroup implements InteractiveComponent {
5050
@Prop({ reflect: true }) scale: Scale = "m";
5151

5252
/**
53-
* Specifies the selection mode of the component:
53+
* Specifies the selection mode of the component, where:
54+
*
5455
* `"multiple"` allows any number of selections,
56+
*
5557
* `"single"` allows only one selection,
56-
* `"single-persist"` allow and require one selected item,
58+
*
59+
* `"single-persist"` allows one selection and prevents de-selection, and
60+
*
5761
* `"none"` does not allow any selections.
5862
*/
5963
@Prop({ reflect: true }) selectionMode: Extract<

packages/calcite-components/src/components/combobox-item/combobox-item.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,15 @@ export class ComboboxItem implements ConditionalSlotComponent, InteractiveCompon
8484
@Prop({ reflect: true }) filterDisabled: boolean;
8585

8686
/**
87-
* Specifies the selection mode:
88-
* - "multiple" allows any number of selected items (default),
89-
* - "single" allows only one selection,
90-
* - "single-persist" allow and require one open item,
91-
* - "ancestors" is like multiple, but shows ancestors of selected items as selected, with only deepest children shown in chips.
87+
* Specifies the selection mode of the component, where:
88+
*
89+
* `"multiple"` allows any number of selections,
90+
*
91+
* `"single"` allows only one selection,
92+
*
93+
* `"single-persist"` allows one selection and prevents de-selection, and
94+
*
95+
* `"ancestors"` allows multiple selections, but shows ancestors of selected items as selected, with only deepest children shown in chips.
9296
*
9397
* @internal
9498
*/

packages/calcite-components/src/components/combobox/combobox.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,11 +218,15 @@ export class Combobox
218218
@Prop({ reflect: true }) required = false;
219219

220220
/**
221-
* Specifies the selection mode:
222-
* `"multiple"` allows any number of selected items,
221+
* Specifies the selection mode of the component, where:
222+
*
223+
* `"multiple"` allows any number of selections,
224+
*
223225
* `"single"` allows only one selection,
224-
* `"single-persist"` allow and require one open item,
225-
* `"ancestors"` is like multiple, but shows ancestors of selected items as selected, with only deepest children shown in chips.
226+
*
227+
* `"single-persist"` allows one selection and prevents de-selection, and
228+
*
229+
* `"ancestors"` allows multiple selections, but shows ancestors of selected items as selected, with only deepest children shown in chips.
226230
*/
227231
@Prop({ reflect: true }) selectionMode: Extract<
228232
"single" | "single-persist" | "ancestors" | "multiple",

packages/calcite-components/src/components/dropdown-group/dropdown-group.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,13 @@ export class DropdownGroup {
4343
@Prop() scale: Scale = "m";
4444

4545
/**
46-
* Specifies the selection mode for `calcite-dropdown-item` children:
47-
* `"multiple"` allows any number of selected items,
48-
* `"single"` allows only one selection,
49-
* `"none"` doesn't allow for any selection.
46+
* Specifies the selection mode of the component, where:
47+
*
48+
* `"multiple"` allows any number of selections,
49+
*
50+
* `"single"` allows only one selection, and
51+
*
52+
* `"none"` does not allow any selections.
5053
*/
5154
@Prop({ reflect: true }) selectionMode: Extract<"none" | "single" | "multiple", SelectionMode> =
5255
"single";

packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ export class InputDatePicker
152152
}
153153
}
154154

155-
/** Selected date as a string in ISO format (YYYY-MM-DD) */
155+
/** Selected date as a string in ISO format (`"yyyy-mm-dd"`). */
156156
@Prop({ mutable: true }) value: string | string[] = "";
157157

158158
@Watch("value")

packages/calcite-components/src/components/input-number/input-number.e2e.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
import { getElementRect, getElementXY, selectText } from "../../tests/utils";
1616
import { letterKeys, numberKeys } from "../../utils/key";
1717
import { locales, numberStringFormatter } from "../../utils/locale";
18+
import { testPostValidationFocusing } from "../input/common/tests";
1819

1920
describe("calcite-input-number", () => {
2021
const delayFor2UpdatesInMs = 200;
@@ -1716,6 +1717,8 @@ describe("calcite-input-number", () => {
17161717
submitsOnEnter: true,
17171718
inputType: "number",
17181719
});
1720+
1721+
testPostValidationFocusing("calcite-input-number");
17191722
});
17201723

17211724
describe("translation support", () => {

packages/calcite-components/src/components/input-number/input-number.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
disconnectForm,
2525
FormComponent,
2626
HiddenFormInputSlot,
27+
internalHiddenInputInputEvent,
2728
submitForm,
2829
} from "../../utils/form";
2930
import {
@@ -433,7 +434,7 @@ export class InputNumber
433434
});
434435
this.mutationObserver?.observe(this.el, { childList: true });
435436
this.setDisabledAction();
436-
this.el.addEventListener("calciteInternalHiddenInputChange", this.hiddenInputChangeHandler);
437+
this.el.addEventListener(internalHiddenInputInputEvent, this.onHiddenFormInputInput);
437438
}
438439

439440
componentDidLoad(): void {
@@ -448,7 +449,7 @@ export class InputNumber
448449
disconnectMessages(this);
449450

450451
this.mutationObserver?.disconnect();
451-
this.el.removeEventListener("calciteInternalHiddenInputChange", this.hiddenInputChangeHandler);
452+
this.el.removeEventListener(internalHiddenInputInputEvent, this.onHiddenFormInputInput);
452453
}
453454

454455
async componentWillLoad(): Promise<void> {
@@ -785,13 +786,14 @@ export class InputNumber
785786
input.max = this.max?.toString(10) ?? "";
786787
}
787788

788-
hiddenInputChangeHandler = (event: Event): void => {
789+
private onHiddenFormInputInput = (event: Event): void => {
789790
if ((event.target as HTMLInputElement).name === this.name) {
790791
this.setNumberValue({
791792
value: (event.target as HTMLInputElement).value,
792793
origin: "direct",
793794
});
794795
}
796+
this.setFocus();
795797
event.stopPropagation();
796798
};
797799

packages/calcite-components/src/components/input-text/input-text.e2e.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
t9n,
1313
} from "../../tests/commonTests";
1414
import { selectText } from "../../tests/utils";
15+
import { testPostValidationFocusing } from "../input/common/tests";
1516

1617
describe("calcite-input-text", () => {
1718
describe("labelable", () => {
@@ -450,6 +451,8 @@ describe("calcite-input-text", () => {
450451

451452
describe("is form-associated", () => {
452453
formAssociated("calcite-input-text", { testValue: "test", submitsOnEnter: true });
454+
455+
testPostValidationFocusing("calcite-input-text");
453456
});
454457

455458
describe("translation support", () => {

packages/calcite-components/src/components/input-text/input-text.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
disconnectForm,
1818
FormComponent,
1919
HiddenFormInputSlot,
20+
internalHiddenInputInputEvent,
2021
submitForm,
2122
} from "../../utils/form";
2223
import {
@@ -335,7 +336,7 @@ export class InputText
335336
connectForm(this);
336337
this.mutationObserver?.observe(this.el, { childList: true });
337338
this.setDisabledAction();
338-
this.el.addEventListener("calciteInternalHiddenInputChange", this.hiddenInputChangeHandler);
339+
this.el.addEventListener(internalHiddenInputInputEvent, this.onHiddenFormInputInput);
339340
}
340341

341342
disconnectedCallback(): void {
@@ -346,7 +347,7 @@ export class InputText
346347
disconnectMessages(this);
347348

348349
this.mutationObserver?.disconnect();
349-
this.el.removeEventListener("calciteInternalHiddenInputChange", this.hiddenInputChangeHandler);
350+
this.el.removeEventListener(internalHiddenInputInputEvent, this.onHiddenFormInputInput);
350351
}
351352

352353
async componentWillLoad(): Promise<void> {
@@ -516,13 +517,14 @@ export class InputText
516517
}
517518
}
518519

519-
hiddenInputChangeHandler = (event: Event): void => {
520+
private onHiddenFormInputInput = (event: Event): void => {
520521
if ((event.target as HTMLInputElement).name === this.name) {
521522
this.setValue({
522523
value: (event.target as HTMLInputElement).value,
523524
origin: "direct",
524525
});
525526
}
527+
this.setFocus();
526528
event.stopPropagation();
527529
};
528530

packages/calcite-components/src/components/input-time-zone/input-time-zone.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ export class InputTimeZone
109109
/**
110110
* This specifies the type of `value` and the associated options presented to the user:
111111
*
112-
* Using `"offset"` will provide options related
112+
* Using `"offset"` will provide options that show timezone offsets.
113+
*
114+
* Using `"name"` will provide options that show the IANA time zone names.
113115
*
114116
* @default "offset"
115117
*/
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { newE2EPage } from "@stencil/core/testing";
2+
import { isElementFocused } from "../../../tests/utils";
3+
import { hiddenFormInputSlotName } from "../../../utils/form";
4+
import { html } from "../../../../support/formatting";
5+
import { JSX } from "../../../components";
6+
7+
export function testPostValidationFocusing(
8+
inputTag: Extract<keyof JSX.IntrinsicElements, "calcite-input" | "calcite-input-text" | "calcite-input-number">,
9+
): void {
10+
it("restores focus on invalid input if user continues typing", async () => {
11+
const page = await newE2EPage();
12+
const inputName = "test";
13+
14+
await page.setContent(html`
15+
<form>
16+
<${inputTag} type="text" required name="${inputName}"></${inputTag}>
17+
</form>
18+
<script>
19+
const form = document.querySelector("form");
20+
form.addEventListener("submit", (event) => {
21+
event.preventDefault();
22+
});
23+
</script>
24+
`);
25+
26+
const input = await page.find(inputTag);
27+
28+
await input.callMethod("setFocus");
29+
await input.press("Enter");
30+
await page.waitForChanges();
31+
32+
const hiddenInputSelector = `input[slot=${hiddenFormInputSlotName}]`;
33+
const inputSelector = `${inputTag}[name=${inputName}]`;
34+
35+
expect(await isElementFocused(page, hiddenInputSelector)).toBe(true);
36+
expect(await isElementFocused(page, inputSelector)).toBe(false);
37+
expect(await input.getProperty("value")).toBe("");
38+
39+
const expectedValue = "12345"; // number works for both text and number types
40+
41+
await page.keyboard.type(expectedValue);
42+
await page.waitForChanges();
43+
44+
expect(await isElementFocused(page, hiddenInputSelector)).toBe(false);
45+
expect(await isElementFocused(page, inputSelector)).toBe(true);
46+
expect(await input.getProperty("value")).toBe(expectedValue);
47+
});
48+
}

packages/calcite-components/src/components/input/input.e2e.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { letterKeys, numberKeys } from "../../utils/key";
1515
import { locales, numberStringFormatter } from "../../utils/locale";
1616
import { getElementRect, getElementXY, selectText } from "../../tests/utils";
1717
import { KeyInput } from "puppeteer";
18+
import { testPostValidationFocusing } from "./common/tests";
1819

1920
describe("calcite-input", () => {
2021
const delayFor2UpdatesInMs = 200;
@@ -2021,6 +2022,8 @@ describe("calcite-input", () => {
20212022
inputType: type,
20222023
});
20232024
}
2025+
2026+
testPostValidationFocusing("calcite-input");
20242027
});
20252028

20262029
describe("translation support", () => {

packages/calcite-components/src/components/input/input.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
disconnectForm,
2525
FormComponent,
2626
HiddenFormInputSlot,
27+
internalHiddenInputInputEvent,
2728
submitForm,
2829
} from "../../utils/form";
2930
import {
@@ -499,7 +500,7 @@ export class Input
499500
this.mutationObserver?.observe(this.el, { childList: true });
500501

501502
this.setDisabledAction();
502-
this.el.addEventListener("calciteInternalHiddenInputChange", this.hiddenInputChangeHandler);
503+
this.el.addEventListener(internalHiddenInputInputEvent, this.onHiddenFormInputInput);
503504
}
504505

505506
disconnectedCallback(): void {
@@ -510,7 +511,7 @@ export class Input
510511
disconnectMessages(this);
511512

512513
this.mutationObserver?.disconnect();
513-
this.el.removeEventListener("calciteInternalHiddenInputChange", this.hiddenInputChangeHandler);
514+
this.el.removeEventListener(internalHiddenInputInputEvent, this.onHiddenFormInputInput);
514515
}
515516

516517
async componentWillLoad(): Promise<void> {
@@ -886,13 +887,14 @@ export class Input
886887
}
887888
}
888889

889-
hiddenInputChangeHandler = (event: Event): void => {
890+
private onHiddenFormInputInput = (event: Event): void => {
890891
if ((event.target as HTMLInputElement).name === this.name) {
891892
this.setValue({
892893
value: (event.target as HTMLInputElement).value,
893894
origin: "direct",
894895
});
895896
}
897+
this.setFocus();
896898
event.stopPropagation();
897899
};
898900

packages/calcite-components/src/components/list-item-group/list-item-group.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export class ListItemGroup implements InteractiveComponent {
5959
//--------------------------------------------------------------------------
6060

6161
/**
62-
* Emitted when the default slot has changes in order to notify parent lists.
62+
* Fires when changes occur in the default slot, notifying parent lists of the changes.
6363
*/
6464
@Event({ cancelable: false })
6565
calciteInternalListItemGroupDefaultSlotChange: EventEmitter<DragEvent>;

packages/calcite-components/src/components/list-item/list-item.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ export class ListItem
236236
//--------------------------------------------------------------------------
237237

238238
/**
239-
* Emits when the item's content is selected.
239+
* Fires when the component is selected.
240240
*/
241241
@Event({ cancelable: false }) calciteListItemSelect: EventEmitter<void>;
242242

0 commit comments

Comments
 (0)