bc072570d2
Co-authored-by: Eric Bailey <git@esb.lol> Co-authored-by: Samuel Newman <mozzius@protonmail.com> Co-authored-by: hailey <me@haileyok.com>
119 lines
3.1 KiB
TypeScript
119 lines
3.1 KiB
TypeScript
import {Children, createContext, useContext, useMemo} from 'react'
|
|
import {View} from 'react-native'
|
|
import {Popover} from 'radix-ui'
|
|
|
|
import {atoms as a, flatten, select, useTheme} from '#/alf'
|
|
import {transparentifyColor} from '#/alf/util/colorGeneration'
|
|
import {
|
|
ARROW_SIZE,
|
|
BUBBLE_MAX_WIDTH,
|
|
MIN_EDGE_SPACE,
|
|
} from '#/components/Tooltip/const'
|
|
import {Text} from '#/components/Typography'
|
|
|
|
type TooltipContextType = {
|
|
position: 'top' | 'bottom'
|
|
onVisibleChange: (open: boolean) => void
|
|
}
|
|
|
|
const TooltipContext = createContext<TooltipContextType>({
|
|
position: 'bottom',
|
|
onVisibleChange: () => {},
|
|
})
|
|
|
|
export function Outer({
|
|
children,
|
|
position = 'bottom',
|
|
visible,
|
|
onVisibleChange,
|
|
}: {
|
|
children: React.ReactNode
|
|
position?: 'top' | 'bottom'
|
|
visible: boolean
|
|
onVisibleChange: (visible: boolean) => void
|
|
}) {
|
|
const ctx = useMemo(
|
|
() => ({position, onVisibleChange}),
|
|
[position, onVisibleChange],
|
|
)
|
|
return (
|
|
<Popover.Root open={visible} onOpenChange={onVisibleChange}>
|
|
<TooltipContext.Provider value={ctx}>{children}</TooltipContext.Provider>
|
|
</Popover.Root>
|
|
)
|
|
}
|
|
|
|
export function Target({children}: {children: React.ReactNode}) {
|
|
return (
|
|
<Popover.Trigger asChild>
|
|
<View collapsable={false}>{children}</View>
|
|
</Popover.Trigger>
|
|
)
|
|
}
|
|
|
|
export function Content({
|
|
children,
|
|
label,
|
|
}: {
|
|
children: React.ReactNode
|
|
label: string
|
|
}) {
|
|
const t = useTheme()
|
|
const {position, onVisibleChange} = useContext(TooltipContext)
|
|
return (
|
|
<Popover.Portal>
|
|
<Popover.Content
|
|
className="radix-popover-content"
|
|
aria-label={label}
|
|
side={position}
|
|
sideOffset={4}
|
|
collisionPadding={MIN_EDGE_SPACE}
|
|
onInteractOutside={() => onVisibleChange(false)}
|
|
style={flatten([
|
|
a.rounded_sm,
|
|
select(t.name, {
|
|
light: t.atoms.bg,
|
|
dark: t.atoms.bg_contrast_100,
|
|
dim: t.atoms.bg_contrast_100,
|
|
}),
|
|
{
|
|
minWidth: 'max-content',
|
|
boxShadow: select(t.name, {
|
|
light: `0 0 24px ${transparentifyColor(t.palette.black, 0.2)}`,
|
|
dark: `0 0 24px ${transparentifyColor(t.palette.black, 0.2)}`,
|
|
dim: `0 0 24px ${transparentifyColor(t.palette.black, 0.2)}`,
|
|
}),
|
|
},
|
|
])}>
|
|
<Popover.Arrow
|
|
width={ARROW_SIZE}
|
|
height={ARROW_SIZE / 2}
|
|
fill={select(t.name, {
|
|
light: t.atoms.bg.backgroundColor,
|
|
dark: t.atoms.bg_contrast_100.backgroundColor,
|
|
dim: t.atoms.bg_contrast_100.backgroundColor,
|
|
})}
|
|
/>
|
|
<View style={[a.px_md, a.py_sm, {maxWidth: BUBBLE_MAX_WIDTH}]}>
|
|
{children}
|
|
</View>
|
|
</Popover.Content>
|
|
</Popover.Portal>
|
|
)
|
|
}
|
|
|
|
export function TextBubble({children}: {children: React.ReactNode}) {
|
|
const c = Children.toArray(children)
|
|
return (
|
|
<Content label={c.join(' ')}>
|
|
<View style={[a.gap_xs]}>
|
|
{c.map((child, i) => (
|
|
<Text key={i} style={[a.text_sm, a.leading_snug]}>
|
|
{child}
|
|
</Text>
|
|
))}
|
|
</View>
|
|
</Content>
|
|
)
|
|
}
|