-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: glitch on Popover with an hover (#2282)
* fix: glitch on Popover with an hover * fix: wrong TS
- Loading branch information
1 parent
d786f1a
commit 72ad5a3
Showing
11 changed files
with
263 additions
and
186 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
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,31 @@ | ||
import React from 'react' | ||
|
||
import { UsePopover } from './usePopover' | ||
import * as S from './styles' | ||
|
||
const transformMap = { | ||
top: 'rotateZ(180deg)', | ||
right: 'rotateZ(-90deg)', | ||
bottom: 'rotateZ(360deg)', | ||
left: 'rotateZ(90deg)', | ||
} | ||
|
||
type ArrowProps = { | ||
store: UsePopover | ||
} | ||
|
||
export const Arrow = ({ store }: ArrowProps) => { | ||
const placement = store.useState('currentPlacement') | ||
|
||
const [parentPlacement] = placement.split('-') | ||
const transform = transformMap[parentPlacement as keyof typeof transformMap] | ||
|
||
return ( | ||
<S.Arrow store={store}> | ||
<S.ArrowItem $transform={transform} h={30} w={30} xmlns="http://www.w3.org/2000/svg"> | ||
<path d="M7 30L15 22L23 30H7Z" fill="currentColor" fillRule="nonzero" id="stroke" /> | ||
<path d="M8 30L15 23L22 30H8Z" fill="currentColor" fillRule="nonzero" /> | ||
</S.ArrowItem> | ||
</S.Arrow> | ||
) | ||
} |
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,46 @@ | ||
import React from 'react' | ||
import { Box } from '@welcome-ui/box' | ||
import { Button } from '@welcome-ui/button' | ||
import { CrossIcon } from '@welcome-ui/icons' | ||
|
||
import { UsePopover, UsePopoverHover } from './usePopover' | ||
import { Arrow } from './Arrow' | ||
import { PopoverProps } from './Popover' | ||
|
||
export interface ContentOptions { | ||
children: PopoverProps['children'] | ||
/** call a function when popover closed */ | ||
onClose?: () => void | ||
store: UsePopover | UsePopoverHover | ||
} | ||
|
||
export const Content = ({ children, onClose, store }: ContentOptions) => { | ||
const handleClose = () => { | ||
if (onClose) onClose() | ||
store?.hide() | ||
} | ||
|
||
const { withCloseButton } = store | ||
|
||
return ( | ||
<Box position="relative"> | ||
<Arrow store={store} /> | ||
{children as React.ReactElement} | ||
{withCloseButton && ( | ||
<Button | ||
flex="0 0 auto" | ||
ml="md" | ||
onClick={handleClose} | ||
position="absolute" | ||
right={1} | ||
shape="square" | ||
size="xs" | ||
top={1} | ||
variant="secondary" | ||
> | ||
<CrossIcon /> | ||
</Button> | ||
)} | ||
</Box> | ||
) | ||
} |
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,42 @@ | ||
import React from 'react' | ||
import { CreateWuiProps, forwardRef } from '@welcome-ui/system' | ||
import * as Ariakit from '@ariakit/react' | ||
|
||
import * as S from './styles' | ||
import { PopoverTrigger } from './Trigger' | ||
import { UsePopover } from './usePopover' | ||
import { Content } from './Content' | ||
|
||
export interface PopoverOptions extends Ariakit.PopoverProps { | ||
/** call a function when popover closed */ | ||
onClose?: () => void | ||
store: UsePopover | ||
} | ||
|
||
export type PopoverProps = CreateWuiProps<'div', PopoverOptions> | ||
|
||
const PopoverComponent = forwardRef<'div', PopoverProps>( | ||
({ children, onClose, store, ...rest }, ref) => { | ||
const { withCloseButton } = store | ||
|
||
return ( | ||
<S.Popover | ||
store={store} | ||
{...rest} | ||
$withCloseButton={withCloseButton} | ||
as={undefined} | ||
ref={ref} | ||
> | ||
<Content onClose={onClose} store={store}> | ||
{children} | ||
</Content> | ||
</S.Popover> | ||
) | ||
} | ||
) | ||
|
||
export const Popover = Object.assign(PopoverComponent, { | ||
Content: S.Content, | ||
Title: S.Title, | ||
Trigger: PopoverTrigger, | ||
}) |
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,42 @@ | ||
import React from 'react' | ||
import { CreateWuiProps, forwardRef } from '@welcome-ui/system' | ||
import * as Ariakit from '@ariakit/react' | ||
|
||
import * as S from './styles' | ||
import { PopoverHoverTrigger } from './Trigger' | ||
import { UsePopoverHover } from './usePopover' | ||
import { Content } from './Content' | ||
|
||
export interface PopoverHoverOptions extends Ariakit.HovercardProps { | ||
/** call a function when popover closed */ | ||
onClose?: () => void | ||
store: UsePopoverHover | ||
} | ||
|
||
export type PopoverHoverProps = CreateWuiProps<'div', PopoverHoverOptions> | ||
|
||
const PopoverHoverComponent = forwardRef<'div', PopoverHoverProps>( | ||
({ children, onClose, store, ...rest }, ref) => { | ||
const { withCloseButton } = store | ||
|
||
return ( | ||
<S.Popover | ||
as={Ariakit.Hovercard} | ||
store={store} | ||
{...rest} | ||
$withCloseButton={withCloseButton} | ||
ref={ref} | ||
> | ||
<Content onClose={onClose} store={store}> | ||
{children} | ||
</Content> | ||
</S.Popover> | ||
) | ||
} | ||
) | ||
|
||
export const PopoverHover = Object.assign(PopoverHoverComponent, { | ||
Content: S.Content, | ||
Title: S.Title, | ||
Trigger: PopoverHoverTrigger, | ||
}) |
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 |
---|---|---|
@@ -1,57 +1,21 @@ | ||
import { CreateWuiProps, forwardRef } from '@welcome-ui/system' | ||
import React from 'react' | ||
import { useIsomorphicLayoutEffect } from '@welcome-ui/utils' | ||
|
||
import { UsePopover } from './usePopover' | ||
import * as S from './styles' | ||
|
||
export type TriggerProps = CreateWuiProps<'button', { store: UsePopover }> | ||
export type PopoverTriggerProps = CreateWuiProps<'button', { store: UsePopover }> | ||
|
||
export const Trigger = forwardRef<'button', TriggerProps>(({ as, store, ...rest }, ref) => { | ||
const { triggerMethod } = store | ||
const isHoverMethod = triggerMethod === 'hover' | ||
const disclosureRef = store.useState('disclosureElement') | ||
const popoverRef = store.useState('popoverElement') | ||
|
||
const showPopover: () => void = () => { | ||
if (isHoverMethod) { | ||
// remove listeners on mouseenter | ||
disclosureRef?.removeEventListener('mouseenter', showPopover) | ||
popoverRef?.removeEventListener('mouseenter', showPopover) | ||
// add listeners on mouseleave | ||
disclosureRef?.addEventListener('mouseleave', hidePopover) | ||
popoverRef?.addEventListener('mouseleave', hidePopover) | ||
// show popover | ||
store.show() | ||
} | ||
} | ||
|
||
const hidePopover: () => void = () => { | ||
if (isHoverMethod) { | ||
// remove listeners on mouseleave | ||
disclosureRef?.removeEventListener('mouseleave', hidePopover) | ||
popoverRef?.removeEventListener('mouseleave', hidePopover) | ||
// add listeners on mouseenter | ||
disclosureRef?.addEventListener('mouseenter', showPopover) | ||
popoverRef?.addEventListener('mouseenter', showPopover) | ||
// hide popover | ||
store.hide() | ||
} | ||
export const PopoverTrigger = forwardRef<'button', PopoverTriggerProps>( | ||
({ as, store, ...rest }, ref) => { | ||
return <S.PopoverTrigger store={store} {...rest} forwardedAs={as} ref={ref} /> | ||
} | ||
) | ||
|
||
useIsomorphicLayoutEffect(() => { | ||
if (isHoverMethod && disclosureRef) { | ||
// add listeners on mount | ||
disclosureRef.addEventListener('mouseenter', showPopover) | ||
disclosureRef.addEventListener('mouseleave', hidePopover) | ||
return () => { | ||
// remove listeners on unmount | ||
disclosureRef.removeEventListener('mouseenter', showPopover) | ||
disclosureRef.removeEventListener('mouseleave', hidePopover) | ||
} | ||
} | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [disclosureRef]) | ||
export type PopoverHoverTriggerProps = CreateWuiProps<'button', { store: UsePopover }> | ||
|
||
return <S.PopoverTrigger store={store} {...rest} forwardedAs={as} ref={ref} /> | ||
}) | ||
export const PopoverHoverTrigger = forwardRef<'button', PopoverHoverTriggerProps>( | ||
({ as, store, ...rest }, ref) => { | ||
return <S.PopoverHoverTrigger store={store} {...rest} forwardedAs={as} ref={ref} /> | ||
} | ||
) |
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 |
---|---|---|
@@ -1,76 +1,3 @@ | ||
import React from 'react' | ||
import { Box } from '@welcome-ui/box' | ||
import { Button } from '@welcome-ui/button' | ||
import { CrossIcon } from '@welcome-ui/icons' | ||
import { CreateWuiProps, forwardRef } from '@welcome-ui/system' | ||
|
||
import * as S from './styles' | ||
import { Trigger } from './Trigger' | ||
import { UsePopover } from './usePopover' | ||
|
||
export interface PopoverOptions { | ||
/** call a function when popover closed */ | ||
onClose?: () => void | ||
store: UsePopover | ||
} | ||
|
||
export type PopoverProps = CreateWuiProps<'div', PopoverOptions> | ||
|
||
/* eslint-disable @typescript-eslint/no-unused-vars */ | ||
export const PopoverComponent = forwardRef<'div', PopoverProps>( | ||
({ children, onClose, store, ...rest }, ref) => { | ||
const closePopover = () => { | ||
if (onClose) onClose() | ||
store?.hide() | ||
} | ||
|
||
const placement = store.useState('currentPlacement') | ||
const { withCloseButton } = store | ||
// get the correct transform style for arrow | ||
const [parentPlacement] = placement.split('-') | ||
const transformMap: { [key: string]: string } = { | ||
top: 'rotateZ(180deg)', | ||
right: 'rotateZ(-90deg)', | ||
bottom: 'rotateZ(360deg)', | ||
left: 'rotateZ(90deg)', | ||
} | ||
const transform = transformMap[parentPlacement] | ||
|
||
return ( | ||
<S.Popover store={store} {...rest} $withCloseButton={withCloseButton} ref={ref}> | ||
<Box position="relative"> | ||
<S.Arrow store={store}> | ||
<S.ArrowItem $transform={transform} h={30} w={30} xmlns="http://www.w3.org/2000/svg"> | ||
<path d="M7 30L15 22L23 30H7Z" fill="currentColor" fillRule="nonzero" id="stroke" /> | ||
<path d="M8 30L15 23L22 30H8Z" fill="currentColor" fillRule="nonzero" /> | ||
</S.ArrowItem> | ||
</S.Arrow> | ||
{children} | ||
{withCloseButton && ( | ||
<Button | ||
flex="0 0 auto" | ||
ml="md" | ||
onClick={closePopover} | ||
position="absolute" | ||
right={1} | ||
shape="square" | ||
size="xs" | ||
top={1} | ||
variant="secondary" | ||
> | ||
<CrossIcon /> | ||
</Button> | ||
)} | ||
</Box> | ||
</S.Popover> | ||
) | ||
} | ||
) | ||
|
||
export const Popover = Object.assign(PopoverComponent, { | ||
Content: S.Content, | ||
Title: S.Title, | ||
Trigger: Trigger, | ||
}) | ||
|
||
export * from './Popover' | ||
export * from './PopoverHover' | ||
export * from './usePopover' |
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
Oops, something went wrong.