From 758299f57427eae2dfa150551f0b181b2b2c4d1e Mon Sep 17 00:00:00 2001 From: Stephane Comeau Date: Tue, 15 Feb 2022 19:38:09 -0800 Subject: [PATCH 01/11] working --- .../web-components/fast-foundation/src/dialog/dialog.ts | 8 ++++---- yarn.lock | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/web-components/fast-foundation/src/dialog/dialog.ts b/packages/web-components/fast-foundation/src/dialog/dialog.ts index b62f43e564e..aa1439b297a 100644 --- a/packages/web-components/fast-foundation/src/dialog/dialog.ts +++ b/packages/web-components/fast-foundation/src/dialog/dialog.ts @@ -1,7 +1,7 @@ import { attr, DOM, Notifier, Observable } from "@microsoft/fast-element"; import { keyEscape, keyTab } from "@microsoft/fast-web-utilities"; -import { isTabbable } from "tabbable"; -import { FoundationElement } from "../foundation-element/foundation-element.js"; +import { isTabbable, tabbable } from "tabbable"; +import { FoundationElement } from "../foundation-element"; /** * A Switch Custom HTML Element. @@ -219,9 +219,9 @@ export class Dialog extends FoundationElement { }; private getTabQueueBounds = (): (HTMLElement | SVGElement)[] => { - const bounds: HTMLElement[] = []; + // const bounds: HTMLElement[] = []; - return Dialog.reduceTabbableItems(bounds, this); + return tabbable(this); }; /** diff --git a/yarn.lock b/yarn.lock index 3d09d123990..1174fc62e12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23160,6 +23160,11 @@ symbol.prototype.description@^1.0.0: has-symbols "^1.0.2" object.getownpropertydescriptors "^2.1.2" +tabbable@5.3.0-beta.0: + version "5.3.0-beta.0" + resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.3.0-beta.0.tgz#2840539883f236f2887312431fbfe07dc305bce5" + integrity sha512-zNNUKn79Qve4JNB3/tP38EdS8eA4Phjh6go1TQ1/o2QcQDoTBVbS4hDYwj6jF4242fCMseo1fLBfaeAQqVgOcA== + tabbable@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-4.0.0.tgz#5bff1d1135df1482cf0f0206434f15eadbeb9261" From c36d10cd9c61bdc8f7572612e3d1ee79022917f7 Mon Sep 17 00:00:00 2001 From: Stephane Comeau Date: Wed, 16 Feb 2022 07:29:51 -0800 Subject: [PATCH 02/11] use tabbable in dialog and toolbar --- .../fast-foundation/src/dialog/dialog.ts | 81 +++---------------- .../fast-foundation/src/toolbar/toolbar.ts | 64 +++------------ 2 files changed, 25 insertions(+), 120 deletions(-) diff --git a/packages/web-components/fast-foundation/src/dialog/dialog.ts b/packages/web-components/fast-foundation/src/dialog/dialog.ts index aa1439b297a..c13dd16055f 100644 --- a/packages/web-components/fast-foundation/src/dialog/dialog.ts +++ b/packages/web-components/fast-foundation/src/dialog/dialog.ts @@ -1,6 +1,6 @@ import { attr, DOM, Notifier, Observable } from "@microsoft/fast-element"; import { keyEscape, keyTab } from "@microsoft/fast-web-utilities"; -import { isTabbable, tabbable } from "tabbable"; +import { FocusableElement, isTabbable, tabbable } from "tabbable"; import { FoundationElement } from "../foundation-element"; /** @@ -207,10 +207,12 @@ export class Dialog extends FoundationElement { return; } - if (e.shiftKey && e.target === bounds[0]) { + const composed: EventTarget[] = e.composedPath(); + + if (e.shiftKey && composed.includes(bounds[0])) { bounds[bounds.length - 1].focus(); e.preventDefault(); - } else if (!e.shiftKey && e.target === bounds[bounds.length - 1]) { + } else if (!e.shiftKey && composed.includes(bounds[bounds.length - 1])) { bounds[0].focus(); e.preventDefault(); } @@ -218,17 +220,19 @@ export class Dialog extends FoundationElement { return; }; - private getTabQueueBounds = (): (HTMLElement | SVGElement)[] => { - // const bounds: HTMLElement[] = []; - - return tabbable(this); + private getTabQueueBounds = (): FocusableElement[] => { + return tabbable(this, { + getShadowRoot: () => { + return undefined; + }, + }); }; /** * focus on first element of tab queue */ private focusFirstElement = (): void => { - const bounds: (HTMLElement | SVGElement)[] = this.getTabQueueBounds(); + const bounds: FocusableElement[] = this.getTabQueueBounds(); if (bounds.length > 0) { bounds[0].focus(); @@ -254,7 +258,7 @@ export class Dialog extends FoundationElement { }; /** - * + * Updates trap focus state * * @internal */ @@ -279,63 +283,4 @@ export class Dialog extends FoundationElement { document.removeEventListener("focusin", this.handleDocumentFocus); } }; - - /** - * Reduce a collection to only its focusable elements. - * - * @param elements - Collection of elements to reduce - * @param element - The current element - * - * @internal - */ - private static reduceTabbableItems( - elements: HTMLElement[], - element: FoundationElement & HTMLElement - ): HTMLElement[] { - if (element.getAttribute("tabindex") === "-1") { - return elements; - } - - if ( - isTabbable(element) || - (Dialog.isFocusableFastElement(element) && Dialog.hasTabbableShadow(element)) - ) { - elements.push(element); - return elements; - } - - if (element.childElementCount) { - return elements.concat( - Array.from(element.children).reduce(Dialog.reduceTabbableItems, []) - ); - } - - return elements; - } - - /** - * Test if element is focusable fast element - * - * @param element - The element to check - * - * @internal - */ - private static isFocusableFastElement( - element: FoundationElement & HTMLElement - ): boolean { - return !!element.$fastController?.definition.shadowOptions?.delegatesFocus; - } - - /** - * Test if the element has a focusable shadow - * - * @param element - The element to check - * - * @internal - */ - private static hasTabbableShadow(element: FoundationElement & HTMLElement) { - return Array.from(element.shadowRoot?.querySelectorAll("*") ?? []).some(x => { - return isTabbable(x); - }); - } } diff --git a/packages/web-components/fast-foundation/src/toolbar/toolbar.ts b/packages/web-components/fast-foundation/src/toolbar/toolbar.ts index d8c0a9b29e6..af4f2ca0138 100644 --- a/packages/web-components/fast-foundation/src/toolbar/toolbar.ts +++ b/packages/web-components/fast-foundation/src/toolbar/toolbar.ts @@ -1,14 +1,11 @@ import { attr, FASTElement, observable, Observable } from "@microsoft/fast-element"; import { ArrowKeys, Direction, limit, Orientation } from "@microsoft/fast-web-utilities"; -import { isFocusable } from "tabbable"; -import { - FoundationElement, - FoundationElementDefinition, -} from "../foundation-element/foundation-element.js"; -import { ARIAGlobalStatesAndProperties } from "../patterns/aria-global.js"; -import { StartEnd, StartEndOptions } from "../patterns/start-end.js"; -import { applyMixins } from "../utilities/apply-mixins.js"; -import { getDirection } from "../utilities/direction.js"; +import { FocusableElement, tabbable } from "tabbable"; +import { FoundationElement, FoundationElementDefinition } from "../foundation-element"; +import { ARIAGlobalStatesAndProperties } from "../patterns/aria-global"; +import { StartEnd, StartEndOptions } from "../patterns/start-end"; +import { applyMixins } from "../utilities/apply-mixins"; +import { getDirection } from "../utilities/direction"; /** * Toolbar configuration options @@ -93,7 +90,7 @@ export class Toolbar extends FoundationElement { * * @internal */ - private focusableElements: HTMLElement[]; + private focusableElements: FocusableElement[]; /** * The orientation of the toolbar. @@ -233,10 +230,11 @@ export class Toolbar extends FoundationElement { * @internal */ protected reduceFocusableElements(): void { - this.focusableElements = this.allSlottedItems.reduce( - Toolbar.reduceFocusableItems, - [] - ); + this.focusableElements = tabbable(this, { + getShadowRoot: () => { + return undefined; + }, + }); this.setFocusableElements(); } @@ -252,44 +250,6 @@ export class Toolbar extends FoundationElement { this.focusableElements[this.activeIndex]?.focus(); } - /** - * Reduce a collection to only its focusable elements. - * - * @param elements - Collection of elements to reduce - * @param element - The current element - * - * @internal - */ - private static reduceFocusableItems( - elements: HTMLElement[], - element: FASTElement & HTMLElement - ): HTMLElement[] { - const isRoleRadio = element.getAttribute("role") === "radio"; - const isFocusableFastElement = - element.$fastController?.definition.shadowOptions?.delegatesFocus; - const hasFocusableShadow = Array.from( - element.shadowRoot?.querySelectorAll("*") ?? [] - ).some(x => isFocusable(x)); - - if ( - isFocusable(element) || - isRoleRadio || - isFocusableFastElement || - hasFocusableShadow - ) { - elements.push(element); - return elements; - } - - if (element.childElementCount) { - return elements.concat( - Array.from(element.children).reduce(Toolbar.reduceFocusableItems, []) - ); - } - - return elements; - } - /** * @internal */ From 7c8e2d2952e5de32c4972b594d47a0b401c801a0 Mon Sep 17 00:00:00 2001 From: Stephane Comeau Date: Wed, 16 Feb 2022 07:32:23 -0800 Subject: [PATCH 03/11] Change files --- ...st-foundation-680ad93b-949d-43f0-8211-46d8089a97fe.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@microsoft-fast-foundation-680ad93b-949d-43f0-8211-46d8089a97fe.json diff --git a/change/@microsoft-fast-foundation-680ad93b-949d-43f0-8211-46d8089a97fe.json b/change/@microsoft-fast-foundation-680ad93b-949d-43f0-8211-46d8089a97fe.json new file mode 100644 index 00000000000..c319f0136a3 --- /dev/null +++ b/change/@microsoft-fast-foundation-680ad93b-949d-43f0-8211-46d8089a97fe.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "use tabbable for shadow dom", + "packageName": "@microsoft/fast-foundation", + "email": "scomea@microsoft.com", + "dependentChangeType": "patch" +} From fc7b38078316eaffddf85baa49f6bf7420d0a943 Mon Sep 17 00:00:00 2001 From: Stephane Comeau Date: Wed, 16 Feb 2022 22:06:24 -0800 Subject: [PATCH 04/11] working --- .../src/dialog/dialog.stories.ts | 28 +++++++++++++++- .../src/dialog/fixtures/dialog.html | 32 +++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/packages/web-components/fast-components/src/dialog/dialog.stories.ts b/packages/web-components/fast-components/src/dialog/dialog.stories.ts index 6559123d7c9..0d6174fe42b 100644 --- a/packages/web-components/fast-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/fast-components/src/dialog/dialog.stories.ts @@ -1,12 +1,15 @@ import { STORY_RENDERED } from "@storybook/core-events"; import addons from "@storybook/addons"; +import { Dialog as FoundationDialog } from "@microsoft/fast-foundation"; import DialogTemplate from "./fixtures/dialog.html"; import "./index.js"; addons.getChannel().addListener(STORY_RENDERED, (name: string) => { if (name.toLowerCase().startsWith("dialog")) { const button1 = document.getElementById("button1"); - const dialog1 = document.getElementById("dialog1"); + const dialog1: FoundationDialog = document.getElementById( + "dialog1" + ) as FoundationDialog; if (button1 && dialog1) { button1.addEventListener("click", (e: MouseEvent) => { @@ -17,6 +20,29 @@ addons.getChannel().addListener(STORY_RENDERED, (name: string) => { dialog1.hidden = true; }); } + + const button2 = document.getElementById("button2"); + const dialog2: FoundationDialog = document.getElementById( + "dialog2" + ) as FoundationDialog; + + const shadowButton1: HTMLButtonElement = document.createElement("button"); + shadowButton1.textContent = "Shadow Button 1"; + dialog2.dialog.prepend(shadowButton1); + + const shadowButton2: HTMLButtonElement = document.createElement("button"); + shadowButton2.textContent = "Shadow Button 2"; + dialog2.dialog.appendChild(shadowButton2); + + if (button2 && dialog2) { + button2.addEventListener("click", (e: MouseEvent) => { + dialog2.hidden = false; + }); + + dialog2.addEventListener("dismiss", (e: Event) => { + dialog2.hidden = true; + }); + } } }); diff --git a/packages/web-components/fast-components/src/dialog/fixtures/dialog.html b/packages/web-components/fast-components/src/dialog/fixtures/dialog.html index 4f69153d800..28ab5d6346b 100644 --- a/packages/web-components/fast-components/src/dialog/fixtures/dialog.html +++ b/packages/web-components/fast-components/src/dialog/fixtures/dialog.html @@ -1,10 +1,8 @@ - Show dialog + Basic Dialog

-tab queue detected automatically - Dialog queue detected automatically

(esc to close)
+ + + With shadow dom elements + +

+ + From 4008c5fd3dfd2bace305098ab4c418768a49bf36 Mon Sep 17 00:00:00 2001 From: Stephane Comeau Date: Thu, 17 Feb 2022 12:10:43 -0800 Subject: [PATCH 05/11] working --- .../src/dialog/dialog.stories.ts | 2 +- .../fast-foundation/src/toolbar/toolbar.ts | 54 ++++++++++++++++--- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/packages/web-components/fast-components/src/dialog/dialog.stories.ts b/packages/web-components/fast-components/src/dialog/dialog.stories.ts index 0d6174fe42b..1ef3f5d7f09 100644 --- a/packages/web-components/fast-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/fast-components/src/dialog/dialog.stories.ts @@ -26,7 +26,7 @@ addons.getChannel().addListener(STORY_RENDERED, (name: string) => { "dialog2" ) as FoundationDialog; - const shadowButton1: HTMLButtonElement = document.createElement("button"); + const shadowButton1: HTMLElement = document.createElement("fast-button"); shadowButton1.textContent = "Shadow Button 1"; dialog2.dialog.prepend(shadowButton1); diff --git a/packages/web-components/fast-foundation/src/toolbar/toolbar.ts b/packages/web-components/fast-foundation/src/toolbar/toolbar.ts index af4f2ca0138..ddf30ac7a77 100644 --- a/packages/web-components/fast-foundation/src/toolbar/toolbar.ts +++ b/packages/web-components/fast-foundation/src/toolbar/toolbar.ts @@ -1,6 +1,6 @@ import { attr, FASTElement, observable, Observable } from "@microsoft/fast-element"; import { ArrowKeys, Direction, limit, Orientation } from "@microsoft/fast-web-utilities"; -import { FocusableElement, tabbable } from "tabbable"; +import { FocusableElement, isFocusable, tabbable } from "tabbable"; import { FoundationElement, FoundationElementDefinition } from "../foundation-element"; import { ARIAGlobalStatesAndProperties } from "../patterns/aria-global"; import { StartEnd, StartEndOptions } from "../patterns/start-end"; @@ -230,14 +230,56 @@ export class Toolbar extends FoundationElement { * @internal */ protected reduceFocusableElements(): void { - this.focusableElements = tabbable(this, { - getShadowRoot: () => { - return undefined; - }, - }); + this.focusableElements = this.allSlottedItems.reduce( + Toolbar.reduceFocusableItems, + [] + ); + // this.focusableElements = tabbable(this, { + // getShadowRoot: () => { + // return undefined; + // }, + // }); this.setFocusableElements(); } + /** + * Reduce a collection to only its focusable elements. + * + * @param elements - Collection of elements to reduce + * @param element - The current element + * + * @internal + */ + private static reduceFocusableItems( + elements: HTMLElement[], + element: FASTElement & HTMLElement + ): HTMLElement[] { + const isRoleRadio = element.getAttribute("role") === "radio"; + const isFocusableFastElement = + element.$fastController?.definition.shadowOptions?.delegatesFocus; + const hasFocusableShadow = Array.from( + element.shadowRoot?.querySelectorAll("*") ?? [] + ).some(x => isFocusable(x)); + + if ( + isFocusable(element) || + isRoleRadio || + isFocusableFastElement || + hasFocusableShadow + ) { + elements.push(element); + return elements; + } + + if (element.childElementCount) { + return elements.concat( + Array.from(element.children).reduce(Toolbar.reduceFocusableItems, []) + ); + } + + return elements; + } + /** * Set the activeIndex and focus the corresponding control. * From 494bf12aa2b849718849c5fe118ffa14d667695d Mon Sep 17 00:00:00 2001 From: Stephane Comeau Date: Mon, 7 Mar 2022 19:00:58 -0800 Subject: [PATCH 06/11] working --- .../src/dialog/dialog.stories.ts | 5 ++++ .../fast-foundation/src/button/button.ts | 26 +++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/web-components/fast-components/src/dialog/dialog.stories.ts b/packages/web-components/fast-components/src/dialog/dialog.stories.ts index 1ef3f5d7f09..2c86ae03547 100644 --- a/packages/web-components/fast-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/fast-components/src/dialog/dialog.stories.ts @@ -30,6 +30,11 @@ addons.getChannel().addListener(STORY_RENDERED, (name: string) => { shadowButton1.textContent = "Shadow Button 1"; dialog2.dialog.prepend(shadowButton1); + const shadowNumberField: HTMLElement = document.createElement( + "fast-number-field" + ); + dialog2.dialog.prepend(shadowNumberField); + const shadowButton2: HTMLButtonElement = document.createElement("button"); shadowButton2.textContent = "Shadow Button 2"; dialog2.dialog.appendChild(shadowButton2); diff --git a/packages/web-components/fast-foundation/src/button/button.ts b/packages/web-components/fast-foundation/src/button/button.ts index 306625205ef..5f73b738b5b 100644 --- a/packages/web-components/fast-foundation/src/button/button.ts +++ b/packages/web-components/fast-foundation/src/button/button.ts @@ -162,7 +162,7 @@ export class Button extends FormAssociatedButton { super.connectedCallback(); this.proxy.setAttribute("type", this.type); - this.handleUnsupportedDelegatesFocus(); + // this.handleUnsupportedDelegatesFocus(); const elements = Array.from(this.control?.children) as HTMLSpanElement[]; if (elements) { @@ -235,18 +235,18 @@ export class Button extends FormAssociatedButton { * This check works for Chrome, Edge Chromium, FireFox, and Safari * Relevant PR on the Firefox browser: https://phabricator.services.mozilla.com/D123858 */ - private handleUnsupportedDelegatesFocus = () => { - // Check to see if delegatesFocus is supported - if ( - window.ShadowRoot && - !window.ShadowRoot.prototype.hasOwnProperty("delegatesFocus") && - this.$fastController.definition.shadowOptions?.delegatesFocus - ) { - this.focus = () => { - this.control.focus(); - }; - } - }; + // private handleUnsupportedDelegatesFocus = () => { + // // Check to see if delegatesFocus is supported + // if ( + // window.ShadowRoot && + // !window.ShadowRoot.prototype.hasOwnProperty("delegatesFocus") && + // this.$fastController.definition.shadowOptions?.delegatesFocus + // ) { + // this.focus = () => { + // this.control.focus(); + // }; + // } + // }; } /** From 303d6bc0f496fd995980fb292bb1ae338607913b Mon Sep 17 00:00:00 2001 From: Stephane Comeau Date: Tue, 8 Mar 2022 09:24:31 -0800 Subject: [PATCH 07/11] working --- .../web-components/fast-components/src/dialog/dialog.stories.ts | 1 + .../fast-components/src/dialog/fixtures/dialog.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/web-components/fast-components/src/dialog/dialog.stories.ts b/packages/web-components/fast-components/src/dialog/dialog.stories.ts index 2c86ae03547..d7ac55acd92 100644 --- a/packages/web-components/fast-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/fast-components/src/dialog/dialog.stories.ts @@ -28,6 +28,7 @@ addons.getChannel().addListener(STORY_RENDERED, (name: string) => { const shadowButton1: HTMLElement = document.createElement("fast-button"); shadowButton1.textContent = "Shadow Button 1"; + shadowButton1.setAttribute("tabindex", "0"); dialog2.dialog.prepend(shadowButton1); const shadowNumberField: HTMLElement = document.createElement( diff --git a/packages/web-components/fast-components/src/dialog/fixtures/dialog.html b/packages/web-components/fast-components/src/dialog/fixtures/dialog.html index 28ab5d6346b..942a64a3c07 100644 --- a/packages/web-components/fast-components/src/dialog/fixtures/dialog.html +++ b/packages/web-components/fast-components/src/dialog/fixtures/dialog.html @@ -38,7 +38,7 @@

Dialog queue detected automatically

hidden="true" >

With shadow dom elements

- Button A + Button A

From b35550c00d9d872fb8cb856d9cf1f1574a05a18d Mon Sep 17 00:00:00 2001 From: Stephane Comeau Date: Fri, 29 Apr 2022 16:56:57 -0700 Subject: [PATCH 08/11] merge --- .../web-components/fast-foundation/src/dialog/README.md | 6 +++--- .../web-components/fast-foundation/src/toolbar/README.md | 6 +++--- yarn.lock | 5 ----- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/web-components/fast-foundation/src/dialog/README.md b/packages/web-components/fast-foundation/src/dialog/README.md index f6febd35bfe..8a56212c5fa 100644 --- a/packages/web-components/fast-foundation/src/dialog/README.md +++ b/packages/web-components/fast-foundation/src/dialog/README.md @@ -57,9 +57,9 @@ export const myDialog = Dialog.compose({ #### Superclass -| Name | Module | Package | -| ------------------- | --------------------------------------------- | ------- | -| `FoundationElement` | /src/foundation-element/foundation-element.js | | +| Name | Module | Package | +| ------------------- | ----------------------- | ------- | +| `FoundationElement` | /src/foundation-element | | #### Fields diff --git a/packages/web-components/fast-foundation/src/toolbar/README.md b/packages/web-components/fast-foundation/src/toolbar/README.md index 7f87342c408..545a72c55b4 100644 --- a/packages/web-components/fast-foundation/src/toolbar/README.md +++ b/packages/web-components/fast-foundation/src/toolbar/README.md @@ -87,9 +87,9 @@ export const myToolbar = Toolbar.compose({ #### Superclass -| Name | Module | Package | -| ------------------- | --------------------------------------------- | ------- | -| `FoundationElement` | /src/foundation-element/foundation-element.js | | +| Name | Module | Package | +| ------------------- | ----------------------- | ------- | +| `FoundationElement` | /src/foundation-element | | #### Fields diff --git a/yarn.lock b/yarn.lock index 1174fc62e12..0cdde1cbf81 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23170,11 +23170,6 @@ tabbable@^4.0.0: resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-4.0.0.tgz#5bff1d1135df1482cf0f0206434f15eadbeb9261" integrity sha512-H1XoH1URcBOa/rZZWxLxHCtOdVUEev+9vo5YdYhC9tCY4wnybX+VQrCYuy9ubkg69fCBxCONJOSLGfw0DWMffQ== -tabbable@^5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.2.1.tgz#e3fda7367ddbb172dcda9f871c0fdb36d1c4cd9c" - integrity sha512-40pEZ2mhjaZzK0BnI+QGNjJO8UYx9pP5v7BGe17SORTO0OEuuaAwQTkAp8whcZvqon44wKFOikD+Al11K3JICQ== - table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" From 29b4f6738ce5a2c6ecac8a1fefc647854fe57a64 Mon Sep 17 00:00:00 2001 From: Stephane Comeau Date: Thu, 5 May 2022 12:07:04 -0700 Subject: [PATCH 09/11] tabbable version --- packages/web-components/fast-foundation/package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/web-components/fast-foundation/package.json b/packages/web-components/fast-foundation/package.json index f56eb4045b4..71d7158abc4 100644 --- a/packages/web-components/fast-foundation/package.json +++ b/packages/web-components/fast-foundation/package.json @@ -97,7 +97,7 @@ "dependencies": { "@microsoft/fast-element": "^1.10.1", "@microsoft/fast-web-utilities": "^5.4.1", - "tabbable": "^5.2.0", + "tabbable": "^5.3.1", "tslib": "^1.13.0" }, "customElements": "dist/custom-elements.json" diff --git a/yarn.lock b/yarn.lock index 0cdde1cbf81..07b987dccc7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23160,16 +23160,16 @@ symbol.prototype.description@^1.0.0: has-symbols "^1.0.2" object.getownpropertydescriptors "^2.1.2" -tabbable@5.3.0-beta.0: - version "5.3.0-beta.0" - resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.3.0-beta.0.tgz#2840539883f236f2887312431fbfe07dc305bce5" - integrity sha512-zNNUKn79Qve4JNB3/tP38EdS8eA4Phjh6go1TQ1/o2QcQDoTBVbS4hDYwj6jF4242fCMseo1fLBfaeAQqVgOcA== - tabbable@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-4.0.0.tgz#5bff1d1135df1482cf0f0206434f15eadbeb9261" integrity sha512-H1XoH1URcBOa/rZZWxLxHCtOdVUEev+9vo5YdYhC9tCY4wnybX+VQrCYuy9ubkg69fCBxCONJOSLGfw0DWMffQ== +tabbable@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.3.1.tgz#059f2a19b829efce2a0ec05785a47dd3bcd0a25b" + integrity sha512-NtO7I7eoAHR+JwwcNsi/PipamtAEebYDnur/k9wM6n238HHy/+1O4+7Zx7e/JaDAbKJPlIFYsfsV/6tPqTOQvg== + table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" From 00ea3142096f0a2dd83ec01dad46a29ffc6afa84 Mon Sep 17 00:00:00 2001 From: Stephane Comeau Date: Thu, 5 May 2022 14:54:53 -0700 Subject: [PATCH 10/11] merge fixes --- .../fast-foundation/src/button/button.ts | 19 ------------------- .../fast-foundation/src/dialog/README.md | 6 +++--- .../fast-foundation/src/dialog/dialog.ts | 6 +++--- 3 files changed, 6 insertions(+), 25 deletions(-) diff --git a/packages/web-components/fast-foundation/src/button/button.ts b/packages/web-components/fast-foundation/src/button/button.ts index 5f73b738b5b..425d8f9c313 100644 --- a/packages/web-components/fast-foundation/src/button/button.ts +++ b/packages/web-components/fast-foundation/src/button/button.ts @@ -162,7 +162,6 @@ export class Button extends FormAssociatedButton { super.connectedCallback(); this.proxy.setAttribute("type", this.type); - // this.handleUnsupportedDelegatesFocus(); const elements = Array.from(this.control?.children) as HTMLSpanElement[]; if (elements) { @@ -229,24 +228,6 @@ export class Button extends FormAssociatedButton { }; public control: HTMLButtonElement; - - /** - * Overrides the focus call for where delegatesFocus is unsupported. - * This check works for Chrome, Edge Chromium, FireFox, and Safari - * Relevant PR on the Firefox browser: https://phabricator.services.mozilla.com/D123858 - */ - // private handleUnsupportedDelegatesFocus = () => { - // // Check to see if delegatesFocus is supported - // if ( - // window.ShadowRoot && - // !window.ShadowRoot.prototype.hasOwnProperty("delegatesFocus") && - // this.$fastController.definition.shadowOptions?.delegatesFocus - // ) { - // this.focus = () => { - // this.control.focus(); - // }; - // } - // }; } /** diff --git a/packages/web-components/fast-foundation/src/dialog/README.md b/packages/web-components/fast-foundation/src/dialog/README.md index 8a56212c5fa..41483185c54 100644 --- a/packages/web-components/fast-foundation/src/dialog/README.md +++ b/packages/web-components/fast-foundation/src/dialog/README.md @@ -57,9 +57,9 @@ export const myDialog = Dialog.compose({ #### Superclass -| Name | Module | Package | -| ------------------- | ----------------------- | ------- | -| `FoundationElement` | /src/foundation-element | | +| Name | Module | Package | +| ------------------- | -------------------------------- | ------- | +| `FoundationElement` | /src/foundation-element/index.js | | #### Fields diff --git a/packages/web-components/fast-foundation/src/dialog/dialog.ts b/packages/web-components/fast-foundation/src/dialog/dialog.ts index c13dd16055f..34e9108e732 100644 --- a/packages/web-components/fast-foundation/src/dialog/dialog.ts +++ b/packages/web-components/fast-foundation/src/dialog/dialog.ts @@ -1,7 +1,7 @@ import { attr, DOM, Notifier, Observable } from "@microsoft/fast-element"; import { keyEscape, keyTab } from "@microsoft/fast-web-utilities"; -import { FocusableElement, isTabbable, tabbable } from "tabbable"; -import { FoundationElement } from "../foundation-element"; +import { FocusableElement, tabbable } from "tabbable"; +import { FoundationElement } from "../foundation-element/index.js"; /** * A Switch Custom HTML Element. @@ -194,7 +194,7 @@ export class Dialog extends FoundationElement { return; } - const bounds: (HTMLElement | SVGElement)[] = this.getTabQueueBounds(); + const bounds: FocusableElement[] = this.getTabQueueBounds(); if (bounds.length === 0) { return; From 96c4d0cf55722a6c45b13cc8ad98cdcb16d369e4 Mon Sep 17 00:00:00 2001 From: Stephane Comeau Date: Fri, 6 May 2022 09:36:38 -0700 Subject: [PATCH 11/11] cleanup --- .../fast-foundation/src/dialog/dialog.ts | 4 +- .../fast-foundation/src/toolbar/README.md | 6 +- .../fast-foundation/src/toolbar/toolbar.ts | 67 ++++--------------- 3 files changed, 17 insertions(+), 60 deletions(-) diff --git a/packages/web-components/fast-foundation/src/dialog/dialog.ts b/packages/web-components/fast-foundation/src/dialog/dialog.ts index 34e9108e732..69f2c79635a 100644 --- a/packages/web-components/fast-foundation/src/dialog/dialog.ts +++ b/packages/web-components/fast-foundation/src/dialog/dialog.ts @@ -222,9 +222,7 @@ export class Dialog extends FoundationElement { private getTabQueueBounds = (): FocusableElement[] => { return tabbable(this, { - getShadowRoot: () => { - return undefined; - }, + getShadowRoot: true, }); }; diff --git a/packages/web-components/fast-foundation/src/toolbar/README.md b/packages/web-components/fast-foundation/src/toolbar/README.md index 545a72c55b4..7f87342c408 100644 --- a/packages/web-components/fast-foundation/src/toolbar/README.md +++ b/packages/web-components/fast-foundation/src/toolbar/README.md @@ -87,9 +87,9 @@ export const myToolbar = Toolbar.compose({ #### Superclass -| Name | Module | Package | -| ------------------- | ----------------------- | ------- | -| `FoundationElement` | /src/foundation-element | | +| Name | Module | Package | +| ------------------- | --------------------------------------------- | ------- | +| `FoundationElement` | /src/foundation-element/foundation-element.js | | #### Fields diff --git a/packages/web-components/fast-foundation/src/toolbar/toolbar.ts b/packages/web-components/fast-foundation/src/toolbar/toolbar.ts index ddf30ac7a77..2c98d870426 100644 --- a/packages/web-components/fast-foundation/src/toolbar/toolbar.ts +++ b/packages/web-components/fast-foundation/src/toolbar/toolbar.ts @@ -1,11 +1,14 @@ -import { attr, FASTElement, observable, Observable } from "@microsoft/fast-element"; +import { attr, observable, Observable } from "@microsoft/fast-element"; import { ArrowKeys, Direction, limit, Orientation } from "@microsoft/fast-web-utilities"; -import { FocusableElement, isFocusable, tabbable } from "tabbable"; -import { FoundationElement, FoundationElementDefinition } from "../foundation-element"; -import { ARIAGlobalStatesAndProperties } from "../patterns/aria-global"; -import { StartEnd, StartEndOptions } from "../patterns/start-end"; -import { applyMixins } from "../utilities/apply-mixins"; -import { getDirection } from "../utilities/direction"; +import { focusable, FocusableElement } from "tabbable"; +import { + FoundationElement, + FoundationElementDefinition, +} from "../foundation-element/foundation-element.js"; +import { ARIAGlobalStatesAndProperties } from "../patterns/aria-global.js"; +import { StartEnd, StartEndOptions } from "../patterns/start-end.js"; +import { applyMixins } from "../utilities/apply-mixins.js"; +import { getDirection } from "../utilities/direction.js"; /** * Toolbar configuration options @@ -230,56 +233,12 @@ export class Toolbar extends FoundationElement { * @internal */ protected reduceFocusableElements(): void { - this.focusableElements = this.allSlottedItems.reduce( - Toolbar.reduceFocusableItems, - [] - ); - // this.focusableElements = tabbable(this, { - // getShadowRoot: () => { - // return undefined; - // }, - // }); + this.focusableElements = focusable(this, { + getShadowRoot: true, + }); this.setFocusableElements(); } - /** - * Reduce a collection to only its focusable elements. - * - * @param elements - Collection of elements to reduce - * @param element - The current element - * - * @internal - */ - private static reduceFocusableItems( - elements: HTMLElement[], - element: FASTElement & HTMLElement - ): HTMLElement[] { - const isRoleRadio = element.getAttribute("role") === "radio"; - const isFocusableFastElement = - element.$fastController?.definition.shadowOptions?.delegatesFocus; - const hasFocusableShadow = Array.from( - element.shadowRoot?.querySelectorAll("*") ?? [] - ).some(x => isFocusable(x)); - - if ( - isFocusable(element) || - isRoleRadio || - isFocusableFastElement || - hasFocusableShadow - ) { - elements.push(element); - return elements; - } - - if (element.childElementCount) { - return elements.concat( - Array.from(element.children).reduce(Toolbar.reduceFocusableItems, []) - ); - } - - return elements; - } - /** * Set the activeIndex and focus the corresponding control. *