From 15b7abcab4e8db12cedb42de5eef678b6aa4892a Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Thu, 18 Jan 2024 11:29:55 +0000 Subject: [PATCH 01/11] Adding `constrainTabbing` prop to `useDialog` hook Tabbing constraint is currently tied to the `focusOnMount` prop in `useDialog'; if `focusOnMount` is not `false`, tabbing will be constrained. Sometimes we want the `focusOnMount` behaviour, without constrained tabbing. This patch adds a separate `constrainTabbing` prop, which implicitly maintains the current behaviour, taking its default value from `focusOnMount`. Otherwise, if set explicitly, tabbing will be constrained based on the value passed. --- packages/components/src/popover/index.tsx | 2 ++ packages/components/src/popover/types.ts | 9 +++++++++ packages/compose/src/hooks/use-dialog/index.ts | 4 +++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/components/src/popover/index.tsx b/packages/components/src/popover/index.tsx index 709d4b9884b5e..1634079c8cae7 100644 --- a/packages/components/src/popover/index.tsx +++ b/packages/components/src/popover/index.tsx @@ -126,6 +126,7 @@ const UnconnectedPopover = ( const { animate = true, headerTitle, + constrainTabbing, onClose, children, className, @@ -264,6 +265,7 @@ const UnconnectedPopover = ( } const [ dialogRef, dialogProps ] = useDialog( { + constrainTabbing, focusOnMount, __unstableOnClose: onDialogClose, // @ts-expect-error The __unstableOnClose property needs to be deprecated first (see https://github.com/WordPress/gutenberg/pull/27675) diff --git a/packages/components/src/popover/types.ts b/packages/components/src/popover/types.ts index c4250b22ba834..427f4afb81bfb 100644 --- a/packages/components/src/popover/types.ts +++ b/packages/components/src/popover/types.ts @@ -65,6 +65,15 @@ export type PopoverProps = { * @default true */ flip?: boolean; + /** + * Determines whether tabbing is constrained to within the popover, + * preventing keyboard focus from leaving the popover content without + * explicit focus elswhere, or whether the popover remains part of the wider + * tab order. If no value is passed, it will be derived from `focusOnMount`. + * + * @default `focusOnMount` !== false + */ + constrainTabbing?: boolean; /** * By default, the _first tabbable element_ in the popover will receive focus * when it mounts. This is the same as setting this prop to `"firstElement"`. diff --git a/packages/compose/src/hooks/use-dialog/index.ts b/packages/compose/src/hooks/use-dialog/index.ts index 66974b60e0703..6cbd9c45792df 100644 --- a/packages/compose/src/hooks/use-dialog/index.ts +++ b/packages/compose/src/hooks/use-dialog/index.ts @@ -20,6 +20,7 @@ import useMergeRefs from '../use-merge-refs'; type DialogOptions = { focusOnMount?: Parameters< typeof useFocusOnMount >[ 0 ]; + constrainTabbing?: boolean; onClose?: () => void; /** * Use the `onClose` prop instead. @@ -48,6 +49,7 @@ type useDialogReturn = [ */ function useDialog( options: DialogOptions ): useDialogReturn { const currentOptions = useRef< DialogOptions | undefined >(); + const { constrainTabbing = options.focusOnMount !== false } = options; useEffect( () => { currentOptions.current = options; }, Object.values( options ) ); @@ -83,7 +85,7 @@ function useDialog( options: DialogOptions ): useDialogReturn { return [ useMergeRefs( [ - options.focusOnMount !== false ? constrainedTabbingRef : null, + constrainTabbing ? constrainedTabbingRef : null, options.focusOnMount !== false ? focusReturnRef : null, options.focusOnMount !== false ? focusOnMountRef : null, closeOnEscapeRef, From ace7bffcaf67dddbb001d8e69f5c6ca96f815a01 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Wed, 24 Jan 2024 20:46:02 +0000 Subject: [PATCH 02/11] Adding tests for constrained tabbing (skipping some which don't work with user-event) --- .../components/src/popover/test/index.tsx | 225 ++++++++++++++++++ .../hooks/use-constrained-tabbing/index.js | 4 +- 2 files changed, 227 insertions(+), 2 deletions(-) diff --git a/packages/components/src/popover/test/index.tsx b/packages/components/src/popover/test/index.tsx index 33a2d8758c09d..37c3fc2a5e49e 100644 --- a/packages/components/src/popover/test/index.tsx +++ b/packages/components/src/popover/test/index.tsx @@ -2,6 +2,7 @@ * External dependencies */ import { render, screen, waitFor, getByText } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import type { CSSProperties } from 'react'; /** @@ -36,6 +37,15 @@ type PlacementToInitialTranslationTuple = [ CSSProperties[ 'translate' ], ]; +jest.spyOn( HTMLElement.prototype, 'offsetHeight', 'get' ).mockImplementation( + function getOffsetHeight( this: HTMLElement ) { + if ( this.tagName === 'BODY' ) { + return window.outerHeight; + } + return 50; + } +); + // There's no matching `placement` for 'middle center' positions, // fallback to 'bottom' (same as `floating-ui`'s default.) const FALLBACK_FOR_MIDDLE_CENTER_POSITIONS = 'bottom'; @@ -188,6 +198,221 @@ describe( 'Popover', () => { expect( document.body ).toHaveFocus(); } ); } ); + + describe( 'tab constraint behavior', () => { + // `constrainTabbing` is implicitly controlled by `focusOnMount`. + // By default, when `focusOnMount` is false, `constrainTabbing` will + // also be false; otherwise, `constrainTabbing` will be true. + + const setup = async ( + props?: Partial< React.ComponentProps< typeof Popover > > + ) => { + const user = await userEvent.setup(); + const view = render( + + + + + + ); + + const popover = screen.getByTestId( 'popover-element' ); + await waitFor( () => expect( popover ).toBeVisible() ); + + const firstButton = screen.getByTestId( 'first-button' ); + const secondButton = screen.getByTestId( 'second-button' ); + const thirdButton = screen.getByTestId( 'third-button' ); + + return { + ...view, + popover, + firstButton, + secondButton, + thirdButton, + user, + }; + }; + + // eslint-disable-next-line jest/no-commented-out-tests + /* + + // Note: due to an issue in testing-library/user-event [1], the + // tests for constrained tabbing fail. + // [1]: https://github.com/testing-library/user-event/issues/1188 + + describe( 'constrains tabbing', () => { + test( 'by default', async () => { + // The default value for `focusOnMount` is 'firstElement', + // which means the default value for `constrainTabbing` is + // 'true'. + + const { user, firstButton, secondButton, thirdButton } = + await setup(); + + await waitFor( () => expect( firstButton ).toHaveFocus() ); + await user.tab(); + expect( secondButton ).toHaveFocus(); + await user.tab(); + expect( thirdButton ).toHaveFocus(); + await user.tab(); + expect( firstButton ).toHaveFocus(); + await user.tab( { shift: true } ); + expect( thirdButton ).toHaveFocus(); + } ); + + test( 'when `focusOnMount` is true', async () => { + const { + user, + popover, + firstButton, + secondButton, + thirdButton, + } = await setup( { focusOnMount: true } ); + + expect( popover ).toHaveFocus(); + await user.tab(); + expect( firstButton ).toHaveFocus(); + await user.tab(); + expect( secondButton ).toHaveFocus(); + await user.tab(); + expect( thirdButton ).toHaveFocus(); + await user.tab(); + expect( firstButton ).toHaveFocus(); + await user.tab( { shift: true } ); + expect( thirdButton ).toHaveFocus(); + } ); + + test( 'when `focusOnMount` is "firstElement"', async () => { + const { user, firstButton, secondButton, thirdButton } = + await setup( { focusOnMount: 'firstElement' } ); + + await waitFor( () => expect( firstButton ).toHaveFocus() ); + await user.tab(); + expect( secondButton ).toHaveFocus(); + await user.tab(); + expect( thirdButton ).toHaveFocus(); + await user.tab(); + expect( firstButton ).toHaveFocus(); + await user.tab( { shift: true } ); + expect( thirdButton ).toHaveFocus(); + } ); + + test( 'when `focusOnMount` is false if `constrainTabbing` is true', async () => { + const { + user, + baseElement, + firstButton, + secondButton, + thirdButton, + } = await setup( { + focusOnMount: false, + constrainTabbing: true, + } ); + + expect( baseElement ).toHaveFocus(); + await user.tab(); + expect( firstButton ).toHaveFocus(); + await user.tab(); + expect( secondButton ).toHaveFocus(); + await user.tab(); + expect( thirdButton ).toHaveFocus(); + await user.tab(); + expect( firstButton ).toHaveFocus(); + await user.tab( { shift: true } ); + expect( thirdButton ).toHaveFocus(); + } ); + } ); + */ + + describe( 'does not constrain tabbing', () => { + test( 'when `constrainTabbing` is false', async () => { + // The default value for `focusOnMount` is 'firstElement', + // which means the default value for `constrainTabbing` is + // 'true', but the provided value should override this. + + const { + user, + baseElement, + firstButton, + secondButton, + thirdButton, + } = await setup( { constrainTabbing: false } ); + + await waitFor( () => expect( firstButton ).toHaveFocus() ); + await user.tab(); + expect( secondButton ).toHaveFocus(); + await user.tab(); + expect( thirdButton ).toHaveFocus(); + await user.tab(); + expect( baseElement ).toHaveFocus(); + } ); + + test( 'when `focusOnMount` is false', async () => { + const { + user, + baseElement, + firstButton, + secondButton, + thirdButton, + } = await setup( { focusOnMount: false } ); + + expect( baseElement ).toHaveFocus(); + await user.tab(); + expect( firstButton ).toHaveFocus(); + await user.tab(); + expect( secondButton ).toHaveFocus(); + await user.tab(); + expect( thirdButton ).toHaveFocus(); + await user.tab(); + expect( baseElement ).toHaveFocus(); + } ); + + test( 'when `focusOnMount` is true if `constrainTabbing` is false', async () => { + const { + user, + baseElement, + popover, + firstButton, + secondButton, + thirdButton, + } = await setup( { + focusOnMount: true, + constrainTabbing: false, + } ); + + expect( popover ).toHaveFocus(); + await user.tab(); + expect( firstButton ).toHaveFocus(); + await user.tab(); + expect( secondButton ).toHaveFocus(); + await user.tab(); + expect( thirdButton ).toHaveFocus(); + await user.tab(); + expect( baseElement ).toHaveFocus(); + } ); + + test( 'when `focusOnMount` is "firstElement" if `constrainTabbing` is false', async () => { + const { + user, + baseElement, + firstButton, + secondButton, + thirdButton, + } = await setup( { + focusOnMount: 'firstElement', + constrainTabbing: false, + } ); + + await waitFor( () => expect( firstButton ).toHaveFocus() ); + await user.tab(); + expect( secondButton ).toHaveFocus(); + await user.tab(); + expect( thirdButton ).toHaveFocus(); + await user.tab(); + expect( baseElement ).toHaveFocus(); + } ); + } ); + } ); } ); describe( 'Slot outside iframe', () => { diff --git a/packages/compose/src/hooks/use-constrained-tabbing/index.js b/packages/compose/src/hooks/use-constrained-tabbing/index.js index 97b8a2a0a5eb5..133fb84b23d11 100644 --- a/packages/compose/src/hooks/use-constrained-tabbing/index.js +++ b/packages/compose/src/hooks/use-constrained-tabbing/index.js @@ -33,9 +33,9 @@ import useRefEffect from '../use-ref-effect'; function useConstrainedTabbing() { return useRefEffect( ( /** @type {HTMLElement} */ node ) => { function onKeyDown( /** @type {KeyboardEvent} */ event ) { - const { keyCode, shiftKey, target } = event; + const { key, keyCode, shiftKey, target } = event; - if ( keyCode !== TAB ) { + if ( key !== 'Tab' || keyCode !== TAB ) { return; } From 9ee78c8769bcbc956e217db156c7e98db9ef122e Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Wed, 24 Jan 2024 21:06:50 +0000 Subject: [PATCH 03/11] Doc blocks for `useDialog` hook --- packages/compose/src/hooks/use-dialog/index.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/compose/src/hooks/use-dialog/index.ts b/packages/compose/src/hooks/use-dialog/index.ts index 6cbd9c45792df..a4eb29981f40e 100644 --- a/packages/compose/src/hooks/use-dialog/index.ts +++ b/packages/compose/src/hooks/use-dialog/index.ts @@ -19,7 +19,24 @@ import useFocusOutside from '../use-focus-outside'; import useMergeRefs from '../use-merge-refs'; type DialogOptions = { + /** + * Determines whether focus should be automatically moved to the popover + * when it mounts. `false` causes no focus shift, `true` causes the popover + * itself to gain focus, and `firstElement` focuses the first focusable + * element within the popover. + * + * @default 'firstElement' + */ focusOnMount?: Parameters< typeof useFocusOnMount >[ 0 ]; + /** + * Determines whether tabbing is constrained to within the popover, + * preventing keyboard focus from leaving the popover content without + * explicit focus elswhere, or whether the popover remains part of the wider + * tab order. If no value is passed, it will be derived from `focusOnMount`. + * + * @see focusOnMount + * @default `focusOnMount` !== false + */ constrainTabbing?: boolean; onClose?: () => void; /** From b2fac366e0a0781fbd83d7a3db03a13192aa3f27 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Wed, 24 Jan 2024 21:10:35 +0000 Subject: [PATCH 04/11] Updating CHANGELOG.md --- packages/components/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 7ad6becdb8aef..07e8ff4ea5dc5 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -12,6 +12,7 @@ - `Tooltip` and `Button`: tidy up unit tests ([#57975](https://github.com/WordPress/gutenberg/pull/57975)). - `BorderControl`, `BorderBoxControl`: Replace style picker with ToggleGroupControl ([#57562](https://github.com/WordPress/gutenberg/pull/57562)). - `SlotFill`: fix typo in use-slot-fills return docs ([#57654](https://github.com/WordPress/gutenberg/pull/57654)) +- `Popover`: Adding `constrainTabbing` prop to `useDialog` hook ([#57962](https://github.com/WordPress/gutenberg/pull/57962)) ### Bug Fix From e7f4d5908c09ea1a253b99a2f3bffaac3ef8a983 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Wed, 24 Jan 2024 21:30:21 +0000 Subject: [PATCH 05/11] Restoring `offsetHeight` mock --- .../components/src/popover/test/index.tsx | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/components/src/popover/test/index.tsx b/packages/components/src/popover/test/index.tsx index 37c3fc2a5e49e..40917e06003f6 100644 --- a/packages/components/src/popover/test/index.tsx +++ b/packages/components/src/popover/test/index.tsx @@ -37,14 +37,24 @@ type PlacementToInitialTranslationTuple = [ CSSProperties[ 'translate' ], ]; -jest.spyOn( HTMLElement.prototype, 'offsetHeight', 'get' ).mockImplementation( - function getOffsetHeight( this: HTMLElement ) { - if ( this.tagName === 'BODY' ) { - return window.outerHeight; - } - return 50; - } -); +let offsetHeightSpy: jest.SpiedGetter< + typeof HTMLElement.prototype.offsetHeight +>; + +beforeAll( () => { + offsetHeightSpy = jest + .spyOn( HTMLElement.prototype, 'offsetHeight', 'get' ) + .mockImplementation( function getOffsetHeight( this: HTMLElement ) { + if ( this.tagName === 'BODY' ) { + return window.outerHeight; + } + return 50; + } ); +} ); + +afterAll( () => { + offsetHeightSpy?.mockRestore(); +} ); // There's no matching `placement` for 'middle center' positions, // fallback to 'bottom' (same as `floating-ui`'s default.) From 74d6f27252b8eca43ab67f176303b90480ba233b Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Fri, 26 Jan 2024 07:44:47 +0000 Subject: [PATCH 06/11] Replacing `keyCode` with `key` in `useConstrainedTabbing` hook --- packages/compose/src/hooks/use-constrained-tabbing/index.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/compose/src/hooks/use-constrained-tabbing/index.js b/packages/compose/src/hooks/use-constrained-tabbing/index.js index 133fb84b23d11..94e0080b211cd 100644 --- a/packages/compose/src/hooks/use-constrained-tabbing/index.js +++ b/packages/compose/src/hooks/use-constrained-tabbing/index.js @@ -1,7 +1,6 @@ /** * WordPress dependencies */ -import { TAB } from '@wordpress/keycodes'; import { focus } from '@wordpress/dom'; /** @@ -33,9 +32,9 @@ import useRefEffect from '../use-ref-effect'; function useConstrainedTabbing() { return useRefEffect( ( /** @type {HTMLElement} */ node ) => { function onKeyDown( /** @type {KeyboardEvent} */ event ) { - const { key, keyCode, shiftKey, target } = event; + const { key, shiftKey, target } = event; - if ( key !== 'Tab' || keyCode !== TAB ) { + if ( key !== 'Tab' ) { return; } From 855953e8eac1c239df1e71fb51c9f214aa8dbfde Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Fri, 26 Jan 2024 07:48:33 +0000 Subject: [PATCH 07/11] Switching `getByTestId` to `getAllByRole` --- packages/components/src/popover/test/index.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/components/src/popover/test/index.tsx b/packages/components/src/popover/test/index.tsx index 40917e06003f6..88039f867f11c 100644 --- a/packages/components/src/popover/test/index.tsx +++ b/packages/components/src/popover/test/index.tsx @@ -220,18 +220,17 @@ describe( 'Popover', () => { const user = await userEvent.setup(); const view = render( - - - + + + ); const popover = screen.getByTestId( 'popover-element' ); await waitFor( () => expect( popover ).toBeVisible() ); - const firstButton = screen.getByTestId( 'first-button' ); - const secondButton = screen.getByTestId( 'second-button' ); - const thirdButton = screen.getByTestId( 'third-button' ); + const [ firstButton, secondButton, thirdButton ] = + screen.getAllByRole( 'button' ); return { ...view, From 756422690052ec5496dc09ab3f3a2fc70afe5720 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Fri, 26 Jan 2024 07:53:13 +0000 Subject: [PATCH 08/11] Adding expectations for shift tabbing in unconstrained focus tests --- packages/components/src/popover/test/index.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/components/src/popover/test/index.tsx b/packages/components/src/popover/test/index.tsx index 88039f867f11c..794f3739a1b5f 100644 --- a/packages/components/src/popover/test/index.tsx +++ b/packages/components/src/popover/test/index.tsx @@ -354,6 +354,10 @@ describe( 'Popover', () => { expect( thirdButton ).toHaveFocus(); await user.tab(); expect( baseElement ).toHaveFocus(); + await user.tab(); + expect( firstButton ).toHaveFocus(); + await user.tab( { shift: true } ); + expect( baseElement ).toHaveFocus(); } ); test( 'when `focusOnMount` is false', async () => { @@ -374,6 +378,10 @@ describe( 'Popover', () => { expect( thirdButton ).toHaveFocus(); await user.tab(); expect( baseElement ).toHaveFocus(); + await user.tab(); + expect( firstButton ).toHaveFocus(); + await user.tab( { shift: true } ); + expect( baseElement ).toHaveFocus(); } ); test( 'when `focusOnMount` is true if `constrainTabbing` is false', async () => { @@ -398,6 +406,10 @@ describe( 'Popover', () => { expect( thirdButton ).toHaveFocus(); await user.tab(); expect( baseElement ).toHaveFocus(); + await user.tab(); + expect( firstButton ).toHaveFocus(); + await user.tab( { shift: true } ); + expect( baseElement ).toHaveFocus(); } ); test( 'when `focusOnMount` is "firstElement" if `constrainTabbing` is false', async () => { @@ -419,6 +431,10 @@ describe( 'Popover', () => { expect( thirdButton ).toHaveFocus(); await user.tab(); expect( baseElement ).toHaveFocus(); + await user.tab(); + expect( firstButton ).toHaveFocus(); + await user.tab( { shift: true } ); + expect( baseElement ).toHaveFocus(); } ); } ); } ); From ee70cd501203c43efcf3d51e70b8f2d2d2807bed Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Fri, 26 Jan 2024 13:35:57 +0000 Subject: [PATCH 09/11] Using `.skip` in favour of a block comment for failing tests --- packages/components/src/popover/test/index.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/components/src/popover/test/index.tsx b/packages/components/src/popover/test/index.tsx index 794f3739a1b5f..b3f5a9b8ef062 100644 --- a/packages/components/src/popover/test/index.tsx +++ b/packages/components/src/popover/test/index.tsx @@ -242,14 +242,12 @@ describe( 'Popover', () => { }; }; - // eslint-disable-next-line jest/no-commented-out-tests - /* - // Note: due to an issue in testing-library/user-event [1], the // tests for constrained tabbing fail. // [1]: https://github.com/testing-library/user-event/issues/1188 - - describe( 'constrains tabbing', () => { + // + // eslint-disable-next-line jest/no-disabled-tests + describe.skip( 'constrains tabbing', () => { test( 'by default', async () => { // The default value for `focusOnMount` is 'firstElement', // which means the default value for `constrainTabbing` is @@ -331,7 +329,6 @@ describe( 'Popover', () => { expect( thirdButton ).toHaveFocus(); } ); } ); - */ describe( 'does not constrain tabbing', () => { test( 'when `constrainTabbing` is false', async () => { From a376dfdaf8da0b6b1a24d11745beaa1b9010d913 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Tue, 30 Jan 2024 16:20:31 +0000 Subject: [PATCH 10/11] Clarifying `getOffsetHeight` mock, by making it global, and adding comments. --- .../components/src/popover/test/index.tsx | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/components/src/popover/test/index.tsx b/packages/components/src/popover/test/index.tsx index b3f5a9b8ef062..22c576683a010 100644 --- a/packages/components/src/popover/test/index.tsx +++ b/packages/components/src/popover/test/index.tsx @@ -37,23 +37,26 @@ type PlacementToInitialTranslationTuple = [ CSSProperties[ 'translate' ], ]; -let offsetHeightSpy: jest.SpiedGetter< - typeof HTMLElement.prototype.offsetHeight ->; - beforeAll( () => { - offsetHeightSpy = jest - .spyOn( HTMLElement.prototype, 'offsetHeight', 'get' ) - .mockImplementation( function getOffsetHeight( this: HTMLElement ) { - if ( this.tagName === 'BODY' ) { - return window.outerHeight; - } - return 50; - } ); + // This mock is necessary because deep in the weeds, `useConstrained` relies + // on `focusable` to return a list of DOM elements that can be focused. Part + // of this process involves checking that an element has an intrinsic size, + // which will always fail in JSDom. + // + // https://github.com/WordPress/gutenberg/blob/trunk/packages/dom/src/focusable.js#L55-L61 + jest.spyOn( + HTMLElement.prototype, + 'offsetHeight', + 'get' + ).mockImplementation( function getOffsetHeight( this: HTMLElement ) { + // The `1` returned here is somewhat arbitrary – it just needs to be a + // non-zero integer. + return 1; + } ); } ); afterAll( () => { - offsetHeightSpy?.mockRestore(); + jest.restoreAllMocks(); } ); // There's no matching `placement` for 'middle center' positions, From 09e5d0fb2245984dbfeae76d1e275f266f356278 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Tue, 30 Jan 2024 16:24:19 +0000 Subject: [PATCH 11/11] Fixing comment typo --- packages/compose/src/hooks/use-dialog/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/compose/src/hooks/use-dialog/index.ts b/packages/compose/src/hooks/use-dialog/index.ts index a4eb29981f40e..1b517478fa0bd 100644 --- a/packages/compose/src/hooks/use-dialog/index.ts +++ b/packages/compose/src/hooks/use-dialog/index.ts @@ -31,8 +31,9 @@ type DialogOptions = { /** * Determines whether tabbing is constrained to within the popover, * preventing keyboard focus from leaving the popover content without - * explicit focus elswhere, or whether the popover remains part of the wider - * tab order. If no value is passed, it will be derived from `focusOnMount`. + * explicit focus elsewhere, or whether the popover remains part of the + * wider tab order. + * If no value is passed, it will be derived from `focusOnMount`. * * @see focusOnMount * @default `focusOnMount` !== false