2022-10-25 15:36:32 +00:00
|
|
|
import { clsx } from 'clsx'
|
2024-02-04 11:25:21 +00:00
|
|
|
import { JSX, Show, createEffect, createSignal } from 'solid-js'
|
2023-11-14 15:10:00 +00:00
|
|
|
|
2022-11-20 21:25:59 +00:00
|
|
|
import { useOutsideClickHandler } from '../../../utils/useOutsideClickHandler'
|
2022-10-25 15:36:32 +00:00
|
|
|
|
2023-11-14 15:10:00 +00:00
|
|
|
import styles from './Popup.module.scss'
|
|
|
|
|
2022-10-28 09:10:14 +00:00
|
|
|
type HorizontalAnchor = 'center' | 'right'
|
|
|
|
|
2022-10-25 15:36:32 +00:00
|
|
|
export type PopupProps = {
|
|
|
|
containerCssClass?: string
|
2023-02-06 21:35:08 +00:00
|
|
|
popupCssClass?: string
|
2022-10-25 15:36:32 +00:00
|
|
|
trigger: JSX.Element
|
|
|
|
children: JSX.Element
|
2023-05-17 04:04:38 +00:00
|
|
|
onVisibilityChange?: (isVisible: boolean) => void
|
2022-10-28 09:10:14 +00:00
|
|
|
horizontalAnchor?: HorizontalAnchor
|
2024-05-06 22:01:20 +00:00
|
|
|
variant?: 'tiny'
|
2024-01-15 18:41:45 +00:00
|
|
|
closePopup?: boolean
|
2022-10-17 20:53:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export const Popup = (props: PopupProps) => {
|
2022-10-25 15:36:32 +00:00
|
|
|
const [isVisible, setIsVisible] = createSignal(false)
|
2022-10-28 09:10:14 +00:00
|
|
|
const horizontalAnchor: HorizontalAnchor = props.horizontalAnchor || 'center'
|
2022-10-17 20:53:04 +00:00
|
|
|
|
2022-10-25 15:36:32 +00:00
|
|
|
createEffect(() => {
|
|
|
|
if (props.onVisibilityChange) {
|
|
|
|
props.onVisibilityChange(isVisible())
|
|
|
|
}
|
2022-10-17 20:53:04 +00:00
|
|
|
})
|
|
|
|
|
2022-11-01 22:05:08 +00:00
|
|
|
const containerRef: { current: HTMLElement } = { current: null }
|
2024-01-15 18:41:45 +00:00
|
|
|
const closePopup = () => setIsVisible(false)
|
2024-01-15 13:22:43 +00:00
|
|
|
|
2022-11-01 22:05:08 +00:00
|
|
|
useOutsideClickHandler({
|
|
|
|
containerRef,
|
|
|
|
predicate: () => isVisible(),
|
2024-01-15 13:22:43 +00:00
|
|
|
handler: () => closePopup(),
|
2022-10-17 20:53:04 +00:00
|
|
|
})
|
2024-01-15 13:22:43 +00:00
|
|
|
|
2024-01-15 18:41:45 +00:00
|
|
|
createEffect(() => {
|
|
|
|
if (props.closePopup) {
|
|
|
|
closePopup()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-10-25 15:36:32 +00:00
|
|
|
const toggle = () => setIsVisible((oldVisible) => !oldVisible)
|
2022-10-17 20:53:04 +00:00
|
|
|
return (
|
2022-11-01 22:05:08 +00:00
|
|
|
<span class={clsx(styles.container, props.containerCssClass)} ref={(el) => (containerRef.current = el)}>
|
2023-04-17 10:31:20 +00:00
|
|
|
<span class={styles.trigger} onClick={toggle}>
|
|
|
|
{props.trigger}
|
|
|
|
</span>
|
2022-10-25 15:36:32 +00:00
|
|
|
<Show when={isVisible()}>
|
2022-10-28 09:10:14 +00:00
|
|
|
<div
|
2023-02-06 21:35:08 +00:00
|
|
|
class={clsx(styles.popup, props.popupCssClass, {
|
2022-10-28 09:10:14 +00:00
|
|
|
[styles.horizontalAnchorCenter]: horizontalAnchor === 'center',
|
2022-12-17 03:27:00 +00:00
|
|
|
[styles.horizontalAnchorRight]: horizontalAnchor === 'right',
|
2023-11-14 15:10:00 +00:00
|
|
|
[styles.tiny]: props.variant === 'tiny',
|
2022-10-28 09:10:14 +00:00
|
|
|
})}
|
|
|
|
>
|
|
|
|
{props.children}
|
|
|
|
</div>
|
2022-10-25 15:36:32 +00:00
|
|
|
</Show>
|
|
|
|
</span>
|
2022-10-17 20:53:04 +00:00
|
|
|
)
|
|
|
|
}
|