Skip to content

Commit

Permalink
fix(react/tooltip): resolve tooltip misalignment issue with popup mod…
Browse files Browse the repository at this point in the history
…al items for V1 (#925)

* fix(react/tooltip): resolve tooltip misalignment issue with popup menu items

* chore: add a common pixelize function

* refactor(react/OverflowTooltip): dynamically adjust disabled based on the isOverflow state

* refactor(react/tree): replace ensureNumber with ensureFiniteNumber

* docs: update tooltip and overflow-tooltip examples

* fix(react/tooltip): resolve tooltip misalignment issue with popup menu items

* chore: add a common pixelize function

* refactor(react/OverflowTooltip): dynamically adjust disabled based on the isOverflow state

* refactor(react/tree): replace ensureNumber with ensureFiniteNumber

* docs: update tooltip and overflow-tooltip examples

* fix: use the Icon component instead of react-icons for v1

* fix: resolve eslint errors

* chore: update yarn.lock file

* Create tonic-ui-893-v1.md

* feat!: update default values for `OverflowTooltip` component props

* feat: disable placement enforcement when `followCursor` or `nextToCursor` prop is enabled

* Update tonic-ui-893-v1.md

---------

Co-authored-by: cheton <cheton@gmail.com>
Co-authored-by: Cheton Wu <447801+cheton@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 19, 2024
1 parent 5072b31 commit 393843a
Show file tree
Hide file tree
Showing 17 changed files with 519 additions and 1,651 deletions.
5 changes: 5 additions & 0 deletions .changeset/tonic-ui-893-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tonic-ui/react": minor
---

fix(react/tooltip): resolve tooltip misalignment issue with popup modal items
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import {
Menu,
MenuButton,
MenuList,
MenuItem,
OverflowTooltip,
Scrollbar,
} from '@tonic-ui/react';
import React from 'react';

const CustomOverflowTooltip = ({ children }) => {
return (
<OverflowTooltip
label={children}
PopperProps={{ usePortal: true }}
>
{children}
</OverflowTooltip>
);
};

const App = () => {
const shortText = 'This text string is not truncated';
const longText = 'This text string will be truncated when exceeding its container width';

return (
<Menu width={240}>
<MenuButton>Options</MenuButton>
<MenuList width="100%">
<Scrollbar maxHeight={200} overflowX="hidden" overflowY="auto">
<MenuItem>
<CustomOverflowTooltip>
{longText}
</CustomOverflowTooltip>
</MenuItem>
<MenuItem>
<CustomOverflowTooltip>
{shortText}
</CustomOverflowTooltip>
</MenuItem>
<MenuItem>
<CustomOverflowTooltip>
{shortText}
</CustomOverflowTooltip>
</MenuItem>
<MenuItem>
<CustomOverflowTooltip>
{shortText}
</CustomOverflowTooltip>
</MenuItem>
<MenuItem>
<CustomOverflowTooltip>
{shortText}
</CustomOverflowTooltip>
</MenuItem>
<MenuItem>
<CustomOverflowTooltip>
{shortText}
</CustomOverflowTooltip>
</MenuItem>
<MenuItem>
<CustomOverflowTooltip>
{longText}
</CustomOverflowTooltip>
</MenuItem>
<MenuItem>
<CustomOverflowTooltip>
{shortText}
</CustomOverflowTooltip>
</MenuItem>
<MenuItem>
<CustomOverflowTooltip>
{shortText}
</CustomOverflowTooltip>
</MenuItem>
<MenuItem>
<CustomOverflowTooltip>
{shortText}
</CustomOverflowTooltip>
</MenuItem>
</Scrollbar>
</MenuList>
</Menu>
);
};

export default App;
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import {
Icon,
Flex,
TextLabel,
} from '@tonic-ui/react';

# OverflowTooltip

The `OverflowTooltip` component is a tooltip that only displays when text overflows its container.

> <TextLabel><Flex alignItems="center" columnGap="2x" mb="2x"><Icon icon="alert" /> IMPORTANT NOTICE</Flex></TextLabel>
> By default, the `OverflowTooltip` component has the `placement` prop set to `bottom-end` and the `offset` prop set to `[8, 12]`. In this setup, the first value in the `offset` array controls the skidding, while the second value determines the distance. You may need to modify the `placement` and `offset` props to suit your specific requirements better.
## Import

```js
Expand All @@ -10,7 +19,9 @@ import { OverflowTooltip } from '@tonic-ui/react';

## Usage

If the text overflows its container, it will be truncated, and an ellipsis will be added. When you hover or focus on the ellipsis text, a tooltip will appear.
When the text overflows its container, it will be truncated, and an ellipsis will be added. Hovering over or focusing on the truncated text will display a tooltip.

By default, the overflow tooltip does not include an arrow and will display next to the cursor.

{render('./basic')}

Expand All @@ -24,9 +35,17 @@ In the second example, a function is passed as a child of the `OverflowTooltip`

By default, the `OverflowTooltip` component positions the tooltip relative to its parent container. In some cases, the tooltip content might be cut off when it extends outside the container that holds it.

To mitigate this issue, you can pass `PopperProps={{ usePortal: true }}` to `OverflowTooltip` to make it positioned on the document root.
To prevent this, pass `PopperProps={{ usePortal: true }}` to the `OverflowTooltip`. This will position the tooltip at the document root.

{render('./faq-tooltip-cut-off')}

### Misalignment with menu items

The `OverflowTooltip` is positioned next to the cursor by default. However, when used within a popup menu, the tooltip may not align correctly with the menu items.

To resolve this issue, set `PopperProps={{ usePortal: true }}`.

{render('./faq-use-portal')}
{render('./faq-misalignment-with-menu-items')}

## Props

Expand All @@ -41,21 +60,21 @@ To mitigate this issue, you can pass `PopperProps={{ usePortal: true }}` to `Ove
| TransitionComponent | ElementType | Grow | The component used for the transition. |
| TransitionProps | object | | Props applied to the [Transition](http://reactcommunity.org/react-transition-group/transition#Transition-props) element. |
| TransitionProps.appear | boolean | true | |
| arrow | boolean | true | If `true`, adds an arrow to the tooltip. |
| arrow | boolean | true | If `true`, adds an arrow to the tooltip. Note: The arrow is not visible when `followCursor` or `nextToCursor` is enabled. |
| children | ReactNode \| `(context) => ReactNode` | | |
| closeOnClick | boolean | true | If `true`, close the tooltip on click. |
| closeOnEsc | boolean | true | If `true`, close the tooltip when pressing the escape key. |
| closeOnMouseDown | boolean | false | If `true`, close the tooltip while the mouse is down. |
| defaultIsOpen | boolean | false | Whether the tooltip will be open by default. |
| disabled | boolean | | If `true`, the tooltip will not display. |
| disabled | boolean | false | If `true`, the tooltip will not display. |
| enterDelay | number | 100 | The delay in milliseconds before the tooltip appears. |
| followCursor | boolean | | If `true`, the tooltip will follow the cursor. |
| isOpen | boolean | | If `true`, show the tooltip. |
| label | string \| ReactNode | | If the tooltip label is a blank or empty string, the tooltip will not display. |
| leaveDelay | number | 0 | The delay in milliseconds before the tooltip disappears. |
| nextToCursor | boolean | | If `true`, the tooltip will be positioned next to the cursor. |
| offset | [skidding, distance] | [0, 8] | The skidding and distance of the tooltip. |
| nextToCursor | boolean | true | If `true`, the tooltip will be positioned next to the cursor. |
| offset | [skidding, distance] | [8, 12] | The skidding and distance of the tooltip. |
| onClose| function | | Callback fired when the tooltip is closed. |
| onOpen | function | | Callback fired when the tooltip is opened. |
| placement | PopperJS.Placement | 'bottom' | Position the tooltip relative to the trigger element as well as surrounding elements. One of: 'top', 'bottom', 'right', 'left', 'top-start', 'top-end', 'bottom-start', 'bottom-end', 'right-start', 'right-end', 'left-start', 'left-end' |
| placement | PopperJS.Placement | 'bottom-end' | Position the tooltip relative to the trigger element as well as surrounding elements. One of: 'top', 'bottom', 'right', 'left', 'top-start', 'top-end', 'bottom-start', 'bottom-end', 'right-start', 'right-end', 'left-start', 'left-end' |
| shouldWrapChildren | boolean | false | If `true`, the tooltip will be wrapped in a `Box` component. Otherwise, you have to ensure tooltip has only one child node. |
4 changes: 3 additions & 1 deletion packages/react-docs/pages/components/tooltip/index.page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ The `distance` number controls the distance between the `TooltipContent` and the

{render('./positioning-offset')}

> By default, the tooltip's offset is set to `[0, 8]`, where the first value represents the `skidding` and the second value represents the `distance`.<br/>In the `nextToCursor` and `followCursor` examples below, the `distance` value is set to 16. You may need to adjust this value to better suit your specific requirements.
#### Using the `nextToCursor` prop

The `nextToCursor` prop positions the tooltip next to the cursor.
Expand Down Expand Up @@ -166,7 +168,7 @@ In the following example, the tooltip's placement is initially set to `top`. How
| TransitionComponent | ElementType | Grow | The component used for the transition. |
| TransitionProps | object | | Props applied to the [Transition](http://reactcommunity.org/react-transition-group/transition#Transition-props) element. |
| TransitionProps.appear | boolean | true | |
| arrow | boolean | true | If `true`, adds an arrow to the tooltip. |
| arrow | boolean | true | If `true`, adds an arrow to the tooltip. Note: The arrow is not visible when `followCursor` or `nextToCursor` is enabled. |
| children | ReactNode \| `(context) => ReactNode` | | |
| closeOnClick | boolean | true | If `true`, the tooltip will close upon clicking. |
| closeOnEsc | boolean | true | If `true`, the tooltip will close upon pressing the escape key. |
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,128 @@
import { Text, Tooltip } from '@tonic-ui/react';
import React from 'react';
import {
Box,
Divider,
Flex,
Icon,
Menu,
MenuButton,
MenuItem,
MenuList,
Text,
TextLabel,
Tooltip,
useColorStyle,
} from '@tonic-ui/react';
import React, { useState } from 'react';

const App = () => (
<Tooltip label="This is a tooltip" followCursor>
<Text display="inline-block">Hover Me</Text>
</Tooltip>
const FormGroup = (props) => (
<Box mb="4x" {...props} />
);

export default App;
const useSelection = (defaultValue) => {
const [value, setValue] = useState(defaultValue);
const changeBy = (value) => () => setValue(value);
return [value, changeBy];
};

const App = () => {
const [colorStyle] = useColorStyle();
const [placement, changePlacementBy] = useSelection('bottom-end');
const [skidding, setSkidding] = useState(8);
const [distance, setDistance] = useState(12);

return (
<>
<FormGroup>
<Box mb="2x">
<TextLabel>
placement
</TextLabel>
</Box>
<Menu>
<MenuButton
variant="secondary"
minWidth={150}
>
{placement}
</MenuButton>
<MenuList
width="max-content"
minWidth={150}
>
{[
'top', 'top-start', 'top-end',
'bottom', 'bottom-start', 'bottom-end',
'left', 'left-start', 'left-end',
'right', 'right-start', 'right-end',
].map(_placement => (
<MenuItem
key={_placement}
onClick={changePlacementBy(_placement)}
>
<Flex columnGap="2x">
{placement === _placement ? <Icon icon="check-s" /> : <Box width="4x" />}
{_placement}
</Flex>
</MenuItem>
))}
</MenuList>
</Menu>
</FormGroup>
<FormGroup>
<Box mb="2x">
<TextLabel>skidding</TextLabel>
</Box>
<Flex columnGap="4x">
<input
type="range"
name="skidding"
min={-48}
max={48}
value={skidding}
onChange={(e) => setSkidding(Number(e.target.value))}
/>
<Text>{skidding}</Text>
</Flex>
</FormGroup>
<FormGroup>
<Box mb="2x">
<TextLabel>distance</TextLabel>
</Box>
<Flex columnGap="4x">
<input
type="range"
name="distance"
min={-48}
max={48}
value={distance}
onChange={(e) => setDistance(Number(e.target.value))}
/>
<Text>{distance}</Text>
</Flex>
</FormGroup>
<Divider my="4x" />
<Tooltip
label="This is a tooltip"
followCursor
offset={[skidding, distance]}
placement={placement}
>
<Flex
sx={{
border: 1,
backgroundColor: colorStyle.background.secondary,
borderColor: colorStyle.divider,
width: 240,
height: 180,
alignItems: 'center',
justifyContent: 'center',
}}
>
Hover Me
</Flex>
</Tooltip>
</>
);
};

export default App;
Loading

0 comments on commit 393843a

Please sign in to comment.