/**
* A link's card, shown on hover over its chip or its row: read only, in the
* package's one elevated box. A screen that cannot hover draws no preview, and
* a tap opens the link (Miky, WID-2: "there's no hover on touch").
*/
import { useSyncExternalStore, type ReactNode } from 'react'
import { LinkCard } from './LinkCard'
import type { Linked } from './linked'
import { MenuPanel } from './Menu'
import { PreviewCard } from './PreviewCard'
const HOVER = '(hover: hover)'
function subscribe(onChange: () => void) {
if (typeof window === 'undefined' || !window.matchMedia) return () => {}
const query = window.matchMedia(HOVER)
query.addEventListener('change', onChange)
return () => query.removeEventListener('change', onChange)
}
/** Whether this screen can hover. Without `matchMedia` (a test, a server) it is taken to. */
export function useCanHover(): boolean {
return useSyncExternalStore(
subscribe,
() => (typeof window === 'undefined' || !window.matchMedia ? true : window.matchMedia(HOVER).matches),
() => true,
)
}
export interface LinkPreviewProps {
linked: Linked
/** The trigger fills its column, as a row does; a chip is inline. */
block?: boolean
children: ReactNode
}
export function LinkPreview({ linked, block = false, children }: LinkPreviewProps) {
const canHover = useCanHover()
if (!canHover) return <>{children}>
// A row fills its column; PreviewCard's own trigger is inline and would shrink it to its words.
return (
} wrapperClassName={block ? 'grid w-full min-w-0 grid-cols-[minmax(0,1fr)]' : 'max-w-full'}>
{children}
)
}
/** The preview drawn open, for a still picture of it: the same box PreviewCard draws. */
export function LinkPreviewOpen({ linked }: { linked: Linked }) {
return (
)
}