Skip to content

Commit

Permalink
Tooltip: Fix positioning by anchoring to child element (#41268)
Browse files Browse the repository at this point in the history
* ToolTip: Fix positioning by anchoring to child element

* Fix left/right issue

* Switch post schedule and post visiblity to 'bottom right' for consistency

* Move left/right transformation to the ToolTip component

* Switch back to functions, fix tests

* Tidy up

* Add changelog entry

* Center Tooltip to the appropriate placement point

* Attempt to simplify the implementation

* Revert change to test

* Revert default back to middle position

* Fix error with getDisabledElement

* Move ref in disabled element to the cloned child element

* Update Storybook example with a small target to better demonstrate positioning issues

* Simplify Tooltip story slightly

* Consolidate child const for both uses

* Revert previous change, but add a named const for the existing child ref for clarity
  • Loading branch information
andrewserong authored Jul 19, 2022
1 parent ca9ece2 commit 49a4a01
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 23 deletions.
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
- `ComboboxControl`: use custom prefix when generating the instanceId ([#42134](https://github.com/WordPress/gutenberg/pull/42134).
- `Popover`: pass missing anchor ref to the `getAnchorRect` callback prop. ([#42076](https://github.com/WordPress/gutenberg/pull/42076)).
- `Popover`: call `getAnchorRect` callback prop even if `anchorRefFallback` has no value. ([#42329](https://github.com/WordPress/gutenberg/pull/42329)).
- Fix `ToolTip` position to ensure it is always positioned relative to the first child of the ToolTip. ([#41268](https://github.com/WordPress/gutenberg/pull/41268))

### Enhancement

Expand Down
46 changes: 37 additions & 9 deletions packages/components/src/tooltip/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import {
concatChildren,
useEffect,
useState,
useRef,
} from '@wordpress/element';
import { useDebounce } from '@wordpress/compose';
import { useDebounce, useMergeRefs } from '@wordpress/compose';

/**
* Internal dependencies
Expand All @@ -31,29 +32,45 @@ export const TOOLTIP_DELAY = 700;

const eventCatcher = <div className="event-catcher" />;

const getDisabledElement = ( { eventHandlers, child, childrenWithPopover } ) =>
cloneElement(
const getDisabledElement = ( {
eventHandlers,
child,
childrenWithPopover,
mergedRefs,
} ) => {
return cloneElement(
<span className="disabled-element-wrapper">
{ cloneElement( eventCatcher, eventHandlers ) }
{ cloneElement( child, {
children: childrenWithPopover,
ref: mergedRefs,
} ) }
</span>,
eventHandlers
{ ...eventHandlers }
);
};

const getRegularElement = ( { child, eventHandlers, childrenWithPopover } ) =>
cloneElement( child, {
const getRegularElement = ( {
child,
eventHandlers,
childrenWithPopover,
mergedRefs,
} ) => {
return cloneElement( child, {
...eventHandlers,
children: childrenWithPopover,
ref: mergedRefs,
} );
};

const addPopoverToGrandchildren = ( {
anchorRef,
grandchildren,
isOver,
offset,
position,
text,
shortcut,
text,
} ) =>
concatChildren(
grandchildren,
Expand All @@ -64,7 +81,8 @@ const addPopoverToGrandchildren = ( {
className="components-tooltip"
aria-hidden="true"
animate={ false }
offset={ 12 }
offset={ offset }
anchorRef={ anchorRef }
__unstableShift
>
{ text }
Expand Down Expand Up @@ -111,6 +129,13 @@ function Tooltip( props ) {
const [ isOver, setIsOver ] = useState( false );
const delayedSetIsOver = useDebounce( setIsOver, delay );

// Create a reference to the Tooltip's child, to be passed to the Popover
// so that the Tooltip can be correctly positioned. Also, merge with the
// existing ref for the first child, so that its ref is preserved.
const childRef = useRef( null );
const existingChildRef = Children.toArray( children )[ 0 ]?.ref;
const mergedChildRefs = useMergeRefs( [ childRef, existingChildRef ] );

const createMouseDown = ( event ) => {
// Preserve original child callback behavior.
emitToChild( children, 'onMouseDown', event );
Expand Down Expand Up @@ -214,10 +239,12 @@ function Tooltip( props ) {
: getRegularElement;

const popoverData = {
anchorRef: childRef,
isOver,
offset: 4,
position,
text,
shortcut,
text,
};
const childrenWithPopover = addPopoverToGrandchildren( {
grandchildren,
Expand All @@ -228,6 +255,7 @@ function Tooltip( props ) {
child,
eventHandlers,
childrenWithPopover,
mergedRefs: mergedChildRefs,
} );
}

Expand Down
41 changes: 28 additions & 13 deletions packages/components/src/tooltip/stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,34 @@ export const _default = () => {
const position = select( 'Position', positionOptions, 'top center' );
const delay = number( 'Delay', 700 );
return (
<Tooltip text={ tooltipText } position={ position } delay={ delay }>
<div
style={ {
margin: '50px auto',
width: '200px',
padding: '20px',
textAlign: 'center',
border: '1px solid #ccc',
} }
>
Hover for more information
</div>
</Tooltip>
<>
<Tooltip text={ tooltipText } position={ position } delay={ delay }>
<div
style={ {
margin: '50px auto',
width: '200px',
padding: '20px',
textAlign: 'center',
border: '1px solid #ccc',
} }
>
Hover for more information
</div>
</Tooltip>
<Tooltip text={ tooltipText } position={ position } delay={ delay }>
<div
style={ {
margin: '50px auto',
width: 'min-content',
padding: '4px',
textAlign: 'center',
border: '1px solid #ccc',
} }
>
Small target
</div>
</Tooltip>
</>
);
};

Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/tooltip/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
z-index: z-index(".components-tooltip");

.components-popover__content {
min-width: 0;
min-width: min-content;
}
}

Expand Down

0 comments on commit 49a4a01

Please sign in to comment.