Skip to content

Commit

Permalink
feat(tooltip): add new tooltip (#1399)
Browse files Browse the repository at this point in the history
* refactor(Popover): Move Popover to legacy/

* chore: add react-poper and @popperjs/core repos

* refactor(eslint): update eslint rule

* test(style): fix stylelint issues

* feat(Popover): update some features for popover

* fix(Popover): use useRef for popover

* fix(eslint): update some eslint issues

* fix(popover): update useRef

* fix(build): update useRef issue

* fix(role): add role for different trigger

* fix(popover): support trigger as string | string[]

* fix(style): update popover styles

* factor(tooltip): move tooltip to legacy/tooltip

* feat(tooltip): add tooltip

* feat(popover): support new props for popover

* fix(Tooltip): add max-width for tooltip

* feat(Tooltip): add tooltip component

* fix(unnecessary): remove unnecessary code

* fix(index.ts): remove unnecessary file

* fix(tooltip): resolve some feedback issues

* fix(interface): update the interface

* fix(lint): resolve es lint issue

Co-authored-by: Zhang Rui <zhangrui@growingio.com>
  • Loading branch information
Ryan Zhang and Zhang Rui committed Nov 1, 2021
1 parent 1090f89 commit da94622
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 0 deletions.
52 changes: 52 additions & 0 deletions src/tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { useMemo } from 'react';
import classNames from 'classnames';
import { isFunction } from 'lodash';
import { TooltipProps } from './interface';
import Popover from '../popover/Popover';
import usePrefixCls from '../utils/hooks/use-prefix-cls';

import Link from '../link';

const Tooltip = (props: TooltipProps) => {
const {
children,
title,
overlay,
tooltipLink,
prefixCls: customizePrefixCls,
subPrefixCls = 'tooltip-new',
...rest
} = props;
const prefixCls = usePrefixCls(subPrefixCls, customizePrefixCls);

const contentInnerCls = useMemo(() => classNames(`${prefixCls}__inner`), [prefixCls]);

const [computedTitle, computedOverlay] = useMemo(
() => [isFunction(title) ? title() : title, isFunction(overlay) ? overlay() : overlay],
[title, overlay]
);

const tooltipOverlay = useMemo(() => {
const isNoTitle = !computedTitle && computedTitle !== 0;
return isNoTitle ? null : (
<>
<span className={`${prefixCls}__inner-title`}>{computedTitle}</span>
{tooltipLink?.link && <Link href={tooltipLink.link}>{tooltipLink.name || tooltipLink.link}</Link>}
</>
);
}, [prefixCls, computedTitle, tooltipLink]);

return (
<Popover
{...rest}
prefixCls={customizePrefixCls}
overlayClassName={prefixCls}
overlayInnerClassName={contentInnerCls}
content={computedOverlay || tooltipOverlay}
>
{children}
</Popover>
);
};

export default Tooltip;
246 changes: 246 additions & 0 deletions src/tooltip/demos/Tooltip.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
import React, { useState } from 'react';
import { Story, Meta } from '@storybook/react/types-6-0';
import { withDesign } from 'storybook-addon-designs';
import Tooltip from '../Tooltip';
import { TooltipProps } from '../interface';
import Input from '../../input';
import { Button } from '../../button';

import '../../popover/style';
import '../style';
import '../../popover/demos/demo.stories.less';

export default {
title: 'Upgraded/Tooltip',
component: Tooltip,
decorators: [withDesign],
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/kP3A6S2fLUGVVMBgDuUx0f/GrowingIO-Design-Components?node-id=889%3A1753',
allowFullscreen: true,
},
docs: {
page: null,
},
},
} as Meta;

const Template: Story<TooltipProps> = (args) => (
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ width: '610px', margin: '70px 0px' }}>
<div className="tooltip-top">
<span className="popover-wrapper">
<Tooltip {...args} placement="topLeft">
<span className="popover-span">TopLeft</span>
</Tooltip>
</span>
<span className="popover-wrapper">
<Tooltip {...args} placement="top">
<span className="popover-span">Top</span>
</Tooltip>
</span>
<span className="popover-wrapper">
<Tooltip {...args} placement="topRight">
<span className="popover-span">TopRight</span>
</Tooltip>
</span>
</div>
<div className="tooltip-left" style={{ marginLeft: '40px' }}>
<span className="popover-wrapper">
<Tooltip {...args} placement="leftTop">
<span className="popover-span">LeftTop</span>
</Tooltip>
</span>
<span className="popover-wrapper">
<Tooltip {...args} placement="left">
<span className="popover-span">Left</span>
</Tooltip>
</span>
<span className="popover-wrapper">
<Tooltip {...args} placement="leftBottom">
<span className="popover-span">LeftBottom</span>
</Tooltip>
</span>
</div>
<div className="tooltip-right" style={{ marginLeft: '455px' }}>
<span className="popover-wrapper">
<Tooltip {...args} placement="rightTop">
<span className="popover-span">RightTop</span>
</Tooltip>
</span>
<span className="popover-wrapper">
<Tooltip {...args} placement="right">
<span className="popover-span">Right</span>
</Tooltip>
</span>
<span className="popover-wrapper">
<Tooltip {...args} placement="rightBottom">
<span className="popover-span">RightBottom</span>
</Tooltip>
</span>
</div>
<div className="tooltip-buttom">
<span className="popover-wrapper">
<Tooltip {...args} placement="bottomLeft">
<span className="popover-span">BottomLeft</span>
</Tooltip>
</span>
<span className="popover-wrapper">
<Tooltip {...args} placement="bottom">
<span className="popover-span">Bottom</span>
</Tooltip>
</span>
<span className="popover-wrapper">
<Tooltip {...args} placement="bottomRight">
<span className="popover-span">BottomRight</span>
</Tooltip>
</span>
</div>
</div>
</div>
);

const overlay = (
<>
这是提示文案。
<br />
需要有足够的长宽!
</>
);
export const Placement = Template.bind({});
Placement.args = {
arrowPointAtCenter: true,
overlay,
};

const TriggerTemplate: Story<TooltipProps> = (args) => (
<div style={{ margin: '150px 200px' }}>
<span style={{ marginRight: 20 }}>
<Tooltip {...args} trigger="hover" placement="top">
<Input value="Touch Me!" style={{ width: 100 }} />
</Tooltip>
</span>
<span style={{ marginRight: 20 }}>
<Tooltip {...args} trigger="focus" placement="top">
<Input value="Focus Me!" style={{ width: 100 }} />
</Tooltip>
</span>
<span style={{ marginRight: 20 }}>
<Tooltip {...args} trigger={['focus', 'click']} placement="top">
<Input value="Focus or Click Me!" style={{ width: 150 }} />
</Tooltip>
</span>
<span style={{ marginRight: 20 }}>
<Tooltip {...args} trigger="click" placement="top">
<Input value="Click Me!" style={{ width: 100 }} />
</Tooltip>
</span>
</div>
);

export const Trigger = TriggerTemplate.bind({});
Trigger.args = {
overlay,
};

const ControlTemplate: Story<TooltipProps> = (args) => {
const [visible, setVisible] = useState(false);
const show = () => setVisible(true);
const hide = () => setVisible(false);
const onVisibleChange = (resetVisible: boolean) => {
console.log(resetVisible);
};

const [visible2, setVisible2] = useState(false);
const show2 = () => setVisible2(true);
const hide2 = () => setVisible2(false);
const onVisibleChange2 = (resetVisible: boolean) => {
setVisible2(resetVisible);
};
return (
<>
<fieldset style={{ border: '1px solid var(--gray-2, #dfe4ee)', marginBottom: 100, padding: '50px 20px' }}>
<legend>Controlled</legend>
<div style={{ marginRight: 20 }}>
<Button onClick={show} style={{ marginRight: 10 }}>
Show Popover
</Button>
<Button onClick={hide} style={{ marginRight: 50 }}>
Hide Popover
</Button>
<Tooltip {...args} visible={visible} placement="top" onVisibleChange={onVisibleChange}>
<Input value="Show Popover Me!" />
</Tooltip>
</div>
</fieldset>
<fieldset style={{ border: '1px solid var(--gray-2, #dfe4ee)', padding: '50px 20px' }}>
<legend>Controlled by onVisibleChange</legend>
<div style={{ marginRight: 20 }}>
<Button onClick={show2} style={{ marginRight: 10 }}>
Show Popover
</Button>
<Button onClick={hide2} style={{ marginRight: 50 }}>
Hide Popover
</Button>
<Tooltip {...args} visible={visible2} placement="top" onVisibleChange={onVisibleChange2}>
<Input value="Show Popover Me!" />
</Tooltip>
</div>
</fieldset>
</>
);
};

export const Controlled = ControlTemplate.bind({});
Controlled.args = { overlay };

// const DefaultTemplate: Story<TooltipProps> = (args) => (
// <>
// <Tooltip {...args}>
// <Input value="Show Popover with allowed Arrow" style={{ width: 280 }} />
// </Tooltip>
// <span>|</span>
// <Tooltip {...args} allowArrow={false}>
// <Input value="Show Popover with rejected Arrow" style={{ width: 280 }} />
// </Tooltip>
// </>
// );
// export const DefaultVisible = DefaultTemplate.bind({});
// DefaultVisible.args = {
// defaultVisible: true,
// overlay,
// placement: 'bottom',
// };

const EnterableTemplate: Story<TooltipProps> = (args) => (
<>
<Tooltip {...args}>
<Input value="Popover supports mouse enter!" style={{ width: 280 }} />
</Tooltip>
<span>|</span>
<Tooltip {...args} enterable={false}>
<Input value="Popover does't support mouse enter!" style={{ width: 280 }} />
</Tooltip>
</>
);

export const Enterable = EnterableTemplate.bind({});
Enterable.args = {
overlay,
};

const MultiLineTemplate: Story<TooltipProps> = (args) => (
<div style={{ margin: '0px 10px' }}>
<Tooltip {...args} placement="right">
<span className="tooltipSpan">多行</span>
</Tooltip>
</div>
);
export const MultiLine = MultiLineTemplate.bind({});
MultiLine.args = {
title: '这是一个很长的描述。这是一个很长的描述。这是一个很长的描述。这是一个很长的描述。这是一个很长的描述。',
tooltipLink: { name: '点击这里', link: 'www.growingio.com' },
placement: 'right',
trigger: 'click',
};
2 changes: 2 additions & 0 deletions src/tooltip/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { TooltipProps } from './interface';
export * from './Tooltip';
20 changes: 20 additions & 0 deletions src/tooltip/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import { PopoverProps } from '../popover/interface';

export interface TooltipLink {
name?: string;
link: string;
}

export interface TooltipProps extends Omit<PopoverProps, 'content'> {
overlay?: React.ReactNode;
title?: React.ReactNode;

subPrefixCls?: string;

tooltipLink?: TooltipLink;
/**
被包裹的元素
*/
children: React.ReactElement;
}
30 changes: 30 additions & 0 deletions src/tooltip/style/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@import '../../stylesheet/variables/index.less';

@tooltip-prefix-cls: ~'@{component-prefix}-tooltip-new';
@arrow-prefix-cls: ~'@{component-prefix}-popover-new__arrow';
@link-prefix-cls: ~'@{component-prefix}-link';

.@{tooltip-prefix-cls} {
&__inner {
max-width: 500px;
padding: 8px 16px;
color: @gray-0;
font-size: 14px;
background-color: @gray-5;
border-radius: 4px;
}

.@{link-prefix-cls} {
color: @gray-0;
&:hover {
color: @gray-0;
}
}

.@{arrow-prefix-cls} {
background-color: @gray-5;
&::before {
background-color: @gray-5;
}
}
}
1 change: 1 addition & 0 deletions src/tooltip/style/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './index.less';

1 comment on commit da94622

@vercel
Copy link

@vercel vercel bot commented on da94622 Nov 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.