diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 35541f2686ea3..91cdaec426d71 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,16 @@ ## Unreleased +### Bug Fix + +- `Popover`: fix limitShift logic by adding iframe offset correctly [#42950](https://github.com/WordPress/gutenberg/pull/42950)). +- `Popover`: refine position-to-placement conversion logic, add tests ([#44377](https://github.com/WordPress/gutenberg/pull/44377)). + +### Internal + +- `Mobile` updated to ignore `react/exhaustive-deps` eslint rule ([#44207](https://github.com/WordPress/gutenberg/pull/44207)). +- `Popover`: refactor unit tests to TypeScript and modern RTL assertions ([#44373](https://github.com/WordPress/gutenberg/pull/44373)). + ## 21.1.0 (2022-09-21) ### Deprecations @@ -12,16 +22,13 @@ - `Button`: Remove unexpected `has-text` class when empty children are passed ([#44198](https://github.com/WordPress/gutenberg/pull/44198)). - The `LinkedButton` to unlink sides in `BoxControl`, `BorderBoxControl` and `BorderRadiusControl` have changed from a rectangular primary button to an icon-only button, with a sentence case tooltip, and default-size icon for better legibility. The `Button` component has been fixed so when `isSmall` and `icon` props are set, and no text is present, the button shape is square rather than rectangular. -- `Popover`: fix limitShift logic by adding iframe offset correctly [#42950](https://github.com/WordPress/gutenberg/pull/42950)). ### Internal - `NavigationMenu` updated to ignore `react/exhaustive-deps` eslint rule ([#44090](https://github.com/WordPress/gutenberg/pull/44090)). -- `Mobile` updated to ignore `react/exhaustive-deps` eslint rule ([#44207](https://github.com/WordPress/gutenberg/pull/44207)). - `RangeControl`: updated to pass `react/exhaustive-deps` eslint rule ([#44271](https://github.com/WordPress/gutenberg/pull/44271)). - `UnitControl` updated to pass the `react/exhaustive-deps` eslint rule ([#44161](https://github.com/WordPress/gutenberg/pull/44161)). - `Notice`: updated to satisfy `react/exhaustive-deps` eslint rule ([#44157](https://github.com/WordPress/gutenberg/pull/44157)) -- `Popover`: refactor unit tests to TypeScript and modern RTL assertions ([#44373](https://github.com/WordPress/gutenberg/pull/44373)). ## 21.0.0 (2022-09-13) diff --git a/packages/components/src/popover/test/index.tsx b/packages/components/src/popover/test/index.tsx index 2a0c5db545da3..b06886e52243e 100644 --- a/packages/components/src/popover/test/index.tsx +++ b/packages/components/src/popover/test/index.tsx @@ -31,6 +31,64 @@ type PlacementToInitialTranslationTuple = [ CSSProperties[ 'translate' ] ]; +// 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'; + +const ALL_POSITIONS_TO_EXPECTED_PLACEMENTS: PositionToPlacementTuple[] = [ + // Format: [yAxis] + [ 'middle', FALLBACK_FOR_MIDDLE_CENTER_POSITIONS ], + [ 'bottom', 'bottom' ], + [ 'top', 'top' ], + // Format: [yAxis] [xAxis] + [ 'middle left', 'left' ], + [ 'middle center', FALLBACK_FOR_MIDDLE_CENTER_POSITIONS ], + [ 'middle right', 'right' ], + [ 'bottom left', 'bottom-end' ], + [ 'bottom center', 'bottom' ], + [ 'bottom right', 'bottom-start' ], + [ 'top left', 'top-end' ], + [ 'top center', 'top' ], + [ 'top right', 'top-start' ], + // Format: [yAxis] [xAxis] [corner] + [ 'middle left left', 'left' ], + [ 'middle left right', 'left' ], + [ 'middle left bottom', 'left-end' ], + [ 'middle left top', 'left-start' ], + [ 'middle center left', FALLBACK_FOR_MIDDLE_CENTER_POSITIONS ], + [ 'middle center right', FALLBACK_FOR_MIDDLE_CENTER_POSITIONS ], + [ 'middle center bottom', FALLBACK_FOR_MIDDLE_CENTER_POSITIONS ], + [ 'middle center top', FALLBACK_FOR_MIDDLE_CENTER_POSITIONS ], + [ 'middle right left', 'right' ], + [ 'middle right right', 'right' ], + [ 'middle right bottom', 'right-end' ], + [ 'middle right top', 'right-start' ], + [ 'bottom left left', 'bottom-end' ], + [ 'bottom left right', 'bottom-end' ], + [ 'bottom left bottom', 'bottom-end' ], + [ 'bottom left top', 'bottom-end' ], + [ 'bottom center left', 'bottom' ], + [ 'bottom center right', 'bottom' ], + [ 'bottom center bottom', 'bottom' ], + [ 'bottom center top', 'bottom' ], + [ 'bottom right left', 'bottom-start' ], + [ 'bottom right right', 'bottom-start' ], + [ 'bottom right bottom', 'bottom-start' ], + [ 'bottom right top', 'bottom-start' ], + [ 'top left left', 'top-end' ], + [ 'top left right', 'top-end' ], + [ 'top left bottom', 'top-end' ], + [ 'top left top', 'top-end' ], + [ 'top center left', 'top' ], + [ 'top center right', 'top' ], + [ 'top center bottom', 'top' ], + [ 'top center top', 'top' ], + [ 'top right left', 'top-start' ], + [ 'top right right', 'top-start' ], + [ 'top right bottom', 'top-start' ], + [ 'top right top', 'top-start' ], +]; + describe( 'Popover', () => { describe( 'Component', () => { describe( 'basic behavior', () => { @@ -93,17 +151,7 @@ describe( 'Popover', () => { } ); describe( 'positionToPlacement', () => { - it.each( [ - [ 'top left', 'top-end' ], - [ 'top center', 'top' ], - [ 'top right', 'top-start' ], - [ 'middle left', 'left' ], - [ 'middle center', 'center' ], - [ 'middle right', 'right' ], - [ 'bottom left', 'bottom-end' ], - [ 'bottom center', 'bottom' ], - [ 'bottom right', 'bottom-start' ], - ] as PositionToPlacementTuple[] )( + it.each( ALL_POSITIONS_TO_EXPECTED_PLACEMENTS )( 'converts `%s` to `%s`', ( inputPosition, expectedPlacement ) => { expect( positionToPlacement( inputPosition ) ).toEqual( diff --git a/packages/components/src/popover/types.ts b/packages/components/src/popover/types.ts index b80e266c1fe2c..2f738ca76a3a9 100644 --- a/packages/components/src/popover/types.ts +++ b/packages/components/src/popover/types.ts @@ -121,6 +121,7 @@ export type PopoverProps = { * _Note: this prop is deprecated. Use the `placement` prop instead._ */ position?: + | `${ PositionYAxis }` | `${ PositionYAxis } ${ PositionXAxis }` | `${ PositionYAxis } ${ PositionXAxis } ${ PositionCorner }`; /** diff --git a/packages/components/src/popover/utils.ts b/packages/components/src/popover/utils.ts index c5b15a076114f..f14e2c921f1ed 100644 --- a/packages/components/src/popover/utils.ts +++ b/packages/components/src/popover/utils.ts @@ -14,6 +14,62 @@ import type { PopoverAnchorRefTopBottom, } from './types'; +const POSITION_TO_PLACEMENT: Record< + NonNullable< PopoverProps[ 'position' ] >, + NonNullable< PopoverProps[ 'placement' ] > +> = { + bottom: 'bottom', + top: 'top', + 'middle left': 'left', + 'middle right': 'right', + 'bottom left': 'bottom-end', + 'bottom center': 'bottom', + 'bottom right': 'bottom-start', + 'top left': 'top-end', + 'top center': 'top', + 'top right': 'top-start', + 'middle left left': 'left', + 'middle left right': 'left', + 'middle left bottom': 'left-end', + 'middle left top': 'left-start', + 'middle right left': 'right', + 'middle right right': 'right', + 'middle right bottom': 'right-end', + 'middle right top': 'right-start', + 'bottom left left': 'bottom-end', + 'bottom left right': 'bottom-end', + 'bottom left bottom': 'bottom-end', + 'bottom left top': 'bottom-end', + 'bottom center left': 'bottom', + 'bottom center right': 'bottom', + 'bottom center bottom': 'bottom', + 'bottom center top': 'bottom', + 'bottom right left': 'bottom-start', + 'bottom right right': 'bottom-start', + 'bottom right bottom': 'bottom-start', + 'bottom right top': 'bottom-start', + 'top left left': 'top-end', + 'top left right': 'top-end', + 'top left bottom': 'top-end', + 'top left top': 'top-end', + 'top center left': 'top', + 'top center right': 'top', + 'top center bottom': 'top', + 'top center top': 'top', + 'top right left': 'top-start', + 'top right right': 'top-start', + 'top right bottom': 'top-start', + 'top right top': 'top-start', + // `middle`/`middle center [corner?]` positions are associated to a fallback + // `bottom` placement because there aren't any corresponding placement values. + middle: 'bottom', + 'middle center': 'bottom', + 'middle center bottom': 'bottom', + 'middle center left': 'bottom', + 'middle center right': 'bottom', + 'middle center top': 'bottom', +}; + /** * Converts the `Popover`'s legacy "position" prop to the new "placement" prop * (used by `floating-ui`). @@ -23,22 +79,8 @@ import type { */ export const positionToPlacement = ( position: NonNullable< PopoverProps[ 'position' ] > -): NonNullable< PopoverProps[ 'placement' ] > => { - const [ x, y, z ] = position.split( ' ' ); - - if ( [ 'top', 'bottom' ].includes( x ) ) { - let suffix = ''; - if ( ( !! z && z === 'left' ) || y === 'right' ) { - suffix = '-start'; - } else if ( ( !! z && z === 'right' ) || y === 'left' ) { - suffix = '-end'; - } - - return ( x + suffix ) as NonNullable< PopoverProps[ 'placement' ] >; - } - - return y as NonNullable< PopoverProps[ 'placement' ] >; -}; +): NonNullable< PopoverProps[ 'placement' ] > => + POSITION_TO_PLACEMENT[ position ] ?? 'bottom'; /** * @typedef AnimationOrigin