ぼざクリ タグ広場 https://hub.nizika.monster
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

84 lines
1.9 KiB

  1. import { useQueryClient } from '@tanstack/react-query'
  2. import { useMemo } from 'react'
  3. import { useNavigate } from 'react-router-dom'
  4. import { useOverlayStore } from '@/components/RouteBlockerOverlay'
  5. import { prefetchForURL } from '@/lib/prefetchers'
  6. import { cn } from '@/lib/utils'
  7. import type { AnchorHTMLAttributes, FC, MouseEvent, TouchEvent } from 'react'
  8. type Props = AnchorHTMLAttributes<HTMLAnchorElement> & {
  9. to: string
  10. replace?: boolean
  11. className?: string
  12. cancelOnError?: boolean }
  13. export default (({ to,
  14. replace,
  15. className,
  16. onMouseEnter,
  17. onTouchStart,
  18. onClick,
  19. cancelOnError = false,
  20. ...rest }: Props) => {
  21. const navigate = useNavigate ()
  22. const qc = useQueryClient ()
  23. const url = useMemo (() => (new URL (to, location.origin)).toString (), [to])
  24. const setOverlay = useOverlayStore (s => s.setActive)
  25. const doPrefetch = async () => {
  26. try
  27. {
  28. await prefetchForURL (qc, url)
  29. return true
  30. }
  31. catch (e)
  32. {
  33. console.error ('データ取得エラー', e)
  34. return false
  35. }
  36. }
  37. const handleMouseEnter = async (ev: MouseEvent<HTMLAnchorElement>) => {
  38. onMouseEnter?.(ev)
  39. doPrefetch ()
  40. }
  41. const handleTouchStart = async (ev: TouchEvent<HTMLAnchorElement>) => {
  42. onTouchStart?.(ev)
  43. doPrefetch ()
  44. }
  45. const handleClick = async (ev: MouseEvent<HTMLAnchorElement>) => {
  46. onClick?.(ev)
  47. if (ev.defaultPrevented
  48. || ev.metaKey
  49. || ev.ctrlKey
  50. || ev.shiftKey
  51. || ev.altKey)
  52. return
  53. ev.preventDefault ()
  54. setOverlay (true)
  55. const ok = await doPrefetch ()
  56. setOverlay (false)
  57. if (!(ok) && cancelOnError)
  58. return
  59. navigate (to, { replace })
  60. }
  61. return (
  62. <a href={to}
  63. onMouseEnter={handleMouseEnter}
  64. onTouchStart={handleTouchStart}
  65. onClick={handleClick}
  66. className={cn ('cursor-pointer', className)}
  67. {...rest}/>)
  68. }) satisfies FC<Props>