From b9b684dd8f036b82d880656fbafdc8fba103fa8a Mon Sep 17 00:00:00 2001
From: eliza
Date: Tue, 30 Apr 2024 16:11:14 -0700
Subject: [PATCH 01/62] set up demo for testing component sequential closing
behavior
---
.../calcite-components/src/demos/sheet.html | 122 +++++++++++++++++-
.../src/utils/focusTrapComponent.ts | 2 +-
2 files changed, 122 insertions(+), 2 deletions(-)
diff --git a/packages/calcite-components/src/demos/sheet.html b/packages/calcite-components/src/demos/sheet.html
index 2a8d9c0a543..222ee4d232c 100644
--- a/packages/calcite-components/src/demos/sheet.html
+++ b/packages/calcite-components/src/demos/sheet.html
@@ -37,7 +37,7 @@
- Sheet
+
+
+
+
+
+ width-scale
+
+ s
+ m
+ l
+
+
+
+ Open Modal from Sheet
+
+
+
+
+
+
This is an example modal that opens from a Sheet.
+
+ Open Another Modal
+
+
+
+
+
+ This is an example of a another modal that opens from a modal. This modal an input date picker, a combobox,
+ a dropdown, a popover and a tooltip.
+
+
+
+
+
+
+
+
+
+
+
+ Scale S
+
+ List
+ Grid
+
+
+
+
+
+
Example Popover
+
Example Tooltip
+
auto
+
+
+
+ Open Sheet
+
+
diff --git a/packages/calcite-components/src/utils/focusTrapComponent.ts b/packages/calcite-components/src/utils/focusTrapComponent.ts
index 8d8e8a734c1..1f0a4e12178 100644
--- a/packages/calcite-components/src/utils/focusTrapComponent.ts
+++ b/packages/calcite-components/src/utils/focusTrapComponent.ts
@@ -59,7 +59,7 @@ export function connectFocusTrap(component: FocusTrapComponent, options?: Connec
const focusTrapOptions: FocusTrapOptions = {
clickOutsideDeactivates: true,
- escapeDeactivates: false,
+ escapeDeactivates: true,
fallbackFocus: focusTrapNode,
setReturnFocus: (el) => {
focusElement(el as FocusableElement);
From 281619e762f6d2bd847d2bb7c31d5925a4033409 Mon Sep 17 00:00:00 2001
From: Matt Driscoll
Date: Tue, 30 Apr 2024 16:33:03 -0700
Subject: [PATCH 02/62] WIP
---
.../src/components/modal/modal.tsx | 19 ++++---------------
.../src/components/sheet/sheet.tsx | 19 ++++---------------
.../src/utils/focusTrapComponent.ts | 14 ++++++++++++--
3 files changed, 20 insertions(+), 32 deletions(-)
diff --git a/packages/calcite-components/src/components/modal/modal.tsx b/packages/calcite-components/src/components/modal/modal.tsx
index 592a8afae72..49ffc69606e 100644
--- a/packages/calcite-components/src/components/modal/modal.tsx
+++ b/packages/calcite-components/src/components/modal/modal.tsx
@@ -5,7 +5,6 @@ import {
EventEmitter,
h,
Host,
- Listen,
Method,
Prop,
State,
@@ -393,20 +392,6 @@ export class Modal
@State() defaultMessages: ModalMessages;
- //--------------------------------------------------------------------------
- //
- // Event Listeners
- //
- //--------------------------------------------------------------------------
-
- @Listen("keydown", { target: "window" })
- handleEscape(event: KeyboardEvent): void {
- if (this.open && !this.escapeDisabled && event.key === "Escape" && !event.defaultPrevented) {
- this.open = false;
- event.preventDefault();
- }
- }
-
//--------------------------------------------------------------------------
//
// Events
@@ -498,6 +483,10 @@ export class Modal
deactivateFocusTrap(this);
}
+ onFocusTrapDeactivate(): void {
+ this.open = false;
+ }
+
@Watch("open")
toggleModal(value: boolean): void {
if (this.ignoreOpenChange) {
diff --git a/packages/calcite-components/src/components/sheet/sheet.tsx b/packages/calcite-components/src/components/sheet/sheet.tsx
index 62f4d35b308..bf1d7760003 100644
--- a/packages/calcite-components/src/components/sheet/sheet.tsx
+++ b/packages/calcite-components/src/components/sheet/sheet.tsx
@@ -5,7 +5,6 @@ import {
EventEmitter,
h,
Host,
- Listen,
Method,
Prop,
VNode,
@@ -218,20 +217,6 @@ export class Sheet implements OpenCloseComponent, FocusTrapComponent, LoadableCo
this.handleMutationObserver(),
);
- //--------------------------------------------------------------------------
- //
- // Event Listeners
- //
- //--------------------------------------------------------------------------
-
- @Listen("keydown", { target: "window" })
- handleEscape(event: KeyboardEvent): void {
- if (this.open && !this.escapeDisabled && event.key === "Escape" && !event.defaultPrevented) {
- this.open = false;
- event.preventDefault();
- }
- }
-
//--------------------------------------------------------------------------
//
// Events
@@ -298,6 +283,10 @@ export class Sheet implements OpenCloseComponent, FocusTrapComponent, LoadableCo
deactivateFocusTrap(this);
}
+ onFocusTrapDeactivate(): void {
+ this.open = false;
+ }
+
private setTransitionEl = (el: HTMLDivElement): void => {
this.transitionEl = el;
this.contentId = ensureId(el);
diff --git a/packages/calcite-components/src/utils/focusTrapComponent.ts b/packages/calcite-components/src/utils/focusTrapComponent.ts
index 1f0a4e12178..7948511911a 100644
--- a/packages/calcite-components/src/utils/focusTrapComponent.ts
+++ b/packages/calcite-components/src/utils/focusTrapComponent.ts
@@ -11,6 +11,10 @@ export interface FocusTrapComponent {
*/
el: HTMLElement;
+ escapeDisabled?: boolean;
+
+ outsideCloseDisabled?: boolean;
+
/**
* When `true`, prevents focus trapping.
*/
@@ -27,6 +31,8 @@ export interface FocusTrapComponent {
* This should be implemented for components that allow user content and/or have conditionally-rendered focusable elements within the trap.
*/
updateFocusTrapElements?: () => Promise;
+
+ onFocusTrapDeactivate?(): void;
}
export type FocusTrap = _FocusTrap;
@@ -58,9 +64,13 @@ export function connectFocusTrap(component: FocusTrapComponent, options?: Connec
}
const focusTrapOptions: FocusTrapOptions = {
- clickOutsideDeactivates: true,
- escapeDeactivates: true,
+ clickOutsideDeactivates: !component.outsideCloseDisabled ?? true,
+ escapeDeactivates: !component.escapeDisabled ?? true,
fallbackFocus: focusTrapNode,
+ onDeactivate: () => {
+ component.onFocusTrapDeactivate();
+ console.log("focus trap deactivated");
+ },
setReturnFocus: (el) => {
focusElement(el as FocusableElement);
return false;
From 2ad2c8e6a359bfce8cca50e67159c34a4271e21b Mon Sep 17 00:00:00 2001
From: eliza
Date: Wed, 1 May 2024 12:41:01 -0700
Subject: [PATCH 03/62] WIP
---
.../calcite-components/src/demos/sheet.html | 34 ++++---------------
1 file changed, 6 insertions(+), 28 deletions(-)
diff --git a/packages/calcite-components/src/demos/sheet.html b/packages/calcite-components/src/demos/sheet.html
index 222ee4d232c..1b412d97b3f 100644
--- a/packages/calcite-components/src/demos/sheet.html
+++ b/packages/calcite-components/src/demos/sheet.html
@@ -144,7 +144,7 @@
- Open Modal from Sheet
+ Open Modal from Sheet
@@ -158,7 +158,7 @@
scale="s"
kind="neutral"
appearance="outline"
- onClick="openAnotherModal('another-modal')"
+ onClick="openComponent('another-modal')"
>Open Another Modal
@@ -215,34 +215,12 @@
- Open Sheet
+ Open Sheet
From c95e3aaacb39b7b532d0fc2fadfde86298782b55 Mon Sep 17 00:00:00 2001
From: eliza
Date: Wed, 1 May 2024 13:17:02 -0700
Subject: [PATCH 04/62] WIP
---
.../components/input-date-picker/input-date-picker.tsx | 8 ++++----
packages/calcite-components/src/demos/sheet.html | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
index f75b9f47964..ff93d6ff0b6 100644
--- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
+++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
@@ -853,6 +853,10 @@ export class InputDatePicker
this.datePickerEl.reset();
}
+ onFocusTrapDeactivate(): void {
+ this.open = false;
+ }
+
setStartInput = (el: HTMLCalciteInputElement): void => {
this.startInput = el;
};
@@ -932,10 +936,6 @@ export class InputDatePicker
this.open = true;
this.focusOnOpen = true;
event.preventDefault();
- } else if (key === "Escape") {
- this.open = false;
- event.preventDefault();
- this.restoreInputFocus();
}
};
diff --git a/packages/calcite-components/src/demos/sheet.html b/packages/calcite-components/src/demos/sheet.html
index 1b412d97b3f..4fa12ea77d9 100644
--- a/packages/calcite-components/src/demos/sheet.html
+++ b/packages/calcite-components/src/demos/sheet.html
@@ -169,7 +169,7 @@
This is an example of a another modal that opens from a modal. This modal an input date picker, a combobox,
a dropdown, a popover and a tooltip.
-
+
Date: Wed, 1 May 2024 14:28:47 -0700
Subject: [PATCH 05/62] WIP
---
.../components/input-time-picker/input-time-picker.tsx | 9 +++++----
packages/calcite-components/src/demos/sheet.html | 9 ++++++++-
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
index 268aa0c39e8..88c3cce69d0 100644
--- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
+++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
@@ -551,6 +551,11 @@ export class InputTimePicker
this.calciteInputTimePickerClose.emit();
}
+ onFocusTrapDeactivate(): void {
+ this.open = false;
+ this.calciteInputEl.setFocus();
+ }
+
private delocalizeTimeString(value: string): string {
// we need to set the corresponding locale before parsing, otherwise it defaults to English (possible dayjs bug)
dayjs.locale(this.effectiveLocale.toLowerCase());
@@ -716,10 +721,6 @@ export class InputTimePicker
this.open = true;
this.focusOnOpen = true;
event.preventDefault();
- } else if (key === "Escape" && this.open) {
- this.open = false;
- event.preventDefault();
- this.calciteInputEl.setFocus();
}
};
diff --git a/packages/calcite-components/src/demos/sheet.html b/packages/calcite-components/src/demos/sheet.html
index 4fa12ea77d9..0a6b957653c 100644
--- a/packages/calcite-components/src/demos/sheet.html
+++ b/packages/calcite-components/src/demos/sheet.html
@@ -169,7 +169,14 @@
This is an example of a another modal that opens from a modal. This modal an input date picker, a combobox,
a dropdown, a popover and a tooltip.
-
+
+ Input Date Picker
+
+
+
+ Input Time Picker
+
+
Date: Wed, 1 May 2024 15:01:03 -0700
Subject: [PATCH 06/62] add docs
---
.../src/components/input-date-picker/input-date-picker.tsx | 1 +
.../src/components/input-time-picker/input-time-picker.tsx | 1 +
packages/calcite-components/src/components/modal/modal.tsx | 1 +
.../calcite-components/src/components/popover/popover.tsx | 5 +++++
packages/calcite-components/src/components/sheet/sheet.tsx | 1 +
packages/calcite-components/src/utils/focusTrapComponent.ts | 2 ++
6 files changed, 11 insertions(+)
diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
index ff93d6ff0b6..640f62b8356 100644
--- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
+++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
@@ -853,6 +853,7 @@ export class InputDatePicker
this.datePickerEl.reset();
}
+ /** Leverage the `focus-trap` builtin stack to handle closing a sequence of open components, instead of components handling own `escape`. */
onFocusTrapDeactivate(): void {
this.open = false;
}
diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
index 88c3cce69d0..4c63ccf4f59 100644
--- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
+++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
@@ -551,6 +551,7 @@ export class InputTimePicker
this.calciteInputTimePickerClose.emit();
}
+ /** Leverage the `focus-trap` builtin stack to handle closing a sequence of open components, instead of components handling own `escape`. */
onFocusTrapDeactivate(): void {
this.open = false;
this.calciteInputEl.setFocus();
diff --git a/packages/calcite-components/src/components/modal/modal.tsx b/packages/calcite-components/src/components/modal/modal.tsx
index 49ffc69606e..280097561c0 100644
--- a/packages/calcite-components/src/components/modal/modal.tsx
+++ b/packages/calcite-components/src/components/modal/modal.tsx
@@ -483,6 +483,7 @@ export class Modal
deactivateFocusTrap(this);
}
+ /** Leverage the `focus-trap` builtin stack to handle closing a sequence of open components, instead of components handling own `escape`. */
onFocusTrapDeactivate(): void {
this.open = false;
}
diff --git a/packages/calcite-components/src/components/popover/popover.tsx b/packages/calcite-components/src/components/popover/popover.tsx
index aeb55416ef2..ba15de43319 100644
--- a/packages/calcite-components/src/components/popover/popover.tsx
+++ b/packages/calcite-components/src/components/popover/popover.tsx
@@ -513,6 +513,11 @@ export class Popover
deactivateFocusTrap(this);
}
+ /** Leverage the `focus-trap` builtin stack to handle closing a sequence of open components, instead of components handling own `escape`. */
+ onFocusTrapDeactivate(): void {
+ this.open = false;
+ }
+
storeArrowEl = (el: SVGElement): void => {
this.arrowEl = el;
this.reposition(true);
diff --git a/packages/calcite-components/src/components/sheet/sheet.tsx b/packages/calcite-components/src/components/sheet/sheet.tsx
index bf1d7760003..5bd2e338b08 100644
--- a/packages/calcite-components/src/components/sheet/sheet.tsx
+++ b/packages/calcite-components/src/components/sheet/sheet.tsx
@@ -283,6 +283,7 @@ export class Sheet implements OpenCloseComponent, FocusTrapComponent, LoadableCo
deactivateFocusTrap(this);
}
+ /** Leverage the `focus-trap` builtin stack to handle closing a sequence of open components, instead of components handling own `escape`. */
onFocusTrapDeactivate(): void {
this.open = false;
}
diff --git a/packages/calcite-components/src/utils/focusTrapComponent.ts b/packages/calcite-components/src/utils/focusTrapComponent.ts
index 7948511911a..d9941a7a93e 100644
--- a/packages/calcite-components/src/utils/focusTrapComponent.ts
+++ b/packages/calcite-components/src/utils/focusTrapComponent.ts
@@ -11,8 +11,10 @@ export interface FocusTrapComponent {
*/
el: HTMLElement;
+ /** When `true`, disables the default close on escape behavior. */
escapeDisabled?: boolean;
+ /** When `true`, disables the closing of the component when clicked outside. */
outsideCloseDisabled?: boolean;
/**
From 1187a3ad0a59908dc0cba1a5f929c0e8a438374b Mon Sep 17 00:00:00 2001
From: eliza
Date: Wed, 1 May 2024 16:56:13 -0700
Subject: [PATCH 07/62] simplified HTML for Demo and e2e test to reflect the
demo workflow
---
.../src/components/sheet/sheet.e2e.ts | 142 +++++++++++++++++-
.../calcite-components/src/demos/sheet.html | 36 +----
2 files changed, 148 insertions(+), 30 deletions(-)
diff --git a/packages/calcite-components/src/components/sheet/sheet.e2e.ts b/packages/calcite-components/src/components/sheet/sheet.e2e.ts
index 5bab2cbaefb..6b84d6e7d96 100644
--- a/packages/calcite-components/src/components/sheet/sheet.e2e.ts
+++ b/packages/calcite-components/src/components/sheet/sheet.e2e.ts
@@ -1,4 +1,4 @@
-import { newE2EPage } from "@stencil/core/testing";
+import { E2EElement, newE2EPage, E2EPage } from "@stencil/core/testing";
import { html } from "../../../support/formatting";
import { focusable, renders, hidden, defaults, accessible } from "../../tests/commonTests";
import { GlobalTestProps, newProgrammaticE2EPage, skipAnimations } from "../../tests/utils";
@@ -541,4 +541,144 @@ describe("calcite-sheet properties", () => {
expect(closeSpy).toHaveReceivedEventTimes(1);
});
});
+
+ const componentStack = html`
+
+
+
+ Open Modal from Sheet
+
+
+
+
+
+
This is an example modal that opens from a Sheet.
+
+ Open Another Modal
+
+
+
+
+
+ This is an example of a another modal that opens from a modal. This modal an input date picker, a combobox, a
+ dropdown, a popover and a tooltip.
+
+
+ Input Date Picker
+
+
+
+ Input Time Picker
+
+
+
+
+
+
+
+
+
+
+
+ Scale S
+
+ List
+ Grid
+
+
+
+
+
+
Example Popover
+
Example Tooltip
+
auto
+
+
+ Open Sheet
+ `;
+
+ it("closes a stack of open components sequentially in visual order", async () => {
+ const page = await newE2EPage();
+ await page.setContent(componentStack);
+ await skipAnimations(page);
+
+ async function openAndCheckVisibility(page: E2EPage, element: E2EElement) {
+ element.setProperty("open", true);
+ await page.waitForChanges();
+ expect(await element.isVisible()).toBe(true);
+ }
+
+ const sheet = await page.find("calcite-sheet");
+ await openAndCheckVisibility(page, sheet);
+
+ const firstModal = await page.find("#example-modal");
+ await openAndCheckVisibility(page, firstModal);
+
+ const secondModal = await page.find("#another-modal");
+ await openAndCheckVisibility(page, secondModal);
+
+ async function testInputPicker(page: E2EPage, pickerSelector: string, modal: E2EElement) {
+ const inputPicker = await page.find(pickerSelector);
+ inputPicker.click();
+ await page.waitForChanges();
+ expect(await inputPicker.getProperty("open")).toBe(true);
+
+ await page.keyboard.press("Escape");
+ await page.waitForChanges();
+ expect(await inputPicker.getProperty("open")).toBe(false);
+
+ await page.keyboard.press("Escape");
+ await page.waitForChanges();
+ expect(await modal.isVisible()).toBe(false);
+
+ modal.setProperty("open", true);
+ await page.waitForChanges();
+ }
+
+ await testInputPicker(page, "calcite-input-date-picker", secondModal);
+ await testInputPicker(page, "calcite-input-time-picker", secondModal);
+
+ secondModal.setProperty("open", true);
+ await page.waitForChanges();
+
+ const popoverButton = await page.find("#popover-button");
+ popoverButton.click();
+ await page.waitForChanges();
+ const popover = await page.find("calcite-popover");
+ expect(await popover.getProperty("open")).toBe(true);
+
+ await page.keyboard.press("Escape");
+ await page.waitForChanges();
+ expect(await popover.getProperty("open")).toBe(false);
+
+ async function pressEscapeAndCheckVisibility(page: E2EPage, element: E2EElement, expectedVisibility: boolean) {
+ page.keyboard.press("Escape");
+ await page.waitForChanges();
+ expect(await element.isVisible()).toBe(expectedVisibility);
+ }
+
+ await pressEscapeAndCheckVisibility(page, secondModal, false);
+ await pressEscapeAndCheckVisibility(page, firstModal, false);
+ await pressEscapeAndCheckVisibility(page, sheet, false);
+ });
});
diff --git a/packages/calcite-components/src/demos/sheet.html b/packages/calcite-components/src/demos/sheet.html
index 0a6b957653c..673a9bc181b 100644
--- a/packages/calcite-components/src/demos/sheet.html
+++ b/packages/calcite-components/src/demos/sheet.html
@@ -126,44 +126,23 @@
});
-->
-
-
-
- width-scale
-
- s
- m
- l
-
-
-
+
+
+
Open Modal from Sheet
-
+
This is an example modal that opens from a Sheet.
- Open Another Modal
-
+
This is an example of a another modal that opens from a modal. This modal an input date picker, a combobox,
@@ -171,7 +150,7 @@
Input Date Picker
-
+
Input Time Picker
@@ -182,7 +161,6 @@
placeholder="placeholder"
max-items="8"
selection-mode="ancestors"
- scale="m"
style="width: 200px"
id="combobox"
>
From fadbb0de34f1f5f4cd9eae8861857acf90b23201 Mon Sep 17 00:00:00 2001
From: eliza
Date: Thu, 2 May 2024 10:20:13 -0700
Subject: [PATCH 08/62] cleanup
---
.../input-date-picker/input-date-picker.tsx | 1 -
.../input-time-picker/input-time-picker.tsx | 2 -
.../src/components/modal/modal.tsx | 1 -
.../src/components/popover/popover.tsx | 1 -
.../src/components/sheet/sheet.tsx | 1 -
.../calcite-components/src/demos/sheet.html | 85 +------------------
.../src/utils/focusTrapComponent.ts | 8 +-
7 files changed, 5 insertions(+), 94 deletions(-)
diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
index 640f62b8356..ff93d6ff0b6 100644
--- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
+++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
@@ -853,7 +853,6 @@ export class InputDatePicker
this.datePickerEl.reset();
}
- /** Leverage the `focus-trap` builtin stack to handle closing a sequence of open components, instead of components handling own `escape`. */
onFocusTrapDeactivate(): void {
this.open = false;
}
diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
index 4c63ccf4f59..565663622cb 100644
--- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
+++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
@@ -551,10 +551,8 @@ export class InputTimePicker
this.calciteInputTimePickerClose.emit();
}
- /** Leverage the `focus-trap` builtin stack to handle closing a sequence of open components, instead of components handling own `escape`. */
onFocusTrapDeactivate(): void {
this.open = false;
- this.calciteInputEl.setFocus();
}
private delocalizeTimeString(value: string): string {
diff --git a/packages/calcite-components/src/components/modal/modal.tsx b/packages/calcite-components/src/components/modal/modal.tsx
index 280097561c0..49ffc69606e 100644
--- a/packages/calcite-components/src/components/modal/modal.tsx
+++ b/packages/calcite-components/src/components/modal/modal.tsx
@@ -483,7 +483,6 @@ export class Modal
deactivateFocusTrap(this);
}
- /** Leverage the `focus-trap` builtin stack to handle closing a sequence of open components, instead of components handling own `escape`. */
onFocusTrapDeactivate(): void {
this.open = false;
}
diff --git a/packages/calcite-components/src/components/popover/popover.tsx b/packages/calcite-components/src/components/popover/popover.tsx
index ba15de43319..eafd4ee13fc 100644
--- a/packages/calcite-components/src/components/popover/popover.tsx
+++ b/packages/calcite-components/src/components/popover/popover.tsx
@@ -513,7 +513,6 @@ export class Popover
deactivateFocusTrap(this);
}
- /** Leverage the `focus-trap` builtin stack to handle closing a sequence of open components, instead of components handling own `escape`. */
onFocusTrapDeactivate(): void {
this.open = false;
}
diff --git a/packages/calcite-components/src/components/sheet/sheet.tsx b/packages/calcite-components/src/components/sheet/sheet.tsx
index 5bd2e338b08..bf1d7760003 100644
--- a/packages/calcite-components/src/components/sheet/sheet.tsx
+++ b/packages/calcite-components/src/components/sheet/sheet.tsx
@@ -283,7 +283,6 @@ export class Sheet implements OpenCloseComponent, FocusTrapComponent, LoadableCo
deactivateFocusTrap(this);
}
- /** Leverage the `focus-trap` builtin stack to handle closing a sequence of open components, instead of components handling own `escape`. */
onFocusTrapDeactivate(): void {
this.open = false;
}
diff --git a/packages/calcite-components/src/demos/sheet.html b/packages/calcite-components/src/demos/sheet.html
index 673a9bc181b..2a8d9c0a543 100644
--- a/packages/calcite-components/src/demos/sheet.html
+++ b/packages/calcite-components/src/demos/sheet.html
@@ -37,7 +37,7 @@
-
-
-
-
-
- Open Modal from Sheet
-
-
-
-
-
-
This is an example modal that opens from a Sheet.
-
- Open Another Modal
-
-
-
-
-
- This is an example of a another modal that opens from a modal. This modal an input date picker, a combobox,
- a dropdown, a popover and a tooltip.
-
-
- Input Date Picker
-
-
-
- Input Time Picker
-
-
-
-
-
-
-
-
-
-
-
- Scale S
-
- List
- Grid
-
-
-
-
-
-
Example Popover
-
Example Tooltip
-
auto
-
-
-
- Open Sheet
-
-
diff --git a/packages/calcite-components/src/utils/focusTrapComponent.ts b/packages/calcite-components/src/utils/focusTrapComponent.ts
index d9941a7a93e..2108dba1790 100644
--- a/packages/calcite-components/src/utils/focusTrapComponent.ts
+++ b/packages/calcite-components/src/utils/focusTrapComponent.ts
@@ -34,6 +34,9 @@ export interface FocusTrapComponent {
*/
updateFocusTrapElements?: () => Promise;
+ /**
+ * Method that gets called when the focus trap is deactivated.
+ */
onFocusTrapDeactivate?(): void;
}
@@ -69,10 +72,7 @@ export function connectFocusTrap(component: FocusTrapComponent, options?: Connec
clickOutsideDeactivates: !component.outsideCloseDisabled ?? true,
escapeDeactivates: !component.escapeDisabled ?? true,
fallbackFocus: focusTrapNode,
- onDeactivate: () => {
- component.onFocusTrapDeactivate();
- console.log("focus trap deactivated");
- },
+ onDeactivate: () => component.onFocusTrapDeactivate(),
setReturnFocus: (el) => {
focusElement(el as FocusableElement);
return false;
From 0622da14f416a12d5eaf53b30abdc5934a35c26d Mon Sep 17 00:00:00 2001
From: eliza
Date: Thu, 2 May 2024 13:28:44 -0700
Subject: [PATCH 09/62] stacked focus-trap components test
---
.../src/components/components.e2e.ts | 129 ++++++++++++++++
.../src/components/sheet/sheet.e2e.ts | 142 +-----------------
.../calcite-components/src/demos/sheet.html | 86 ++++++++++-
.../src/utils/focusTrapComponent.ts | 2 +-
4 files changed, 216 insertions(+), 143 deletions(-)
create mode 100644 packages/calcite-components/src/components/components.e2e.ts
diff --git a/packages/calcite-components/src/components/components.e2e.ts b/packages/calcite-components/src/components/components.e2e.ts
new file mode 100644
index 00000000000..3261601e3ef
--- /dev/null
+++ b/packages/calcite-components/src/components/components.e2e.ts
@@ -0,0 +1,129 @@
+import { E2EElement, newE2EPage, E2EPage } from "@stencil/core/testing";
+import { html } from "../../support/formatting";
+import { skipAnimations } from "../tests/utils";
+
+describe("stacked focus-trap components", () => {
+ const componentStack = html`
+
+
+
+ Open Modal from Sheet
+
+
+
+
+
+
This is an example modal that opens from a Sheet.
+
+ Open Another Modal
+
+
+
+
+
+ This is an example of a another modal that opens from a modal. This modal an input date picker, a combobox, a
+ dropdown, a popover and a tooltip.
+
+
+
+
+
+
+
+
+
+
+ Scale S
+
+ List
+ Grid
+
+
+
+
+
Example Popover.
+
+ Input Date Picker
+
+
+
+ Input Time Picker
+
+
+
+
+
Example Popover
+
Example Tooltip
+
auto
+
+
+ Open Sheet
+ `;
+
+ it("closes a stack of open components sequentially in visual order", async () => {
+ const page = await newE2EPage();
+ await page.setContent(componentStack);
+ await skipAnimations(page);
+
+ async function testStackEscapeSequence(page: E2EPage, pickerType: string) {
+ async function openAndCheckVisibility(element: E2EElement) {
+ element.setProperty("open", true);
+ await page.waitForChanges();
+ expect(await element.isVisible()).toBe(true);
+ }
+
+ const sheet = await page.find("calcite-sheet");
+ await openAndCheckVisibility(sheet);
+
+ const firstModal = await page.find("#example-modal");
+ await openAndCheckVisibility(firstModal);
+
+ const secondModal = await page.find("#another-modal");
+ await openAndCheckVisibility(secondModal);
+
+ const popover = await page.find("calcite-popover");
+ await openAndCheckVisibility(popover);
+
+ const inputPicker = await page.find(pickerType);
+ inputPicker.click();
+ await page.waitForChanges();
+ expect(await inputPicker.getProperty("open")).toBe(true);
+
+ async function testEscapeAndCheckOpenState(elements: E2EElement[]) {
+ for (let i = 0; i < elements.length; i++) {
+ await page.keyboard.press("Escape");
+ await page.waitForChanges();
+ expect(await elements[i].getProperty("open")).toBe(false);
+
+ for (let j = 0; j < elements.length; j++) {
+ const expectedOpenState = j > i;
+ expect(await elements[j].getProperty("open")).toBe(expectedOpenState);
+ }
+ }
+ }
+
+ await testEscapeAndCheckOpenState([inputPicker, popover, secondModal, firstModal, sheet]);
+ }
+
+ await testStackEscapeSequence(page, "calcite-input-date-picker");
+ await testStackEscapeSequence(page, "calcite-input-time-picker");
+ });
+});
diff --git a/packages/calcite-components/src/components/sheet/sheet.e2e.ts b/packages/calcite-components/src/components/sheet/sheet.e2e.ts
index 6b84d6e7d96..5bab2cbaefb 100644
--- a/packages/calcite-components/src/components/sheet/sheet.e2e.ts
+++ b/packages/calcite-components/src/components/sheet/sheet.e2e.ts
@@ -1,4 +1,4 @@
-import { E2EElement, newE2EPage, E2EPage } from "@stencil/core/testing";
+import { newE2EPage } from "@stencil/core/testing";
import { html } from "../../../support/formatting";
import { focusable, renders, hidden, defaults, accessible } from "../../tests/commonTests";
import { GlobalTestProps, newProgrammaticE2EPage, skipAnimations } from "../../tests/utils";
@@ -541,144 +541,4 @@ describe("calcite-sheet properties", () => {
expect(closeSpy).toHaveReceivedEventTimes(1);
});
});
-
- const componentStack = html`
-
-
-
- Open Modal from Sheet
-
-
-
-
-
-
This is an example modal that opens from a Sheet.
-
- Open Another Modal
-
-
-
-
-
- This is an example of a another modal that opens from a modal. This modal an input date picker, a combobox, a
- dropdown, a popover and a tooltip.
-
-
- Input Date Picker
-
-
-
- Input Time Picker
-
-
-
-
-
-
-
-
-
-
-
- Scale S
-
- List
- Grid
-
-
-
-
-
-
Example Popover
-
Example Tooltip
-
auto
-
-
- Open Sheet
- `;
-
- it("closes a stack of open components sequentially in visual order", async () => {
- const page = await newE2EPage();
- await page.setContent(componentStack);
- await skipAnimations(page);
-
- async function openAndCheckVisibility(page: E2EPage, element: E2EElement) {
- element.setProperty("open", true);
- await page.waitForChanges();
- expect(await element.isVisible()).toBe(true);
- }
-
- const sheet = await page.find("calcite-sheet");
- await openAndCheckVisibility(page, sheet);
-
- const firstModal = await page.find("#example-modal");
- await openAndCheckVisibility(page, firstModal);
-
- const secondModal = await page.find("#another-modal");
- await openAndCheckVisibility(page, secondModal);
-
- async function testInputPicker(page: E2EPage, pickerSelector: string, modal: E2EElement) {
- const inputPicker = await page.find(pickerSelector);
- inputPicker.click();
- await page.waitForChanges();
- expect(await inputPicker.getProperty("open")).toBe(true);
-
- await page.keyboard.press("Escape");
- await page.waitForChanges();
- expect(await inputPicker.getProperty("open")).toBe(false);
-
- await page.keyboard.press("Escape");
- await page.waitForChanges();
- expect(await modal.isVisible()).toBe(false);
-
- modal.setProperty("open", true);
- await page.waitForChanges();
- }
-
- await testInputPicker(page, "calcite-input-date-picker", secondModal);
- await testInputPicker(page, "calcite-input-time-picker", secondModal);
-
- secondModal.setProperty("open", true);
- await page.waitForChanges();
-
- const popoverButton = await page.find("#popover-button");
- popoverButton.click();
- await page.waitForChanges();
- const popover = await page.find("calcite-popover");
- expect(await popover.getProperty("open")).toBe(true);
-
- await page.keyboard.press("Escape");
- await page.waitForChanges();
- expect(await popover.getProperty("open")).toBe(false);
-
- async function pressEscapeAndCheckVisibility(page: E2EPage, element: E2EElement, expectedVisibility: boolean) {
- page.keyboard.press("Escape");
- await page.waitForChanges();
- expect(await element.isVisible()).toBe(expectedVisibility);
- }
-
- await pressEscapeAndCheckVisibility(page, secondModal, false);
- await pressEscapeAndCheckVisibility(page, firstModal, false);
- await pressEscapeAndCheckVisibility(page, sheet, false);
- });
});
diff --git a/packages/calcite-components/src/demos/sheet.html b/packages/calcite-components/src/demos/sheet.html
index 2a8d9c0a543..8b66f382c59 100644
--- a/packages/calcite-components/src/demos/sheet.html
+++ b/packages/calcite-components/src/demos/sheet.html
@@ -37,7 +37,7 @@
- Sheet
+
+
+
+
+
+ Open Modal from Sheet
+
+
+
+
+
+
This is an example modal that opens from a Sheet.
+
+ Open Another Modal
+
+
+
+
+
+ This is an example of a another modal that opens from a modal. This modal an input date picker, a combobox,
+ a dropdown, a popover and a tooltip.
+
+
+
+
+
+
+
+
+
+
+
+ Scale S
+
+ List
+ Grid
+
+
+
+
+
Example Popover.
+
+ Input Date Picker
+
+
+
+ Input Time Picker
+
+
+
+
+
Example Popover
+
Example Tooltip
+
auto
+
+
+
+ Open Sheet
+
+
diff --git a/packages/calcite-components/src/utils/focusTrapComponent.ts b/packages/calcite-components/src/utils/focusTrapComponent.ts
index 2108dba1790..137235c9d76 100644
--- a/packages/calcite-components/src/utils/focusTrapComponent.ts
+++ b/packages/calcite-components/src/utils/focusTrapComponent.ts
@@ -35,7 +35,7 @@ export interface FocusTrapComponent {
updateFocusTrapElements?: () => Promise;
/**
- * Method that gets called when the focus trap is deactivated.
+ * Method that will be called before returning focus to the node that had focus prior to activation upon deactivation.
*/
onFocusTrapDeactivate?(): void;
}
From 00e576b91ac9abf545f117e1728d19a5a75cab73 Mon Sep 17 00:00:00 2001
From: eliza
Date: Wed, 8 May 2024 11:27:04 -0700
Subject: [PATCH 10/62] relocate test for closing of stacked focus-trap
components to globalStyles
---
.../src/components/components.e2e.ts | 129 -----------------
.../calcite-components/src/demos/sheet.html | 86 +-----------
.../src/tests/globalStyles.e2e.ts | 130 +++++++++++++++++-
3 files changed, 130 insertions(+), 215 deletions(-)
delete mode 100644 packages/calcite-components/src/components/components.e2e.ts
diff --git a/packages/calcite-components/src/components/components.e2e.ts b/packages/calcite-components/src/components/components.e2e.ts
deleted file mode 100644
index 3261601e3ef..00000000000
--- a/packages/calcite-components/src/components/components.e2e.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import { E2EElement, newE2EPage, E2EPage } from "@stencil/core/testing";
-import { html } from "../../support/formatting";
-import { skipAnimations } from "../tests/utils";
-
-describe("stacked focus-trap components", () => {
- const componentStack = html`
-
-
-
- Open Modal from Sheet
-
-
-
-
-
-
This is an example modal that opens from a Sheet.
-
- Open Another Modal
-
-
-
-
-
- This is an example of a another modal that opens from a modal. This modal an input date picker, a combobox, a
- dropdown, a popover and a tooltip.
-
-
-
-
-
-
-
-
-
-
- Scale S
-
- List
- Grid
-
-
-
-
-
Example Popover.
-
- Input Date Picker
-
-
-
- Input Time Picker
-
-
-
-
-
Example Popover
-
Example Tooltip
-
auto
-
-
- Open Sheet
- `;
-
- it("closes a stack of open components sequentially in visual order", async () => {
- const page = await newE2EPage();
- await page.setContent(componentStack);
- await skipAnimations(page);
-
- async function testStackEscapeSequence(page: E2EPage, pickerType: string) {
- async function openAndCheckVisibility(element: E2EElement) {
- element.setProperty("open", true);
- await page.waitForChanges();
- expect(await element.isVisible()).toBe(true);
- }
-
- const sheet = await page.find("calcite-sheet");
- await openAndCheckVisibility(sheet);
-
- const firstModal = await page.find("#example-modal");
- await openAndCheckVisibility(firstModal);
-
- const secondModal = await page.find("#another-modal");
- await openAndCheckVisibility(secondModal);
-
- const popover = await page.find("calcite-popover");
- await openAndCheckVisibility(popover);
-
- const inputPicker = await page.find(pickerType);
- inputPicker.click();
- await page.waitForChanges();
- expect(await inputPicker.getProperty("open")).toBe(true);
-
- async function testEscapeAndCheckOpenState(elements: E2EElement[]) {
- for (let i = 0; i < elements.length; i++) {
- await page.keyboard.press("Escape");
- await page.waitForChanges();
- expect(await elements[i].getProperty("open")).toBe(false);
-
- for (let j = 0; j < elements.length; j++) {
- const expectedOpenState = j > i;
- expect(await elements[j].getProperty("open")).toBe(expectedOpenState);
- }
- }
- }
-
- await testEscapeAndCheckOpenState([inputPicker, popover, secondModal, firstModal, sheet]);
- }
-
- await testStackEscapeSequence(page, "calcite-input-date-picker");
- await testStackEscapeSequence(page, "calcite-input-time-picker");
- });
-});
diff --git a/packages/calcite-components/src/demos/sheet.html b/packages/calcite-components/src/demos/sheet.html
index 8b66f382c59..2a8d9c0a543 100644
--- a/packages/calcite-components/src/demos/sheet.html
+++ b/packages/calcite-components/src/demos/sheet.html
@@ -37,7 +37,7 @@
-
-
-
-
-
- Open Modal from Sheet
-
-
-
-
-
-
This is an example modal that opens from a Sheet.
-
- Open Another Modal
-
-
-
-
-
- This is an example of a another modal that opens from a modal. This modal an input date picker, a combobox,
- a dropdown, a popover and a tooltip.
-
-
-
-
-
-
-
-
-
-
-
- Scale S
-
- List
- Grid
-
-
-
-
-
Example Popover.
-
- Input Date Picker
-
-
-
- Input Time Picker
-
-
-
-
-
Example Popover
-
Example Tooltip
-
auto
-
-
-
- Open Sheet
-
-
diff --git a/packages/calcite-components/src/tests/globalStyles.e2e.ts b/packages/calcite-components/src/tests/globalStyles.e2e.ts
index 35341d3c847..867f57c6411 100644
--- a/packages/calcite-components/src/tests/globalStyles.e2e.ts
+++ b/packages/calcite-components/src/tests/globalStyles.e2e.ts
@@ -1,5 +1,7 @@
-import { newE2EPage } from "@stencil/core/testing";
+import { E2EElement, newE2EPage, E2EPage } from "@stencil/core/testing";
import { html } from "../../support/formatting";
+import { skipAnimations } from "../tests/utils";
+
describe("global styles", () => {
describe("animation", () => {
const snippet = `
@@ -92,4 +94,130 @@ describe("global styles", () => {
});
expect(eleTransitionDuration).toEqual("0.15s");
});
+
+ describe("stacked focus-trap components", () => {
+ const componentStack = html`
+
+
+
+ Open Modal from Sheet
+
+
+
+
+
+
This is an example modal that opens from a Sheet.
+
+ Open Another Modal
+
+
+
+
+
+ This is an example of a another modal that opens from a modal. This modal an input date picker, a combobox, a
+ dropdown, a popover and a tooltip.
+
+
+
+
+
+
+
+
+
+
+ Scale S
+
+ List
+ Grid
+
+
+
+
+
Example Popover.
+
+ Input Date Picker
+
+
+
+ Input Time Picker
+
+
+
+
+
Example Popover
+
Example Tooltip
+
auto
+
+
+ Open Sheet
+ `;
+
+ it("closes a stack of open components sequentially in visual order", async () => {
+ const page = await newE2EPage();
+ await page.setContent(componentStack);
+ await skipAnimations(page);
+
+ async function testStackEscapeSequence(page: E2EPage, pickerType: string) {
+ async function openAndCheckVisibility(element: E2EElement) {
+ element.setProperty("open", true);
+ await page.waitForChanges();
+ expect(await element.isVisible()).toBe(true);
+ }
+
+ const sheet = await page.find("calcite-sheet");
+ await openAndCheckVisibility(sheet);
+
+ const firstModal = await page.find("#example-modal");
+ await openAndCheckVisibility(firstModal);
+
+ const secondModal = await page.find("#another-modal");
+ await openAndCheckVisibility(secondModal);
+
+ const popover = await page.find("calcite-popover");
+ await openAndCheckVisibility(popover);
+
+ const inputPicker = await page.find(pickerType);
+ inputPicker.click();
+ await page.waitForChanges();
+ expect(await inputPicker.getProperty("open")).toBe(true);
+
+ async function testEscapeAndCheckOpenState(elements: E2EElement[]) {
+ for (let i = 0; i < elements.length; i++) {
+ await page.keyboard.press("Escape");
+ await page.waitForChanges();
+ expect(await elements[i].getProperty("open")).toBe(false);
+
+ for (let j = 0; j < elements.length; j++) {
+ const expectedOpenState = j > i;
+ expect(await elements[j].getProperty("open")).toBe(expectedOpenState);
+ }
+ }
+ }
+
+ await testEscapeAndCheckOpenState([inputPicker, popover, secondModal, firstModal, sheet]);
+ }
+
+ await testStackEscapeSequence(page, "calcite-input-date-picker");
+ await testStackEscapeSequence(page, "calcite-input-time-picker");
+ });
+ });
});
From 55fbb0726d0f951ab968ea5a9745c770a35d2e63 Mon Sep 17 00:00:00 2001
From: eliza
Date: Wed, 8 May 2024 12:44:50 -0700
Subject: [PATCH 11/62] fix failing tests
---
packages/calcite-components/src/utils/focusTrapComponent.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/calcite-components/src/utils/focusTrapComponent.ts b/packages/calcite-components/src/utils/focusTrapComponent.ts
index 137235c9d76..8b40898fe23 100644
--- a/packages/calcite-components/src/utils/focusTrapComponent.ts
+++ b/packages/calcite-components/src/utils/focusTrapComponent.ts
@@ -72,7 +72,7 @@ export function connectFocusTrap(component: FocusTrapComponent, options?: Connec
clickOutsideDeactivates: !component.outsideCloseDisabled ?? true,
escapeDeactivates: !component.escapeDisabled ?? true,
fallbackFocus: focusTrapNode,
- onDeactivate: () => component.onFocusTrapDeactivate(),
+ onDeactivate: () => component.onFocusTrapDeactivate?.(),
setReturnFocus: (el) => {
focusElement(el as FocusableElement);
return false;
From 0af108e3cfcc07693d411b1a9cc825a3de8771a9 Mon Sep 17 00:00:00 2001
From: eliza
Date: Thu, 20 Jun 2024 10:57:09 -0700
Subject: [PATCH 12/62] add wait for events open/close to input-date-picker for
additional check
---
.../input-date-picker.e2e.ts | 49 +++++++++++++++++--
1 file changed, 46 insertions(+), 3 deletions(-)
diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts b/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts
index f26060794a8..1ccfde3e9dc 100644
--- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts
+++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts
@@ -13,7 +13,7 @@ import {
} from "../../tests/commonTests";
import { html } from "../../../support/formatting";
import { CSS as MONTH_HEADER_CSS } from "../date-picker-month-header/resources";
-import { getFocusedElementProp, skipAnimations } from "../../tests/utils";
+import { getFocusedElementProp, GlobalTestProps, skipAnimations } from "../../tests/utils";
import { CSS } from "./resources";
const animationDurationInMs = 200;
@@ -344,23 +344,40 @@ describe("calcite-input-date-picker", () => {
await skipAnimations(page);
await page.waitForChanges();
inputDatePicker = await page.find("calcite-input-date-picker");
+ type InputDatePickerEventOrderWindow = GlobalTestProps<{ events: string[] }>;
+
+ await page.$eval("calcite-input-date-picker", (sheet: HTMLCalciteInputDatePickerElement) => {
+ const receivedEvents: string[] = [];
+ (window as InputDatePickerEventOrderWindow).events = receivedEvents;
+
+ ["calciteInputDatePickerOpen", "calciteInputDatePickerClose"].forEach((eventType) => {
+ sheet.addEventListener(eventType, (event) => receivedEvents.push(event.type));
+ });
+ });
});
it("toggles the date picker when clicked", async () => {
+ const openSpy = await inputDatePicker.spyOnEvent("calciteInputDatePickerOpen");
+ const closeSpy = await inputDatePicker.spyOnEvent("calciteInputDatePickerClose");
+
let calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`);
expect(await calendar.isVisible()).toBe(false);
await inputDatePicker.click();
+
await page.waitForChanges();
- calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`);
+ expect(openSpy).toHaveReceivedEventTimes(1);
+ calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`);
expect(await calendar.isVisible()).toBe(true);
await inputDatePicker.click();
+
await page.waitForChanges();
- calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`);
+ expect(closeSpy).toHaveReceivedEventTimes(1);
+ calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`);
expect(await calendar.isVisible()).toBe(false);
});
@@ -404,6 +421,8 @@ describe("calcite-input-date-picker", () => {
}
it("toggles the date picker when clicked", async () => {
+ const openSpy = await inputDatePicker.spyOnEvent("calciteInputDatePickerOpen");
+ const closeSpy = await inputDatePicker.spyOnEvent("calciteInputDatePickerClose");
const calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`);
expect(await isCalendarVisible(calendar, "start")).toBe(false);
@@ -428,11 +447,13 @@ describe("calcite-input-date-picker", () => {
await resetFocus(page);
await startInput.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(1);
expect(await isCalendarVisible(calendar, "start")).toBe(true);
await startInput.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(1);
expect(await isCalendarVisible(calendar, "start")).toBe(false);
@@ -441,11 +462,13 @@ describe("calcite-input-date-picker", () => {
await resetFocus(page);
await startInputToggle.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(2);
expect(await isCalendarVisible(calendar, "start")).toBe(true);
await startInputToggle.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(2);
expect(await isCalendarVisible(calendar, "start")).toBe(false);
@@ -454,11 +477,13 @@ describe("calcite-input-date-picker", () => {
await resetFocus(page);
await endInput.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(3);
expect(await isCalendarVisible(calendar, "end")).toBe(true);
await endInput.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(3);
expect(await isCalendarVisible(calendar, "end")).toBe(false);
@@ -467,11 +492,13 @@ describe("calcite-input-date-picker", () => {
await resetFocus(page);
await endInputToggle.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(4);
expect(await isCalendarVisible(calendar, "end")).toBe(true);
await endInputToggle.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(4);
expect(await isCalendarVisible(calendar, "end")).toBe(false);
@@ -480,11 +507,13 @@ describe("calcite-input-date-picker", () => {
await resetFocus(page);
await startInput.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(5);
expect(await isCalendarVisible(calendar, "start")).toBe(true);
await startInputToggle.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(5);
expect(await isCalendarVisible(calendar, "start")).toBe(false);
@@ -493,11 +522,13 @@ describe("calcite-input-date-picker", () => {
await resetFocus(page);
await startInputToggle.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(6);
expect(await isCalendarVisible(calendar, "start")).toBe(true);
await startInput.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(6);
expect(await isCalendarVisible(calendar, "start")).toBe(false);
@@ -506,11 +537,13 @@ describe("calcite-input-date-picker", () => {
await resetFocus(page);
await endInput.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(7);
expect(await isCalendarVisible(calendar, "end")).toBe(true);
await endInputToggle.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(7);
expect(await isCalendarVisible(calendar, "end")).toBe(false);
@@ -519,11 +552,13 @@ describe("calcite-input-date-picker", () => {
await resetFocus(page);
await endInputToggle.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(8);
expect(await isCalendarVisible(calendar, "end")).toBe(true);
await endInput.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(8);
expect(await isCalendarVisible(calendar, "end")).toBe(false);
@@ -532,11 +567,13 @@ describe("calcite-input-date-picker", () => {
await resetFocus(page);
await startInput.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(9);
expect(await isCalendarVisible(calendar, "start")).toBe(true);
await endInputToggle.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(9);
expect(await isCalendarVisible(calendar, "end")).toBe(true);
@@ -545,11 +582,13 @@ describe("calcite-input-date-picker", () => {
await resetFocus(page);
await startInputToggle.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(10);
expect(await isCalendarVisible(calendar, "start")).toBe(true);
await endInput.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(10);
expect(await isCalendarVisible(calendar, "end")).toBe(true);
@@ -562,11 +601,13 @@ describe("calcite-input-date-picker", () => {
await resetFocus(page);
await endInput.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(11);
expect(await isCalendarVisible(calendar, "end")).toBe(true);
await startInputToggle.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(11);
expect(await isCalendarVisible(calendar, "start")).toBe(true);
@@ -575,12 +616,14 @@ describe("calcite-input-date-picker", () => {
await resetFocus(page);
await endInputToggle.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(12);
expect(await isCalendarVisible(calendar, "end")).toBe(true);
await resetFocus(page);
await startInput.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(12);
expect(await isCalendarVisible(calendar, "start")).toBe(true);
});
From 47cf21d37b3ae9581f5060886c17c4f7b78d266b Mon Sep 17 00:00:00 2001
From: eliza
Date: Thu, 20 Jun 2024 11:25:44 -0700
Subject: [PATCH 13/62] add wait for events open/close to input-time-picker for
additional check
---
.../input-time-picker.e2e.ts | 27 ++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts b/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts
index fbabd7beb20..8179589933e 100644
--- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts
+++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts
@@ -12,7 +12,7 @@ import {
renders,
t9n,
} from "../../tests/commonTests";
-import { getFocusedElementProp, skipAnimations, waitForAnimationFrame } from "../../tests/utils";
+import { getFocusedElementProp, GlobalTestProps, skipAnimations, waitForAnimationFrame } from "../../tests/utils";
import { html } from "../../../support/formatting";
import { openClose } from "../../tests/commonTests";
@@ -860,6 +860,21 @@ describe("calcite-input-time-picker", () => {
const popover = await page.find("calcite-input-time-picker >>> calcite-popover");
const stopgapDelayUntilOpenCloseEventsAreImplemented = 500;
+ type InputTimePickerEventOrderWindow = GlobalTestProps<{ events: string[] }>;
+
+ await page.$eval("calcite-input-time-picker", (sheet: HTMLCalciteInputTimePickerElement) => {
+ const receivedEvents: string[] = [];
+ (window as InputTimePickerEventOrderWindow).events = receivedEvents;
+
+ ["calciteInputTimePickerOpen", "calciteInputTimePickerClose"].forEach((eventType) => {
+ sheet.addEventListener(eventType, (event) => receivedEvents.push(event.type));
+ });
+ });
+
+ const inputTimePicker = await page.find("calcite-input-time-picker");
+ const openSpy = await inputTimePicker.spyOnEvent("calciteInputDatePickerOpen");
+ const closeSpy = await inputTimePicker.spyOnEvent("calciteInputDatePickerClose");
+
await page.keyboard.press("Tab");
expect(await getFocusedElementProp(page, "tagName")).toBe("CALCITE-INPUT-TIME-PICKER");
@@ -875,6 +890,7 @@ describe("calcite-input-time-picker", () => {
await page.keyboard.press("ArrowDown");
await page.waitForChanges();
await page.waitForTimeout(stopgapDelayUntilOpenCloseEventsAreImplemented);
+ expect(openSpy).toHaveReceivedEventTimes(1);
expect(await popover.isVisible()).toBe(true);
expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-TIME-PICKER");
@@ -890,6 +906,7 @@ describe("calcite-input-time-picker", () => {
await page.keyboard.press("Escape");
await page.waitForChanges();
await page.waitForTimeout(stopgapDelayUntilOpenCloseEventsAreImplemented);
+ expect(closeSpy).toHaveReceivedEventTimes(1);
expect(await popover.isVisible()).toBe(false);
expect(await getFocusedElementProp(page, "tagName")).toBe("CALCITE-INPUT-TIME-PICKER");
@@ -923,17 +940,21 @@ describe("calcite-input-time-picker", () => {
it("toggles the time picker when clicked", async () => {
let popover = await page.find("calcite-input-time-picker >>> calcite-popover");
+ const openSpy = await inputTimePicker.spyOnEvent("calciteInputDatePickerOpen");
+ const closeSpy = await inputTimePicker.spyOnEvent("calciteInputDatePickerClose");
expect(await popover.isVisible()).toBe(false);
await inputTimePicker.click();
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(1);
popover = await page.find("calcite-input-time-picker >>> calcite-popover");
expect(await popover.isVisible()).toBe(true);
await inputTimePicker.click();
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(1);
popover = await page.find("calcite-input-time-picker >>> calcite-popover");
expect(await popover.isVisible()).toBe(false);
@@ -941,6 +962,8 @@ describe("calcite-input-time-picker", () => {
it("toggles the time picker when using arrow down/escape key", async () => {
let popover = await page.find("calcite-input-time-picker >>> calcite-popover");
+ const openSpy = await inputTimePicker.spyOnEvent("calciteInputDatePickerOpen");
+ const closeSpy = await inputTimePicker.spyOnEvent("calciteInputDatePickerClose");
expect(await popover.isVisible()).toBe(false);
@@ -948,12 +971,14 @@ describe("calcite-input-time-picker", () => {
await page.waitForChanges();
await page.keyboard.press("ArrowDown");
await page.waitForChanges();
+ expect(openSpy).toHaveReceivedEventTimes(1);
popover = await page.find("calcite-input-time-picker >>> calcite-popover");
expect(await popover.isVisible()).toBe(true);
await page.keyboard.press("Escape");
await page.waitForChanges();
+ expect(closeSpy).toHaveReceivedEventTimes(1);
popover = await page.find("calcite-input-time-picker >>> calcite-popover");
expect(await popover.isVisible()).toBe(false);
From 8ca1dc56bd941c0b3dfe5a52b3254a584196a46d Mon Sep 17 00:00:00 2001
From: eliza
Date: Tue, 30 Jul 2024 14:32:53 -0700
Subject: [PATCH 14/62] docs
---
.../calcite-components/src/components.d.ts | 105 +-----------------
1 file changed, 2 insertions(+), 103 deletions(-)
diff --git a/packages/calcite-components/src/components.d.ts b/packages/calcite-components/src/components.d.ts
index 1db6e346670..346aed4f24b 100644
--- a/packages/calcite-components/src/components.d.ts
+++ b/packages/calcite-components/src/components.d.ts
@@ -10,192 +10,92 @@ import { RequestedItem } from "./components/accordion/interfaces";
import { IconName } from "./components/icon/interfaces";
import { RequestedItem as RequestedItem1 } from "./components/accordion-item/interfaces";
import { ActionMessages } from "./components/action/assets/action/t9n";
-import { ActionMessages } from "./components/action/assets/action/t9n";
-import { ActionBarMessages } from "./components/action-bar/assets/action-bar/t9n";
import { FlipPlacement, LogicalPlacement, MenuPlacement, OverlayPositioning, ReferenceElement } from "./utils/floating-ui";
-import { ActionGroupMessages } from "./components/action-group/assets/action-group/t9n";
-import { ActionPadMessages } from "./components/action-pad/assets/action-pad/t9n";
import { ActionBarMessages } from "./components/action-bar/assets/action-bar/t9n";
import { Columns } from "./components/action-group/interfaces";
-import { AlertMessages } from "./components/alert/assets/alert/t9n";
import { ActionGroupMessages } from "./components/action-group/assets/action-group/t9n";
-import { BlockMessages } from "./components/block/assets/block/t9n";
import { ActionPadMessages } from "./components/action-pad/assets/action-pad/t9n";
-import { BlockSectionMessages } from "./components/block-section/assets/block-section/t9n";
import { AlertDuration, Sync } from "./components/alert/interfaces";
-import { ButtonMessages } from "./components/button/assets/button/t9n";
-import { CardMessages } from "./components/card/assets/card/t9n";
import { NumberingSystem } from "./utils/locale";
-import { CarouselMessages } from "./components/carousel/assets/carousel/t9n";
import { AlertMessages } from "./components/alert/assets/alert/t9n";
-import { ChipMessages } from "./components/chip/assets/chip/t9n";
import { HeadingLevel } from "./components/functional/Heading";
import { BlockMessages } from "./components/block/assets/block/t9n";
-import { ColorPickerMessages } from "./components/color-picker/assets/color-picker/t9n";
import { BlockSectionToggleDisplay } from "./components/block-section/interfaces";
-import { ComboboxMessages } from "./components/combobox/assets/combobox/t9n";
-import { DatePickerMessages } from "./components/date-picker/assets/date-picker/t9n";
import { BlockSectionMessages } from "./components/block-section/assets/block-section/t9n";
import { ButtonAlignment, DropdownIconType } from "./components/button/interfaces";
-import { DialogMessages } from "./components/dialog/assets/dialog/t9n";
import { ButtonMessages } from "./components/button/assets/button/t9n";
import { CardMessages } from "./components/card/assets/card/t9n";
import { ArrowType, AutoplayType } from "./components/carousel/interfaces";
import { CarouselMessages } from "./components/carousel/assets/carousel/t9n";
-import { FilterMessages } from "./components/filter/assets/filter/t9n";
import { MutableValidityState } from "./utils/form";
-import { FlowItemMessages } from "./components/flow-item/assets/flow-item/t9n";
import { ChipMessages } from "./components/chip/assets/chip/t9n";
-import { HandleMessages } from "./components/handle/assets/handle/t9n";
import { ColorValue, InternalColor } from "./components/color-picker/interfaces";
-import { InlineEditableMessages } from "./components/inline-editable/assets/inline-editable/t9n";
import { Format } from "./components/color-picker/utils";
-import { InputMessages } from "./components/input/assets/input/t9n";
-import { InputDatePickerMessages } from "./components/input-date-picker/assets/input-date-picker/t9n";
-import { InputNumberMessages } from "./components/input-number/assets/input-number/t9n";
-import { InputTextMessages } from "./components/input-text/assets/input-text/t9n";
-import { InputTimePickerMessages } from "./components/input-time-picker/assets/input-time-picker/t9n";
-import { TimePickerMessages } from "./components/time-picker/assets/time-picker/t9n";
-import { InputTimeZoneMessages } from "./components/input-time-zone/assets/input-time-zone/t9n";
import { ColorPickerMessages } from "./components/color-picker/assets/color-picker/t9n";
import { ComboboxChildElement, SelectionDisplay } from "./components/combobox/interfaces";
import { ComboboxMessages } from "./components/combobox/assets/combobox/t9n";
-import { ListMessages } from "./components/list/assets/list/t9n";
import { DatePickerMessages } from "./components/date-picker/assets/date-picker/t9n";
-import { ListItemMessages } from "./components/list-item/assets/list-item/t9n";
-import { MenuMessages } from "./components/menu/assets/menu/t9n";
-import { MenuItemMessages } from "./components/menu-item/assets/menu-item/t9n";
import { DateLocaleData } from "./components/date-picker/utils";
import { HoverRange } from "./utils/date";
-import { ModalMessages } from "./components/modal/assets/modal/t9n";
-import { NoticeMessages } from "./components/notice/assets/notice/t9n";
-import { PaginationMessages } from "./components/pagination/assets/pagination/t9n";
-import { PanelMessages } from "./components/panel/assets/panel/t9n";
import { DialogMessages } from "./components/dialog/assets/dialog/t9n";
import { OverlayPositioning as OverlayPositioning1 } from "./components";
-import { PickListItemMessages } from "./components/pick-list-item/assets/pick-list-item/t9n";
-import { PopoverMessages } from "./components/popover/assets/popover/t9n";
-import { RatingMessages } from "./components/rating/assets/rating/t9n";
-import { ScrimMessages } from "./components/scrim/assets/scrim/t9n";
import { DialogPlacement } from "./components/dialog/interfaces";
import { RequestedItem as RequestedItem2 } from "./components/dropdown-group/interfaces";
-import { ShellPanelMessages } from "./components/shell-panel/assets/shell-panel/t9n";
import { ItemKeyboardEvent } from "./components/dropdown/interfaces";
import { FilterMessages } from "./components/filter/assets/filter/t9n";
-import { StepperMessages } from "./components/stepper/assets/stepper/t9n";
-import { StepperItemMessages } from "./components/stepper-item/assets/stepper-item/t9n";
import { FlowItemLikeElement } from "./components/flow/interfaces";
-import { TabNavMessages } from "./components/tab-nav/assets/tab-nav/t9n";
import { FlowItemMessages } from "./components/flow-item/assets/flow-item/t9n";
import { ColorStop, DataSeries } from "./components/graph/interfaces";
-import { TabTitleMessages } from "./components/tab-title/assets/tab-title/t9n";
import { HandleMessages } from "./components/handle/assets/handle/t9n";
-import { TableMessages } from "./components/table/assets/table/t9n";
-import { TableCellMessages } from "./components/table-cell/assets/table-cell/t9n";
-import { TableHeaderMessages } from "./components/table-header/assets/table-header/t9n";
-import { TextAreaMessages } from "./components/text-area/assets/text-area/t9n";
import { HandleChange, HandleNudge } from "./components/handle/interfaces";
import { InlineEditableMessages } from "./components/inline-editable/assets/inline-editable/t9n";
-import { TipMessages } from "./components/tip/assets/tip/t9n";
-import { TipManagerMessages } from "./components/tip-manager/assets/tip-manager/t9n";
import { InputPlacement } from "./components/input/interfaces";
-import { ValueListMessages } from "./components/value-list/assets/value-list/t9n";
import { InputMessages } from "./components/input/assets/input/t9n";
import { InputDatePickerMessages } from "./components/input-date-picker/assets/input-date-picker/t9n";
import { InputNumberMessages } from "./components/input-number/assets/input-number/t9n";
import { InputTextMessages } from "./components/input-text/assets/input-text/t9n";
import { InputTimePickerMessages } from "./components/input-time-picker/assets/input-time-picker/t9n";
-export { ActionMessages } from "./components/action/assets/action/t9n";
import { TimePickerMessages } from "./components/time-picker/assets/time-picker/t9n";
-export { ActionBarMessages } from "./components/action-bar/assets/action-bar/t9n";
import { InputTimeZoneMessages } from "./components/input-time-zone/assets/input-time-zone/t9n";
-export { ActionGroupMessages } from "./components/action-group/assets/action-group/t9n";
-export { ActionPadMessages } from "./components/action-pad/assets/action-pad/t9n";
import { OffsetStyle, TimeZoneMode } from "./components/input-time-zone/interfaces";
import { ListDragDetail } from "./components/list/interfaces";
-export { AlertMessages } from "./components/alert/assets/alert/t9n";
import { ItemData } from "./components/list-item/interfaces";
-export { BlockMessages } from "./components/block/assets/block/t9n";
import { ListMessages } from "./components/list/assets/list/t9n";
-export { BlockSectionMessages } from "./components/block-section/assets/block-section/t9n";
import { SelectionAppearance } from "./components/list/resources";
-export { ButtonMessages } from "./components/button/assets/button/t9n";
-export { CardMessages } from "./components/card/assets/card/t9n";
import { ListItemMessages } from "./components/list-item/assets/list-item/t9n";
-export { CarouselMessages } from "./components/carousel/assets/carousel/t9n";
import { MenuMessages } from "./components/menu/assets/menu/t9n";
-export { ChipMessages } from "./components/chip/assets/chip/t9n";
import { MenuItemMessages } from "./components/menu-item/assets/menu-item/t9n";
import { MenuItemCustomEvent } from "./components/menu-item/interfaces";
-export { ColorPickerMessages } from "./components/color-picker/assets/color-picker/t9n";
import { MeterFillType, MeterLabelType } from "./components/meter/interfaces";
-export { ComboboxMessages } from "./components/combobox/assets/combobox/t9n";
-export { DatePickerMessages } from "./components/date-picker/assets/date-picker/t9n";
import { ModalMessages } from "./components/modal/assets/modal/t9n";
import { NoticeMessages } from "./components/notice/assets/notice/t9n";
-export { DialogMessages } from "./components/dialog/assets/dialog/t9n";
import { PaginationMessages } from "./components/pagination/assets/pagination/t9n";
import { PanelMessages } from "./components/panel/assets/panel/t9n";
import { ItemData as ItemData1, ListFocusId } from "./components/pick-list/shared-list-logic";
import { ICON_TYPES } from "./components/pick-list/resources";
-export { FilterMessages } from "./components/filter/assets/filter/t9n";
import { PickListItemMessages } from "./components/pick-list-item/assets/pick-list-item/t9n";
-export { FlowItemMessages } from "./components/flow-item/assets/flow-item/t9n";
import { PopoverMessages } from "./components/popover/assets/popover/t9n";
-export { HandleMessages } from "./components/handle/assets/handle/t9n";
import { RatingMessages } from "./components/rating/assets/rating/t9n";
-export { InlineEditableMessages } from "./components/inline-editable/assets/inline-editable/t9n";
import { ScrimMessages } from "./components/scrim/assets/scrim/t9n";
-export { InputMessages } from "./components/input/assets/input/t9n";
-export { InputDatePickerMessages } from "./components/input-date-picker/assets/input-date-picker/t9n";
-export { InputNumberMessages } from "./components/input-number/assets/input-number/t9n";
-export { InputTextMessages } from "./components/input-text/assets/input-text/t9n";
-export { InputTimePickerMessages } from "./components/input-time-picker/assets/input-time-picker/t9n";
-export { TimePickerMessages } from "./components/time-picker/assets/time-picker/t9n";
-export { InputTimeZoneMessages } from "./components/input-time-zone/assets/input-time-zone/t9n";
import { DisplayMode } from "./components/sheet/interfaces";
import { DisplayMode as DisplayMode1 } from "./components/shell-panel/interfaces";
import { ShellPanelMessages } from "./components/shell-panel/assets/shell-panel/t9n";
-export { ListMessages } from "./components/list/assets/list/t9n";
import { DragDetail } from "./utils/sortableComponent";
-export { ListItemMessages } from "./components/list-item/assets/list-item/t9n";
-export { MenuMessages } from "./components/menu/assets/menu/t9n";
-export { MenuItemMessages } from "./components/menu-item/assets/menu-item/t9n";
import { StepperItemChangeEventDetail, StepperItemEventDetail, StepperItemKeyEventDetail, StepperLayout } from "./components/stepper/interfaces";
import { StepperMessages } from "./components/stepper/assets/stepper/t9n";
-export { ModalMessages } from "./components/modal/assets/modal/t9n";
-export { NoticeMessages } from "./components/notice/assets/notice/t9n";
-export { PaginationMessages } from "./components/pagination/assets/pagination/t9n";
-export { PanelMessages } from "./components/panel/assets/panel/t9n";
import { StepperItemMessages } from "./components/stepper-item/assets/stepper-item/t9n";
import { TabID, TabLayout, TabPosition } from "./components/tabs/interfaces";
-export { PickListItemMessages } from "./components/pick-list-item/assets/pick-list-item/t9n";
-export { PopoverMessages } from "./components/popover/assets/popover/t9n";
-export { RatingMessages } from "./components/rating/assets/rating/t9n";
-export { ScrimMessages } from "./components/scrim/assets/scrim/t9n";
import { TabNavMessages } from "./components/tab-nav/assets/tab-nav/t9n";
import { Element } from "@stencil/core";
-export { ShellPanelMessages } from "./components/shell-panel/assets/shell-panel/t9n";
import { TabChangeEventDetail, TabCloseEventDetail } from "./components/tab/interfaces";
import { TabTitleMessages } from "./components/tab-title/assets/tab-title/t9n";
-export { StepperMessages } from "./components/stepper/assets/stepper/t9n";
-export { StepperItemMessages } from "./components/stepper-item/assets/stepper-item/t9n";
import { RowType, TableInteractionMode, TableLayout, TableRowFocusEvent, TableSelectionDisplay } from "./components/table/interfaces";
-export { TabNavMessages } from "./components/tab-nav/assets/tab-nav/t9n";
import { TableMessages } from "./components/table/assets/table/t9n";
import { TableCellMessages } from "./components/table-cell/assets/table-cell/t9n";
-export { TabTitleMessages } from "./components/tab-title/assets/tab-title/t9n";
import { TableHeaderMessages } from "./components/table-header/assets/table-header/t9n";
-export { TableMessages } from "./components/table/assets/table/t9n";
-export { TableCellMessages } from "./components/table-cell/assets/table-cell/t9n";
-export { TableHeaderMessages } from "./components/table-header/assets/table-header/t9n";
-export { TextAreaMessages } from "./components/text-area/assets/text-area/t9n";
import { TextAreaMessages } from "./components/text-area/assets/text-area/t9n";
import { TileSelectType } from "./components/tile-select/interfaces";
-export { TipMessages } from "./components/tip/assets/tip/t9n";
-export { TipManagerMessages } from "./components/tip-manager/assets/tip-manager/t9n";
import { TileSelectGroupLayout } from "./components/tile-select-group/interfaces";
-export { ValueListMessages } from "./components/value-list/assets/value-list/t9n";
import { TipMessages } from "./components/tip/assets/tip/t9n";
import { TipManagerMessages } from "./components/tip-manager/assets/tip-manager/t9n";
import { TreeItemSelectDetail } from "./components/tree-item/interfaces";
@@ -1879,8 +1779,7 @@ export namespace Components {
"placement": MenuPlacement;
/**
* Updates the position of the component.
- * @param delayed If true, the repositioning is delayed.
- * @returns void
+ * @param delayed
*/
"reposition": (delayed?: boolean) => Promise;
/**
@@ -4166,7 +4065,7 @@ export namespace Components {
"referenceElement": ReferenceElement | string;
/**
* Updates the position of the component.
- * @param delayed If true, delay the repositioning.
+ * @param delayed
*/
"reposition": (delayed?: boolean) => Promise;
/**
From 5861f8210bb9f07fde65b613243df8a2be5121a7 Mon Sep 17 00:00:00 2001
From: eliza
Date: Fri, 2 Aug 2024 11:52:18 -0700
Subject: [PATCH 15/62] fix timing issues with modal and sheet
---
.../src/components/modal/modal.e2e.ts | 27 ++++++++++++-------
.../src/components/sheet/sheet.e2e.ts | 5 ++++
2 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/packages/calcite-components/src/components/modal/modal.e2e.ts b/packages/calcite-components/src/components/modal/modal.e2e.ts
index a57d1ba3939..c2e55254999 100644
--- a/packages/calcite-components/src/components/modal/modal.e2e.ts
+++ b/packages/calcite-components/src/components/modal/modal.e2e.ts
@@ -153,7 +153,7 @@ describe("calcite-modal", () => {
const mockCallBack = jest.fn();
await page.exposeFunction("beforeClose", mockCallBack);
await page.setContent(`
-
+
`);
const modal = await page.find("calcite-modal");
await page.$eval(
@@ -163,13 +163,15 @@ describe("calcite-modal", () => {
window as GlobalTestProps<{ beforeClose: HTMLCalciteModalElement["beforeClose"] }>
).beforeClose),
);
+ await skipAnimations(page);
await page.waitForChanges();
+
modal.setProperty("open", true);
await page.waitForChanges();
expect(await modal.getProperty("opened")).toBe(true);
+
await page.keyboard.press("Escape");
await page.waitForChanges();
- await page.waitForChanges();
expect(mockCallBack).toHaveBeenCalledTimes(1);
expect(await modal.getProperty("opened")).toBe(false);
});
@@ -395,35 +397,42 @@ describe("calcite-modal", () => {
it("closes and allows re-opening when Escape key is pressed", async () => {
const page = await newE2EPage();
- await page.setContent(``);
+ await page.setContent(``);
await skipAnimations(page);
const modal = await page.find("calcite-modal");
- await modal.setProperty("open", true);
+
+ modal.setProperty("open", true);
await page.waitForChanges();
expect(await modal.isVisible()).toBe(true);
+
await page.keyboard.press("Escape");
await page.waitForChanges();
expect(await modal.isVisible()).toBe(false);
expect(await modal.getProperty("open")).toBe(false);
- await modal.setProperty("open", true);
+
+ modal.setProperty("open", true);
+ await page.waitForChanges();
await page.waitForChanges();
expect(await modal.isVisible()).toBe(true);
});
it("closes when Escape key is pressed and modal is open on page load", async () => {
const page = await newE2EPage();
- await page.setContent(``);
+ await page.setContent(``);
+ await skipAnimations(page);
const modal = await page.find("calcite-modal");
await page.waitForChanges();
- expect(modal).toHaveAttribute("open");
+ await page.waitForEvent("calciteModalOpen");
expect(modal).toHaveAttribute("open");
await page.keyboard.press("Escape");
+
+ await page.waitForEvent("calciteModalClose");
await page.waitForChanges();
expect(modal).not.toHaveAttribute("open");
- expect(modal).not.toHaveAttribute("open");
+
await modal.setProperty("open", true);
await page.waitForChanges();
- expect(modal).toHaveAttribute("open");
+ await page.waitForChanges();
expect(modal).toHaveAttribute("open");
});
diff --git a/packages/calcite-components/src/components/sheet/sheet.e2e.ts b/packages/calcite-components/src/components/sheet/sheet.e2e.ts
index d37aab9f41b..4f875728c4c 100644
--- a/packages/calcite-components/src/components/sheet/sheet.e2e.ts
+++ b/packages/calcite-components/src/components/sheet/sheet.e2e.ts
@@ -181,11 +181,16 @@ describe("calcite-sheet properties", () => {
window as GlobalTestProps<{ beforeClose: HTMLCalciteSheetElement["beforeClose"] }>
).beforeClose),
);
+ await skipAnimations(page);
await page.waitForChanges();
+ await page.waitForEvent("calciteSheetOpen");
expect(await sheet.getProperty("opened")).toBe(true);
+
await page.keyboard.press("Escape");
await page.waitForChanges();
await page.waitForChanges();
+ await page.waitForTimeout(500);
+
expect(mockCallBack).toHaveBeenCalledTimes(1);
expect(await sheet.getProperty("opened")).toBe(false);
});
From 95af390b02968d89d2995f3c392708040cee573a Mon Sep 17 00:00:00 2001
From: eliza
Date: Fri, 2 Aug 2024 15:02:04 -0700
Subject: [PATCH 16/62] remove focus-trapping logic and let popover handle it
---
.../input-time-picker/input-time-picker.tsx | 36 -------------------
1 file changed, 36 deletions(-)
diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
index c00ce7abb27..0ecd5f5c498 100644
--- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
+++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
@@ -53,7 +53,6 @@ import {
} from "../../utils/locale";
import {
activateFocusTrap,
- connectFocusTrap,
deactivateFocusTrap,
FocusTrapComponent,
} from "../../utils/focusTrapComponent";
@@ -689,27 +688,6 @@ export class InputTimePicker
return timeString;
}
- private popoverCloseHandler = () => {
- deactivateFocusTrap(this, {
- onDeactivate: () => {
- this.calciteInputEl.setFocus();
- this.focusOnOpen = false;
- },
- });
- this.open = false;
- };
-
- private popoverOpenHandler = () => {
- activateFocusTrap(this, {
- onActivate: () => {
- if (this.focusOnOpen) {
- this.calciteTimePickerEl.setFocus();
- this.focusOnOpen = false;
- }
- },
- });
- };
-
keyDownHandler = (event: KeyboardEvent): void => {
const { defaultPrevented, key } = event;
@@ -872,17 +850,6 @@ export class InputTimePicker
this.transitionEl = el;
};
- private setCalciteTimePickerEl = (el: HTMLCalciteTimePickerElement): void => {
- this.calciteTimePickerEl = el;
- connectFocusTrap(this, {
- focusTrapEl: el,
- focusTrapOptions: {
- initialFocus: false,
- setReturnFocus: false,
- },
- });
- };
-
private setInputValue = (newInputValue: string): void => {
if (!this.calciteInputEl) {
return;
@@ -1046,8 +1013,6 @@ export class InputTimePicker
id={dialogId}
label={messages.chooseTime}
lang={this.effectiveLocale}
- onCalcitePopoverClose={this.popoverCloseHandler}
- onCalcitePopoverOpen={this.popoverOpenHandler}
open={this.open}
overlayPositioning={this.overlayPositioning}
placement={this.placement}
@@ -1060,7 +1025,6 @@ export class InputTimePicker
messageOverrides={this.messageOverrides}
numberingSystem={this.numberingSystem}
onCalciteInternalTimePickerChange={this.timePickerChangeHandler}
- ref={this.setCalciteTimePickerEl}
scale={this.scale}
step={this.step}
tabIndex={this.open ? undefined : -1}
From 69dbd5a463205ce8cc1dceda9c2881d6ee6eda73 Mon Sep 17 00:00:00 2001
From: eliza
Date: Fri, 2 Aug 2024 15:15:48 -0700
Subject: [PATCH 17/62] WIP
---
.../src/components/input-time-picker/input-time-picker.tsx | 3 ---
1 file changed, 3 deletions(-)
diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
index 0ecd5f5c498..136b25b7880 100644
--- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
+++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
@@ -381,8 +381,6 @@ export class InputTimePicker
private calciteTimePickerEl: HTMLCalciteTimePickerElement;
- private focusOnOpen = false;
-
focusTrap: FocusTrap;
private dialogId = `time-picker-dialog--${guid()}`;
@@ -724,7 +722,6 @@ export class InputTimePicker
}
} else if (key === "ArrowDown") {
this.open = true;
- this.focusOnOpen = true;
event.preventDefault();
}
};
From ba39a7f3a0dc5949b0c868ab9786d9f2efb74653 Mon Sep 17 00:00:00 2001
From: eliza
Date: Fri, 2 Aug 2024 16:33:26 -0700
Subject: [PATCH 18/62] WIP
---
.../src/components/input-time-picker/input-time-picker.tsx | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
index 136b25b7880..b2fbd171767 100644
--- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
+++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
@@ -842,6 +842,10 @@ export class InputTimePicker
this.popoverEl = el;
};
+ private setCalciteTimePickerEl = (el: HTMLCalciteTimePickerElement): void => {
+ this.calciteTimePickerEl = el;
+ };
+
private setInputAndTransitionEl = (el: HTMLCalciteInputElement): void => {
this.calciteInputEl = el;
this.transitionEl = el;
@@ -1022,6 +1026,7 @@ export class InputTimePicker
messageOverrides={this.messageOverrides}
numberingSystem={this.numberingSystem}
onCalciteInternalTimePickerChange={this.timePickerChangeHandler}
+ ref={this.setCalciteTimePickerEl}
scale={this.scale}
step={this.step}
tabIndex={this.open ? undefined : -1}
From 3e4b38eead18459e419bf88a909254772ce5834b Mon Sep 17 00:00:00 2001
From: eliza
Date: Sat, 3 Aug 2024 21:00:26 -0700
Subject: [PATCH 19/62] enable focus trap in input-time-picker and fix failing
tests
---
.../input-time-picker/input-time-picker.e2e.ts | 12 ++++++------
.../input-time-picker/input-time-picker.tsx | 8 +++++++-
2 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts b/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts
index 319ae4af726..92bb0a9059a 100644
--- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts
+++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts
@@ -874,8 +874,8 @@ describe("calcite-input-time-picker", () => {
});
const inputTimePicker = await page.find("calcite-input-time-picker");
- const openSpy = await inputTimePicker.spyOnEvent("calciteInputDatePickerOpen");
- const closeSpy = await inputTimePicker.spyOnEvent("calciteInputDatePickerClose");
+ const openSpy = await inputTimePicker.spyOnEvent("calciteInputTimePickerOpen");
+ const closeSpy = await inputTimePicker.spyOnEvent("calciteInputTimePickerClose");
await page.keyboard.press("Tab");
expect(await getFocusedElementProp(page, "tagName")).toBe("CALCITE-INPUT-TIME-PICKER");
@@ -942,8 +942,8 @@ describe("calcite-input-time-picker", () => {
it("toggles the time picker when clicked", async () => {
let popover = await page.find("calcite-input-time-picker >>> calcite-popover");
- const openSpy = await inputTimePicker.spyOnEvent("calciteInputDatePickerOpen");
- const closeSpy = await inputTimePicker.spyOnEvent("calciteInputDatePickerClose");
+ const openSpy = await inputTimePicker.spyOnEvent("calciteInputTimePickerOpen");
+ const closeSpy = await inputTimePicker.spyOnEvent("calciteInputTimePickerClose");
expect(await popover.isVisible()).toBe(false);
@@ -964,8 +964,8 @@ describe("calcite-input-time-picker", () => {
it("toggles the time picker when using arrow down/escape key", async () => {
let popover = await page.find("calcite-input-time-picker >>> calcite-popover");
- const openSpy = await inputTimePicker.spyOnEvent("calciteInputDatePickerOpen");
- const closeSpy = await inputTimePicker.spyOnEvent("calciteInputDatePickerClose");
+ const openSpy = await inputTimePicker.spyOnEvent("calciteInputTimePickerOpen");
+ const closeSpy = await inputTimePicker.spyOnEvent("calciteInputTimePickerClose");
expect(await popover.isVisible()).toBe(false);
diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
index b2fbd171767..0484450203e 100644
--- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
+++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx
@@ -5,6 +5,7 @@ import {
EventEmitter,
h,
Host,
+ Listen,
Method,
Prop,
State,
@@ -444,6 +445,11 @@ export class InputTimePicker
/** Fires when the component is open and animation is complete. */
@Event({ cancelable: false }) calciteInputTimePickerOpen: EventEmitter;
+ @Listen("calcitePopoverClose")
+ calcitePopoverCloseHandler(): void {
+ this.open = false;
+ }
+
//--------------------------------------------------------------------------
//
// Event Listeners
@@ -1010,7 +1016,7 @@ export class InputTimePicker
{!this.readOnly && this.renderToggleIcon(this.open)}
Date: Wed, 7 Aug 2024 23:03:09 -0700
Subject: [PATCH 20/62] Helper to manage focusTrap by determining if a click
event occurred outside of the component.
---
.../src/utils/focusTrapComponent.ts | 22 ++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/packages/calcite-components/src/utils/focusTrapComponent.ts b/packages/calcite-components/src/utils/focusTrapComponent.ts
index 461ba1391c2..75295554f15 100644
--- a/packages/calcite-components/src/utils/focusTrapComponent.ts
+++ b/packages/calcite-components/src/utils/focusTrapComponent.ts
@@ -14,8 +14,10 @@ export interface FocusTrapComponent {
/** When `true`, disables the default close on escape behavior. */
escapeDisabled?: boolean;
- /** When `true`, disables the closing of the component when clicked outside. */
- outsideCloseDisabled?: boolean;
+ /**
+ * When `true`, indicates the click has happened outside of the component and can therefore deactivate focusTrap.
+ */
+ clickOutsideDeactivates?: (event: MouseEvent) => boolean;
/**
* When `true`, prevents focus trapping.
@@ -69,7 +71,7 @@ export function connectFocusTrap(component: FocusTrapComponent, options?: Connec
}
const focusTrapOptions: FocusTrapOptions = {
- clickOutsideDeactivates: !component.outsideCloseDisabled ?? true,
+ clickOutsideDeactivates: component.clickOutsideDeactivates ?? true,
escapeDeactivates: !component.escapeDisabled ?? true,
fallbackFocus: focusTrapNode,
onDeactivate: () => component.onFocusTrapDeactivate?.(),
@@ -131,3 +133,17 @@ export function deactivateFocusTrap(
export function updateFocusTrapElements(component: FocusTrapComponent): void {
component.focusTrap?.updateContainerElements(component.el);
}
+
+/**
+ * Helper to manage focusTrap by determining if a click event occurred outside of the component. When `true`, the focus trap will deactivate.
+ *
+ * @param {FocusTrapComponent} component The FocusTrap component.
+ * @param [options] The FocusTrap activate options.
+ * @param event
+ */
+export function clickOutsideDeactivates(event: MouseEvent): boolean {
+ const path = event.composedPath();
+ const isClickInside = path.some((el: EventTarget) => this.contains(el as Node));
+ // If the click is inside the component, do not deactivate the focus trap
+ return !isClickInside;
+}
From 7418a25dce501639497dfbd17400b675aa81ff89 Mon Sep 17 00:00:00 2001
From: eliza
Date: Thu, 8 Aug 2024 13:58:24 -0700
Subject: [PATCH 21/62] WIP
---
.../input-date-picker/input-date-picker.tsx | 5 +++++
.../src/utils/focusTrapComponent.ts | 16 +---------------
2 files changed, 6 insertions(+), 15 deletions(-)
diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
index 8f8cb2f7674..d49727e6861 100644
--- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
+++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
@@ -833,10 +833,12 @@ export class InputDatePicker
}
onBeforeOpen(): void {
+ console.log("onBeforeOpen");
this.calciteInputDatePickerBeforeOpen.emit();
}
onOpen(): void {
+ console.log("onOpen");
activateFocusTrap(this, {
onActivate: () => {
if (this.focusOnOpen) {
@@ -849,10 +851,12 @@ export class InputDatePicker
}
onBeforeClose(): void {
+ console.log("onBeforeClose");
this.calciteInputDatePickerBeforeClose.emit();
}
onClose(): void {
+ console.log("onClose");
this.calciteInputDatePickerClose.emit();
deactivateFocusTrap(this);
this.restoreInputFocus();
@@ -978,6 +982,7 @@ export class InputDatePicker
connectFocusTrap(this, {
focusTrapEl: el,
focusTrapOptions: {
+ clickOutsideDeactivates: () => !event.composedPath().includes(el),
initialFocus: false,
setReturnFocus: false,
},
diff --git a/packages/calcite-components/src/utils/focusTrapComponent.ts b/packages/calcite-components/src/utils/focusTrapComponent.ts
index 75295554f15..a5151bc8223 100644
--- a/packages/calcite-components/src/utils/focusTrapComponent.ts
+++ b/packages/calcite-components/src/utils/focusTrapComponent.ts
@@ -17,7 +17,7 @@ export interface FocusTrapComponent {
/**
* When `true`, indicates the click has happened outside of the component and can therefore deactivate focusTrap.
*/
- clickOutsideDeactivates?: (event: MouseEvent) => boolean;
+ clickOutsideDeactivates?: boolean | ((event: MouseEvent) => boolean);
/**
* When `true`, prevents focus trapping.
@@ -133,17 +133,3 @@ export function deactivateFocusTrap(
export function updateFocusTrapElements(component: FocusTrapComponent): void {
component.focusTrap?.updateContainerElements(component.el);
}
-
-/**
- * Helper to manage focusTrap by determining if a click event occurred outside of the component. When `true`, the focus trap will deactivate.
- *
- * @param {FocusTrapComponent} component The FocusTrap component.
- * @param [options] The FocusTrap activate options.
- * @param event
- */
-export function clickOutsideDeactivates(event: MouseEvent): boolean {
- const path = event.composedPath();
- const isClickInside = path.some((el: EventTarget) => this.contains(el as Node));
- // If the click is inside the component, do not deactivate the focus trap
- return !isClickInside;
-}
From a9dd5c0b9f1bf3a42e1d9cd59fef44f037fae3d4 Mon Sep 17 00:00:00 2001
From: eliza
Date: Thu, 8 Aug 2024 14:38:37 -0700
Subject: [PATCH 22/62] WIP
---
.../src/components/input-date-picker/input-date-picker.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
index d49727e6861..e42cf8588e5 100644
--- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
+++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
@@ -982,7 +982,7 @@ export class InputDatePicker
connectFocusTrap(this, {
focusTrapEl: el,
focusTrapOptions: {
- clickOutsideDeactivates: () => !event.composedPath().includes(el),
+ clickOutsideDeactivates: () => !event.composedPath().includes(this.el),
initialFocus: false,
setReturnFocus: false,
},
From 58622a48db27e9f121b15bad6e58057cea42d610 Mon Sep 17 00:00:00 2001
From: eliza
Date: Fri, 9 Aug 2024 10:29:52 -0700
Subject: [PATCH 23/62] WIP test
---
.../input-date-picker/input-date-picker.tsx | 24 +++++++++++++++++--
.../src/demos/input-date-picker.html | 6 ++---
2 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
index e42cf8588e5..ac5b29b41bb 100644
--- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
+++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx
@@ -553,7 +553,7 @@ export class InputDatePicker
};
return (
-
+
{this.localeData && (