-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: remove close text on modals and add tooltip component (#1146)
- Loading branch information
Showing
5 changed files
with
217 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import type { CSSProperties, PropsWithChildren, ReactNode } from 'react' | ||
import { useState } from 'react' | ||
import { tx } from '@twind/core' | ||
|
||
type UseHoverStateProps = { closingDelay: number } | ||
const defaultUseHoverStateProps: UseHoverStateProps = { | ||
closingDelay: 200 | ||
} | ||
|
||
// TODO move this outside of this component and also replace inside the menu component | ||
const useHoverState = (props: Partial<UseHoverStateProps> | undefined = undefined) => { | ||
const { closingDelay } = { ...defaultUseHoverStateProps, ...props } | ||
|
||
const [open, setOpen] = useState(false) | ||
const [timer, setTimer] = useState<NodeJS.Timeout>() | ||
|
||
const onMouseEnter = () => { | ||
clearTimeout(timer) | ||
setOpen(true) | ||
} | ||
|
||
const onMouseLeave = () => { | ||
setTimer(setTimeout(() => { | ||
setOpen(false) | ||
}, closingDelay)) | ||
} | ||
|
||
return { | ||
open, setOpen, handlers: { onMouseEnter, onMouseLeave } | ||
} | ||
} | ||
|
||
type Position = 'top' | 'bottom' | 'left' | 'right' | ||
|
||
export type TooltipProps = PropsWithChildren<{ | ||
tooltip: string | ReactNode, | ||
/** | ||
* Number of milliseconds until the tooltip appears | ||
* | ||
* defaults to 1000ms | ||
*/ | ||
animationDelay?: number, | ||
/** | ||
* Class names of additional styling properties for the tooltip | ||
*/ | ||
tooltipClassName?: string, | ||
/** | ||
* Class names of additional styling properties for the container from which the tooltip will be created | ||
*/ | ||
containerClassName?: string, | ||
position?: Position, | ||
zIndex?: number, | ||
offset?: number | ||
}> | ||
|
||
/** | ||
* A Component for showing a tooltip when hovering over Content | ||
* @param tooltip The tooltip to show can be a text or any ReactNode | ||
* @param children The Content for which the tooltip should be created | ||
* @param animationDelay The delay before the tooltip appears | ||
* @param tooltipClassName Additional ClassNames for the Container of the tooltip | ||
* @param containerClassName Additional ClassNames for the Container holding the content | ||
* @param position The direction of the tooltip relative to the Container | ||
* @param zIndex The z Index of the tooltip (you may require this when stacking modals) | ||
* @param offset The distance to the parent container in pixels | ||
* @constructor | ||
*/ | ||
export const Tooltip = ({ | ||
tooltip, | ||
children, | ||
animationDelay = 650, | ||
tooltipClassName = '', | ||
containerClassName = '', | ||
position = 'bottom', | ||
zIndex = 10, | ||
offset = 6, | ||
}: TooltipProps) => { | ||
const { open, handlers } = useHoverState() | ||
|
||
const positionClasses = { | ||
top: `bottom-full left-1/2 -translate-x-1/2 mb-[${offset}px]`, | ||
bottom: `top-full left-1/2 -translate-x-1/2 mt-[${offset}px]`, | ||
left: `right-full top-1/2 -translate-y-1/2 mr-[${offset}px]`, | ||
right: `left-full top-1/2 -translate-y-1/2 ml-[${offset}px]` | ||
} | ||
|
||
const backgroundColor = 'gray-100' | ||
const borderColor = 'gray-600' | ||
|
||
const triangleSize = 6 | ||
const triangleClasses = { | ||
top: `top-full left-1/2 -translate-x-1/2 border-t-${borderColor} border-l-transparent border-r-transparent`, | ||
bottom: `bottom-full left-1/2 -translate-x-1/2 border-b-${borderColor} border-l-transparent border-r-transparent`, | ||
left: `left-full top-1/2 -translate-y-1/2 border-l-${borderColor} border-t-transparent border-b-transparent`, | ||
right: `right-full top-1/2 -translate-y-1/2 border-r-${borderColor} border-t-transparent border-b-transparent` | ||
} | ||
|
||
const triangleStyle: Record<Position, CSSProperties> = { | ||
top: { borderWidth: `${triangleSize}px ${triangleSize}px 0 ${triangleSize}px` }, | ||
bottom: { borderWidth: `0 ${triangleSize}px ${triangleSize}px ${triangleSize}px` }, | ||
left: { borderWidth: `${triangleSize}px 0 ${triangleSize}px ${triangleSize}px` }, | ||
right: { borderWidth: `${triangleSize}px ${triangleSize}px ${triangleSize}px 0` } | ||
} | ||
|
||
return ( | ||
<div | ||
className={tx(`relative inline-block`, containerClassName)} | ||
{...handlers} | ||
> | ||
{children} | ||
{open && ( | ||
<div | ||
className={tx(`opacity-0 absolute z-[${zIndex}] text-black text-xs font-semibold text-[${borderColor}] px-2 py-1 rounded whitespace-nowrap border-2 border-${borderColor} | ||
animate-tooltip-fade-in animation-delay-${animationDelay} shadow-lg bg-${backgroundColor}`, positionClasses[position], tooltipClassName)} | ||
> | ||
{tooltip} | ||
<div className={tx(`absolute w-0 h-0 z-[${zIndex}]`, triangleClasses[position])} style={triangleStyle[position]}/> | ||
</div> | ||
)} | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import type { Meta, StoryObj } from '@storybook/react' | ||
import { tw } from '@twind/core' | ||
import type { TooltipProps } from '../../../components/Tooltip' | ||
import { Tooltip } from '../../../components/Tooltip' | ||
|
||
type TooltipExampleProps = Omit<TooltipProps, 'children' | 'tooltip'> & { tooltipText: string } | ||
|
||
const TooltipExample = ({ tooltipText, ...props } : TooltipExampleProps) => { | ||
return ( | ||
<Tooltip tooltip={tooltipText} {...props}><span className={tw('bg-hw-primary-400 text-white px-2 py-1 rounded-lg')}>Hover over me</span></Tooltip> | ||
) | ||
} | ||
|
||
const meta = { | ||
title: 'Other/Tooltip', | ||
component: TooltipExample, | ||
} satisfies Meta<typeof TooltipExample> | ||
|
||
export default meta | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const TooltipExampleStory: Story = { | ||
args: { | ||
tooltipText: 'Tooltip', | ||
animationDelay: 700, | ||
position: 'bottom', | ||
zIndex: 10, | ||
offset: 6, | ||
containerClassName: '', | ||
tooltipClassName: '' | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import type { Meta, StoryObj } from '@storybook/react' | ||
import { tw } from '@twind/core' | ||
import type { TooltipProps } from '../../../components/Tooltip' | ||
import { Tooltip } from '../../../components/Tooltip' | ||
|
||
type TooltipStackExampleProps = Omit<TooltipProps, 'children' | 'tooltip'> | ||
|
||
const TooltipStackExample = ({ ...props }: TooltipStackExampleProps) => { | ||
return ( | ||
<Tooltip tooltip={( | ||
<Tooltip zIndex={11} tooltip={( | ||
<span>Try to hover <Tooltip tooltip="Great right?" zIndex={12}> | ||
<span className={tw('font-bold underline')}>here</span> | ||
</Tooltip></span> | ||
)}>This is a Text on which you can hover to show | ||
another Tooltip | ||
</Tooltip> | ||
)} {...props}> | ||
<span className={tw('bg-hw-primary-400 text-white px-2 py-1 rounded-lg')}>Hover over me</span> | ||
</Tooltip> | ||
) | ||
} | ||
|
||
const meta = { | ||
title: 'Other/Tooltip', | ||
component: TooltipStackExample, | ||
} satisfies Meta<typeof TooltipStackExample> | ||
|
||
export default meta | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const TooltipStackExampleStory: Story = { | ||
args: { | ||
animationDelay: 700, | ||
position: 'right', | ||
zIndex: 10, | ||
offset: 6, | ||
containerClassName: '', | ||
tooltipClassName: '' | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters