diff --git a/packages/core/src/button-inline/button-inline.element.ts b/packages/core/src/button-inline/button-inline.element.ts index 6a433f0c5..0e5b130dc 100644 --- a/packages/core/src/button-inline/button-inline.element.ts +++ b/packages/core/src/button-inline/button-inline.element.ts @@ -49,9 +49,3 @@ export class CdsButtonInline extends CdsBaseButton { return [baseStyles, styles]; } } - -/** - * @deprecated - * renamed to `cds-button-inline` in 6.0 to align to rest of the `cds-button-*` APIs - */ -export class CdsInlineButton extends CdsButtonInline {} diff --git a/packages/core/src/button-inline/register.ts b/packages/core/src/button-inline/register.ts index e2796f0d7..4bd77d4e0 100644 --- a/packages/core/src/button-inline/register.ts +++ b/packages/core/src/button-inline/register.ts @@ -5,7 +5,7 @@ */ import { registerElementSafely } from '@cds/core/internal'; -import { CdsButtonInline, CdsInlineButton } from './button-inline.element.js'; +import { CdsButtonInline } from './button-inline.element.js'; registerElementSafely('cds-button-inline', CdsButtonInline); @@ -14,12 +14,3 @@ declare global { 'cds-button-inline': CdsButtonInline; } } - -/** @deprecated */ -registerElementSafely('cds-inline-button', CdsInlineButton); - -declare global { - interface HTMLElementTagNameMap { - 'cds-inline-button': CdsInlineButton; - } -} diff --git a/packages/core/src/internal/index.ts b/packages/core/src/internal/index.ts index e9cb98ddf..990d84454 100644 --- a/packages/core/src/internal/index.ts +++ b/packages/core/src/internal/index.ts @@ -47,7 +47,6 @@ export * from './services/keycodes.service.js'; export * from './utils/conditional.js'; export * from './utils/enum.js'; export * from './utils/exists.js'; -export * from './utils/focus-trap.js'; export * from './utils/framework.js'; export * from './i18n/utils.js'; export * from './positioning/utils.js'; diff --git a/packages/core/src/internal/utils/focus-trap.spec.ts b/packages/core/src/internal/utils/focus-trap.spec.ts deleted file mode 100644 index d13239607..000000000 --- a/packages/core/src/internal/utils/focus-trap.spec.ts +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (c) 2016-2021 VMware, Inc. All Rights Reserved. - * This software is released under MIT license. - * The full license information can be found in LICENSE in the root directory of this project. - */ - -import { html, LitElement } from 'lit'; -import { createTestElement, removeTestElement } from '@cds/core/test'; -import { createId, customElement, property, sleep, state } from '@cds/core/internal'; -import { - addReboundElementsToFocusTrapElement, - castHtmlElementToFocusTrapElement, - createFocusTrapReboundElement, - elementIsOutsideFocusTrapElement, - FocusTrap, - refocusIfOutsideFocusTrapElement, - removeReboundElementsFromFocusTrapElement, -} from './focus-trap.js'; -import { CDS_FOCUS_TRAP_DOCUMENT_ATTR, FocusTrapTrackerService } from '../services/focus-trap-tracker.service.js'; - -@customElement('test-deprecated-focus-trap') -class DeprecatedFocusTrap extends LitElement { - focusTrap: FocusTrap; - - topReboundElement: HTMLElement; - bottomReboundElement: HTMLElement; - - /** - * Its recommended to remove or add a focus trap element from the DOM - * some SSR systems can have technical constraints where the item can - * only be removed via CSS/hidden. - */ - @property({ type: Boolean }) hidden = false; - - @state({ type: Boolean, reflect: true }) - protected demoMode = false; - - @property({ type: String }) focusTrapId: string; - - constructor() { - super(); - this.focusTrapId = createId(); - // if we see issues instantiating here, we should consider moving to - // firstUpdated() - this.focusTrap = new FocusTrap(this); - } - - connectedCallback() { - super.connectedCallback(); - this.toggleFocusTrap(); - } - - disconnectedCallback() { - super.disconnectedCallback(); - this.focusTrap.removeFocusTrap(); - } - - attributeChangedCallback(name: string, old: string, value: string) { - super.attributeChangedCallback(name, old, value); - - if (name === 'hidden' && old !== value) { - this.toggleFocusTrap(); - } - } - - protected render() { - return html``; - } - - private toggleFocusTrap() { - if (!this.demoMode && !this.hasAttribute('hidden')) { - this.focusTrap.enableFocusTrap(); - } else { - this.focusTrap.removeFocusTrap(); - } - } -} - -@customElement('test-focus-trap') -class TestFocusTrap extends DeprecatedFocusTrap { - render() { - return html``; - } -} - -describe('Focus Trap Utilities: ', () => { - let focusedElement: HTMLElement; - let noFocusElement: HTMLElement; - let testElement: HTMLElement; - let focusTrapElement: TestFocusTrap; - - beforeEach(async () => { - testElement = await createTestElement( - html`` - ); - focusTrapElement = testElement.querySelector('test-focus-trap'); - focusedElement = testElement.querySelector('.inside-focus'); - noFocusElement = testElement.querySelector('.outside-focus'); - }); - - afterEach(() => { - removeTestElement(testElement); - }); - - describe('Functional Helper: ', () => { - afterEach(() => { - removeReboundElementsFromFocusTrapElement(focusTrapElement); - }); - - describe('addReboundElementsToFocusTrapElement()', () => { - it('adds rebound elements correctly when there are no siblings', () => { - addReboundElementsToFocusTrapElement(focusTrapElement); - const reboundElements = testElement.querySelectorAll('.offscreen-focus-rebounder'); - expect(reboundElements.length).toBe(2); - expect(reboundElements[0].nextSibling).toEqual(focusTrapElement); - expect(focusTrapElement.nextSibling).toEqual(reboundElements[1]); - }); - - it('does not double-add rebound elements if called twice by accident', () => { - addReboundElementsToFocusTrapElement(focusTrapElement); - addReboundElementsToFocusTrapElement(focusTrapElement); - const reboundElements = testElement.querySelectorAll('.offscreen-focus-rebounder'); - expect(reboundElements.length).toBe(2); - }); - - it('adds rebound elements correctly when there are siblings ', () => { - // this creates a sibling element to focusTrapElement - const siblingEl = document.createElement('div'); - focusTrapElement.parentElement.appendChild(siblingEl); - - addReboundElementsToFocusTrapElement(focusTrapElement); - - const reboundElements = document.querySelectorAll('.offscreen-focus-rebounder'); - expect(reboundElements.length).toBe(2); - - expect(reboundElements[0].nextSibling).toEqual(focusTrapElement); - expect(focusTrapElement.nextSibling).toEqual(reboundElements[1]); - }); - }); - - describe('removeReboundElementsFromFocusTrapElement()', () => { - it('removes rebound elements correctly', () => { - addReboundElementsToFocusTrapElement(focusTrapElement); - removeReboundElementsFromFocusTrapElement(focusTrapElement); - expect(document.querySelectorAll('.offscreen-focus-rebounder').length).toBe(0); - }); - - it('does not blow up if no rebound elements', () => { - removeReboundElementsFromFocusTrapElement(focusTrapElement); - expect(removeReboundElementsFromFocusTrapElement).not.toThrow(); - expect(document.querySelectorAll('.offscreen-focus-rebounder').length).toBe(0); - }); - }); - - describe('createFocusTrapReboundElement()', () => { - let testElement: HTMLElement; - - beforeEach(() => { - testElement = createFocusTrapReboundElement(); - }); - - afterEach(() => { - removeTestElement(testElement); - }); - - it('creates a focusable offscreen element', () => { - expect(testElement.getAttribute('tabindex')).toBe('0'); - expect(testElement.classList).toContain('offscreen-focus-rebounder'); - }); - }); - - describe('refocusIfOutsideFocusTrapElement()', () => { - it('calls focus() if in current focus trap element', async () => { - spyOn(focusedElement, 'focus'); - FocusTrapTrackerService.setCurrent(focusTrapElement); - refocusIfOutsideFocusTrapElement(focusedElement, focusTrapElement); - expect(focusedElement.focus).toHaveBeenCalled(); - }); - - it('redirects focus() if focused element not in current focus trap element', async () => { - spyOn(noFocusElement, 'focus'); - refocusIfOutsideFocusTrapElement(noFocusElement, focusTrapElement); - expect(noFocusElement.focus).not.toHaveBeenCalled(); - }); - - it('redirects focus() if it tries to focus a rebounder', async () => { - const topReboundElement = focusTrapElement.topReboundElement; - const bottomReboundElement = focusTrapElement.bottomReboundElement; - spyOn(topReboundElement, 'focus'); - spyOn(bottomReboundElement, 'focus'); - refocusIfOutsideFocusTrapElement(topReboundElement, focusTrapElement); - expect(topReboundElement.focus).not.toHaveBeenCalled(); - refocusIfOutsideFocusTrapElement(bottomReboundElement, focusTrapElement); - expect(bottomReboundElement.focus).not.toHaveBeenCalled(); - }); - }); - - describe('elementIsOutsideFocusTrapElement()', () => { - let focusedElement: HTMLElement; - let focusTrapElement: TestFocusTrap; - - beforeEach(async () => { - focusTrapElement = (await createTestElement()) as TestFocusTrap; - }); - - afterEach(() => { - removeTestElement(focusTrapElement); - if (focusedElement) { - focusedElement.remove(); - } - }); - - it('returns true if element is outside focus trap element', async () => { - focusedElement = await createTestElement(); - expect(elementIsOutsideFocusTrapElement(focusedElement, focusTrapElement)).toBeTruthy(); - }); - - it('returns true if focused element is top rebound element', async () => { - const focusedElement = await createTestElement(); - focusTrapElement.topReboundElement = focusedElement; - expect(elementIsOutsideFocusTrapElement(focusedElement, focusTrapElement)).toBeTruthy(); - }); - - it('returns true if focused element is bottom rebound element', async () => { - const focusedElement = await createTestElement(); - focusTrapElement.bottomReboundElement = focusedElement; - expect(elementIsOutsideFocusTrapElement(focusedElement, focusTrapElement)).toBeTruthy(); - }); - - it('returns false if element is inside focus trap element', () => { - const focusedElement = document.createElement('div') as HTMLElement; - focusTrapElement.appendChild(focusedElement); - expect(elementIsOutsideFocusTrapElement(focusedElement, focusTrapElement)).toBeFalsy(); - }); - - it('returns false if element is inside focus trap element shadow dom', async () => { - const specialTestElement = await createTestElement( - html`` - ); - const fte = testElement.querySelector('test-focus-trap'); - const elToFocus = fte.shadowRoot.querySelector('.shadow-button'); - expect(elementIsOutsideFocusTrapElement(elToFocus as HTMLElement, fte)).toBeFalsy(); - removeTestElement(specialTestElement); - }); - }); - }); -}); - -describe('FocusTrap Class: ', () => { - describe('enableFocusTrap()', () => { - let focusTrap: FocusTrap; - let testElement: HTMLElement; - - function setUpFocusTrap(element: HTMLElement): FocusTrap { - const ft = new FocusTrap(castHtmlElementToFocusTrapElement(element)); - ft.enableFocusTrap(); - return ft; - } - - beforeEach(async () => { - testElement = await createTestElement(); - }); - - afterEach(() => { - focusTrap.removeFocusTrap(); - removeTestElement(testElement); - }); - - it('set focus trap id', () => { - focusTrap = setUpFocusTrap(testElement); - expect(focusTrap.focusTrapElement.focusTrapId).toBeTruthy('needs to set focus trap id on plain html elements'); - }); - - it('should add rebound elements', () => { - focusTrap = setUpFocusTrap(testElement); - expect(document.querySelectorAll('.offscreen-focus-rebounder').length).toBe(2); - }); - - it('should have a tabindex of -1 to be able to programatically focus', () => { - focusTrap = setUpFocusTrap(testElement); - expect(testElement.getAttribute('tabindex')).toBe('-1'); - }); - - it('should not override tabindex if focus trap element already has a tabindex set', () => { - testElement.setAttribute('tabindex', '1'); - focusTrap = setUpFocusTrap(testElement); - expect(testElement.getAttribute('tabindex')).toBe('1'); - expect(testElement.getAttribute('tabindex')).not.toBe('-1'); - }); - - it('should add to focus trap attr on root element (html) to prevent scrolling', () => { - focusTrap = setUpFocusTrap(testElement); - expect(document.documentElement.getAttribute(CDS_FOCUS_TRAP_DOCUMENT_ATTR)).toBe(''); - }); - - it('should set itself to current on FocusTrapTracker service', () => { - focusTrap = setUpFocusTrap(testElement); - expect(FocusTrapTrackerService.getCurrent()).toEqual(testElement as any); - }); - - it('should be focused', async () => { - focusTrap = setUpFocusTrap(testElement); - // focus is not immediately set due to safari issue - await sleep(23); - expect(document.activeElement).toEqual(testElement, 'focus is set asynchronously after creation'); - }); - - it('should be set to active', () => { - focusTrap = setUpFocusTrap(testElement); - expect(focusTrap.active).toBe(true); - }); - - it('should throw an error if enabledFocusTrap is called again', () => { - focusTrap = setUpFocusTrap(testElement); - const secondCall = () => focusTrap.enableFocusTrap(); - expect(secondCall).toThrow(); - }); - }); - - describe('removeFocusTrap()', () => { - let previousFocusedElement: HTMLElement; - let focusTrap: FocusTrap; - let testElement: HTMLElement; - - beforeEach(async () => { - testElement = await createTestElement(); - focusTrap = new FocusTrap(testElement as any); - previousFocusedElement = await createTestElement(); - previousFocusedElement.setAttribute('tabindex', '0'); - previousFocusedElement.focus(); - focusTrap.enableFocusTrap(); - focusTrap.removeFocusTrap(); - }); - - afterEach(() => { - removeTestElement(testElement); - }); - - it('should remove rebound elements', () => { - expect(document.querySelectorAll('.offscreen-focus-rebounder').length).toBe(0); - }); - - it('should remove layout attribute to prevent scrolling on body', () => { - expect(document.body.getAttribute('cds-layout')).toBeNull(); - }); - - it('should not be set as current on FocusTrapTracker', () => { - expect(FocusTrapTrackerService.getCurrent()).not.toEqual(testElement as any); - }); - - it('should not be set to active', () => { - expect(focusTrap.active).toBe(false); - }); - - it('should restore previous focus', () => { - expect(document.activeElement).toEqual(previousFocusedElement); - }); - }); -}); - -describe('Nested FocusTraps: ', () => { - let outerFocusTrap: TestFocusTrap; - let innerFocusTrap: TestFocusTrap; - let testElement: HTMLElement; - let outerFocusButton: HTMLElement; - let innerFocusButton: HTMLElement; - let noFocusButton: HTMLElement; - - beforeEach(async () => { - testElement = await createTestElement(html` - - - - - - `); - outerFocusTrap = testElement.querySelector('.outer-focus-trap'); - innerFocusTrap = testElement.querySelector('.inner-focus-trap'); - outerFocusButton = testElement.querySelector('.inside-outer-focus'); - innerFocusButton = testElement.querySelector('.inside-inner-focus'); - noFocusButton = testElement.querySelector('.outside-focus'); - }); - - afterEach(() => { - removeTestElement(testElement); - }); - - it('set multiple focus trap ids', () => { - expect( - FocusTrapTrackerService.getTrapElements() - .map(e => e.focusTrapId) - .indexOf(outerFocusTrap.focusTrapId) === 0 - ).toBe(true, 'sets focus trap ids as expected (1)'); - expect( - FocusTrapTrackerService.getTrapElements() - .map(e => e.focusTrapId) - .indexOf(innerFocusTrap.focusTrapId) === 1 - ).toBe(true, 'sets focus trap ids as expected (2)'); - }); - - it('keeps focus inside the inner trap', () => { - noFocusButton.focus(); - let focused = document.activeElement; - expect(focused).not.toBe(noFocusButton, 'should not focus elements outside of active focus trap (1)'); - expect(focused).toBe( - innerFocusTrap, - 'should apply focus to focus trap if trying to focus elements outside of active focus trap (1)' - ); - outerFocusButton.focus(); - focused = document.activeElement; - expect(focused).not.toBe(outerFocusButton, 'should not focus elements outside of active focus trap (2)'); - expect(focused).toBe( - innerFocusTrap, - 'should apply focus to focus trap if trying to focus elements outside of active focus trap (2)' - ); - innerFocusButton.focus(); - focused = document.activeElement; - expect(focused).toBe(innerFocusButton, 'should allow focus on elements inside of active focus trap (1)'); - }); - - it('cancelling inner trap falls back to outer trap', () => { - innerFocusTrap.focusTrap.removeFocusTrap(); - expect(FocusTrapTrackerService.getTrapElements().findIndex(e => e.focusTrapId === innerFocusTrap.focusTrapId)).toBe( - -1, - 'should remove focus trap from focus trap ids' - ); - - noFocusButton.focus(); - let focused = document.activeElement; - expect(focused).not.toBe(noFocusButton, 'should not focus elements outside of active focus trap (3)'); - expect(focused).toBe( - outerFocusTrap, - 'should apply focus to focus trap if trying to focus elements outside of active focus trap (3)' - ); - - outerFocusButton.focus(); - focused = document.activeElement; - expect(focused).toBe(outerFocusButton, 'should allow focus on elements inside of active focus trap (1)'); - }); -}); diff --git a/packages/core/src/internal/utils/focus-trap.ts b/packages/core/src/internal/utils/focus-trap.ts deleted file mode 100644 index afb2bf81f..000000000 --- a/packages/core/src/internal/utils/focus-trap.ts +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2016-2021 VMware, Inc. All Rights Reserved. - * This software is released under MIT license. - * The full license information can be found in LICENSE in the root directory of this project. - */ - -import { FocusTrapTrackerService } from '../services/focus-trap-tracker.service.js'; -import { anyPassOrAnyFail } from './conditional.js'; -import { isHTMLElement, isFocusable, queryAllFocusable } from './dom.js'; -import { arrayHead, arrayTail } from './array.js'; -import { createId } from './identity.js'; -export interface FocusTrapElement extends HTMLElement { - topReboundElement: HTMLElement | undefined; - bottomReboundElement: HTMLElement | undefined; - focusTrapId: string; -} - -/* c8 ignore next 17 */ -/** - * @deprecated since version 6.0 - */ -export function reorderCloseButtonSlot(elements: Element[]): Element[] { - const closeButtonIndex = elements.findIndex(el => el.tagName.toLowerCase() === 'cds-internal-close-button'); - - if (closeButtonIndex > 0 && elements[closeButtonIndex].hasAttribute('slot')) { - // Put in the close button in a slot moves it around in the tab focus flow; - // this helps to place it at the top of the modal where it is expected to be - return [ - elements[closeButtonIndex], - ...elements.filter(el => el.tagName.toLowerCase() !== 'cds-internal-close-button'), - ]; - } else { - return [...elements]; - } -} - -/* c8 ignore next 27 */ -/** - * @deprecated since version 6.0 - */ -export function refocusIfOutsideFocusTrapElement( - focusedElement: HTMLElement, - focusTrapElement: FocusTrapElement, - elementToRefocus?: HTMLElement -) { - const focusTrapIsCurrent = FocusTrapTrackerService.getCurrent() === focusTrapElement; - const elementToFocusIsOutsideFocusTrap = elementIsOutsideFocusTrapElement(focusedElement, focusTrapElement); - - if (focusTrapIsCurrent && elementToFocusIsOutsideFocusTrap) { - const isReboundEl = whichReboundElement(focusedElement, focusTrapElement); - const focusableChildren = queryAllFocusable(focusTrapElement); - const orderedFocusableChildrenAsArray = reorderCloseButtonSlot(Array.from(focusableChildren)); - - if (isReboundEl !== null) { - if (isReboundEl === 'top') { - elementToRefocus = arrayTail(orderedFocusableChildrenAsArray) as HTMLElement; - } else if (isReboundEl === 'bottom') { - elementToRefocus = arrayHead(orderedFocusableChildrenAsArray) as HTMLElement; - } - } - - (elementToRefocus || focusTrapElement).focus(); - } else { - focusedElement.focus(); - } -} - -/* c8 ignore next 9 */ -/** - * @deprecated since version 6.0 - */ -export function whichReboundElement(el: HTMLElement, focusTrapElement: FocusTrapElement): 'top' | 'bottom' | null { - if (el === focusTrapElement.topReboundElement) { - return 'top'; - } else if (el === focusTrapElement.bottomReboundElement) { - return 'bottom'; - } else { - return null; - } -} - -/* c8 ignore next 13 */ -/** - * @deprecated since version 6.0 - */ -export function elementIsOutsideFocusTrapElement( - focusedElement: HTMLElement, - focusTrapElement: FocusTrapElement -): boolean { - return anyPassOrAnyFail( - [ - () => { - return whichReboundElement(focusedElement, focusTrapElement) !== null; - }, - ], // true if true - [ - () => focusTrapElement.contains(focusedElement), - () => focusTrapElement.shadowRoot !== null && focusTrapElement.shadowRoot.contains(focusedElement), - ], // false if true - true // fallthrough - ); -} - -/* c8 ignore next 6 */ -/** - * @deprecated since version 6.0 - */ -export function createFocusTrapReboundElement() { - const offScreenSpan = document.createElement('span'); - offScreenSpan.setAttribute('tabindex', '0'); - offScreenSpan.classList.add('offscreen-focus-rebounder'); - return offScreenSpan; -} - -/** - * @deprecated since version 6.0 - */ -export function addReboundElementsToFocusTrapElement(focusTrapElement: FocusTrapElement) { - if (focusTrapElement && !focusTrapElement.topReboundElement && !focusTrapElement.bottomReboundElement) { - focusTrapElement.topReboundElement = createFocusTrapReboundElement(); - focusTrapElement.bottomReboundElement = createFocusTrapReboundElement(); - - const parent = focusTrapElement.parentElement; - const sibling = focusTrapElement.nextSibling; - - if (parent) { - parent.insertBefore(focusTrapElement.topReboundElement, focusTrapElement); - if (sibling) { - parent.insertBefore(focusTrapElement.bottomReboundElement, sibling); - } else { - parent.appendChild(focusTrapElement.bottomReboundElement); - } - } - } -} - -/** - * @deprecated since version 6.0 - */ -export function removeReboundElementsFromFocusTrapElement(focusTrapElement: FocusTrapElement) { - if (focusTrapElement) { - const parent = focusTrapElement.parentElement; - - if (parent) { - const topRebound = focusTrapElement.topReboundElement; - const bottomRebound = focusTrapElement.bottomReboundElement; - if (topRebound) { - parent.removeChild(topRebound); - } - if (bottomRebound) { - parent.removeChild(bottomRebound); - } - } - // These are here to to make sure that we completely delete all traces of the removed DOM objects. - delete focusTrapElement.topReboundElement; - delete focusTrapElement.bottomReboundElement; - } -} - -// this helper exists to enable the focus trap class to handle vanilla html elements -// it's primary concern is to keep TS happy. -// end users should prefer using the CdsBaseFocusTrap component to this method. -// but it exists... -/** - * @deprecated since version 6.0 - */ -export function castHtmlElementToFocusTrapElement(el: HTMLElement): FocusTrapElement { - return el as FocusTrapElement; -} - -/** - * @deprecated since version 6.0 - */ -export class FocusTrap { - focusTrapElement: FocusTrapElement; - previousFocus: HTMLElement; - private onFocusInEvent: any; - - firstFocusElement: HTMLElement | FocusTrapElement; - - active = false; - - constructor(hostElement: FocusTrapElement) { - hostElement = castHtmlElementToFocusTrapElement(hostElement); - - if (!hostElement.focusTrapId) { - hostElement.focusTrapId = createId(); - } - - this.focusTrapElement = hostElement; - } - - enableFocusTrap() { - const fte = this.focusTrapElement; - const firstFocusElement = fte.querySelector('[cds-first-focus]'); - const contentWrapper = fte.shadowRoot ? fte.shadowRoot.querySelector('.private-host[tabindex]') : null; - const activeEl = document.activeElement; - - if (FocusTrapTrackerService.getCurrent() === fte) { - throw new Error('Focus trap is already enabled for this instance.'); - } - - // Note that first-focus only shows a focus ring when an overlay is first opened - // if the overlay is opened via keyboard navigation. This is a browser behavior, not a bug. - this.firstFocusElement = - (firstFocusElement as HTMLElement) || (contentWrapper as HTMLElement) || this.focusTrapElement; - - addReboundElementsToFocusTrapElement(fte); - - if (!isFocusable(this.firstFocusElement)) { - this.firstFocusElement.setAttribute('tabindex', '-1'); - } - - if (activeEl && isHTMLElement(activeEl)) { - this.previousFocus = activeEl as HTMLElement; - } - - FocusTrapTrackerService.setCurrent(fte); - - // setTimeout here is required for Safari which may try to set focus on - // element before it is visible... - const focusTimer = setTimeout(() => { - this.firstFocusElement.focus(); - clearTimeout(focusTimer); - }, 1); - - this.onFocusInEvent = this.onFocusIn.bind(this); - document.addEventListener('focusin', this.onFocusInEvent); - this.active = true; - } - - removeFocusTrap() { - document.removeEventListener('focusin', this.onFocusInEvent); - removeReboundElementsFromFocusTrapElement(this.focusTrapElement); - FocusTrapTrackerService.activatePreviousCurrent(); - this.active = false; - if (this.previousFocus) { - // timeout here helps screen readers behave more consistently when focus traps are closed - const focusTimer = setTimeout(() => { - this.previousFocus.focus(); - clearTimeout(focusTimer); - }, 1); - } - } - - private onFocusIn(event: FocusEvent) { - refocusIfOutsideFocusTrapElement( - event.composedPath()[0] as HTMLElement, - this.focusTrapElement, - this.firstFocusElement - ); - } -} diff --git a/packages/react/src/button/index.tsx b/packages/react/src/button/index.tsx index 84d3a76d7..5922f6f11 100644 --- a/packages/react/src/button/index.tsx +++ b/packages/react/src/button/index.tsx @@ -1,5 +1,4 @@ import { CdsButton as Button, CdsIconButton as IconButton } from '@cds/core/button'; -import { CdsButtonInline as InlineButton } from '@cds/core/button-inline'; import '@cds/core/button/register'; import { createComponent } from '@lit-labs/react'; import * as React from 'react'; @@ -7,6 +6,5 @@ import { logReactVersion } from '../utils/index'; export const CdsButton = createComponent(React, 'cds-button', Button, {}, 'CdsButton'); export const CdsIconButton = createComponent(React, 'cds-icon-button', IconButton, {}, 'CdsIconButton'); -export const CdsInlineButton = createComponent(React, 'cds-inline-button', InlineButton, {}, 'CdsInlineButton'); logReactVersion(React);