|
- import { useQueryClient } from '@tanstack/react-query'
- import { useMemo } from 'react'
- import { useNavigate } from 'react-router-dom'
-
- import { useOverlayStore } from '@/components/RouteBlockerOverlay'
- import { prefetchForURL } from '@/lib/prefetchers'
- import { cn } from '@/lib/utils'
-
- import type { AnchorHTMLAttributes, FC, MouseEvent, TouchEvent } from 'react'
-
- type Props = AnchorHTMLAttributes<HTMLAnchorElement> & {
- to: string
- replace?: boolean
- className?: string
- cancelOnError?: boolean }
-
-
- export default (({ to,
- replace,
- className,
- onMouseEnter,
- onTouchStart,
- onClick,
- cancelOnError = false,
- ...rest }: Props) => {
- const navigate = useNavigate ()
- const qc = useQueryClient ()
- const url = useMemo (() => (new URL (to, location.origin)).toString (), [to])
- const setOverlay = useOverlayStore (s => s.setActive)
-
- const doPrefetch = async () => {
- try
- {
- await prefetchForURL (qc, url)
- return true
- }
- catch (e)
- {
- console.error ('データ取得エラー', e)
- return false
- }
- }
-
- const handleMouseEnter = async (ev: MouseEvent<HTMLAnchorElement>) => {
- onMouseEnter?.(ev)
- doPrefetch ()
- }
-
- const handleTouchStart = async (ev: TouchEvent<HTMLAnchorElement>) => {
- onTouchStart?.(ev)
- doPrefetch ()
- }
-
- const handleClick = async (ev: MouseEvent<HTMLAnchorElement>) => {
- onClick?.(ev)
-
- if (ev.defaultPrevented
- || ev.metaKey
- || ev.ctrlKey
- || ev.shiftKey
- || ev.altKey)
- return
-
- ev.preventDefault ()
-
- setOverlay (true)
- const ok = await doPrefetch ()
- setOverlay (false)
-
- if (!(ok) && cancelOnError)
- return
-
- navigate (to, { replace })
- }
-
- return (
- <a href={to}
- onMouseEnter={handleMouseEnter}
- onTouchStart={handleTouchStart}
- onClick={handleClick}
- className={cn ('cursor-pointer', className)}
- {...rest}/>)
- }) satisfies FC<Props>
|