webapp/src/components/_shared/Popup/Popup.tsx

66 lines
1.8 KiB
TypeScript
Raw Normal View History

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'
2022-11-20 21:25:59 +00:00
import { useOutsideClickHandler } from '../../../utils/useOutsideClickHandler'
2022-10-25 15:36:32 +00:00
import styles from './Popup.module.scss'
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
onVisibilityChange?: (isVisible: boolean) => void
horizontalAnchor?: HorizontalAnchor
2024-05-06 22:01:20 +00:00
variant?: 'tiny'
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)
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
})
const containerRef: { current: HTMLElement } = { current: null }
const closePopup = () => setIsVisible(false)
useOutsideClickHandler({
containerRef,
predicate: () => isVisible(),
handler: () => closePopup(),
2022-10-17 20:53:04 +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 (
<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()}>
<div
2023-02-06 21:35:08 +00:00
class={clsx(styles.popup, props.popupCssClass, {
[styles.horizontalAnchorCenter]: horizontalAnchor === 'center',
2022-12-17 03:27:00 +00:00
[styles.horizontalAnchorRight]: horizontalAnchor === 'right',
[styles.tiny]: props.variant === 'tiny',
})}
>
{props.children}
</div>
2022-10-25 15:36:32 +00:00
</Show>
</span>
2022-10-17 20:53:04 +00:00
)
}