{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "use-view-transition",
  "title": "useViewTransition",
  "description": "Five named page-transition presets on the View Transitions API, with a reduced-motion cross-fade and a plain fallback.",
  "files": [
    {
      "path": "registry/miseui/hooks/use-view-transition.ts",
      "content": "import { useCallback, useEffect } from \"react\"\nimport { flushSync } from \"react-dom\"\n\n/**\n * Presets name the spatial story of a navigation, so the user keeps their\n * place: siblings slide along one axis, details scale up from the list, a\n * replaced screen fades through a neutral frame.\n */\nexport type ViewTransitionPreset = \"fade-through\" | \"shared-axis-x\" | \"shared-axis-y\" | \"scale-up\" | \"blur-in\"\n\nexport const STYLE_ELEMENT_ID = \"miseui-view-transitions\"\n\nconst DURATION_MS = 240\nconst EASE = \"cubic-bezier(0.2, 0, 0, 1)\"\nconst AXIS_OFFSET = \"24px\"\nconst SCALE_FROM = 0.96\nconst BLUR_PX = 12\n\nconst PRESET_CSS = `\n@keyframes miseui-vt-fade-out { to { opacity: 0 } }\n@keyframes miseui-vt-fade-in { from { opacity: 0 } }\n@keyframes miseui-vt-out-left { to { opacity: 0; transform: translateX(-${AXIS_OFFSET}) } }\n@keyframes miseui-vt-in-right { from { opacity: 0; transform: translateX(${AXIS_OFFSET}) } }\n@keyframes miseui-vt-out-up { to { opacity: 0; transform: translateY(-${AXIS_OFFSET}) } }\n@keyframes miseui-vt-in-down { from { opacity: 0; transform: translateY(${AXIS_OFFSET}) } }\n@keyframes miseui-vt-scale-in { from { opacity: 0; transform: scale(${SCALE_FROM}) } }\n@keyframes miseui-vt-blur-in { from { opacity: 0; filter: blur(${BLUR_PX}px) } }\n::view-transition-old(root), ::view-transition-new(root) { animation-duration: ${DURATION_MS}ms; animation-timing-function: ${EASE}; }\nhtml[data-transition=\"fade-through\"]::view-transition-old(root) { animation-name: miseui-vt-fade-out; animation-duration: ${DURATION_MS / 2}ms }\nhtml[data-transition=\"fade-through\"]::view-transition-new(root) { animation-name: miseui-vt-fade-in; animation-delay: ${DURATION_MS / 2}ms; animation-fill-mode: backwards }\nhtml[data-transition=\"shared-axis-x\"]::view-transition-old(root) { animation-name: miseui-vt-out-left }\nhtml[data-transition=\"shared-axis-x\"]::view-transition-new(root) { animation-name: miseui-vt-in-right }\nhtml[data-transition=\"shared-axis-y\"]::view-transition-old(root) { animation-name: miseui-vt-out-up }\nhtml[data-transition=\"shared-axis-y\"]::view-transition-new(root) { animation-name: miseui-vt-in-down }\nhtml[data-transition=\"scale-up\"]::view-transition-old(root) { animation-name: miseui-vt-fade-out }\nhtml[data-transition=\"scale-up\"]::view-transition-new(root) { animation-name: miseui-vt-scale-in }\nhtml[data-transition=\"blur-in\"]::view-transition-old(root) { animation-name: miseui-vt-fade-out }\nhtml[data-transition=\"blur-in\"]::view-transition-new(root) { animation-name: miseui-vt-blur-in }\n@media (prefers-reduced-motion: reduce) {\n  ::view-transition-old(root) { animation-name: miseui-vt-fade-out !important; transform: none !important }\n  ::view-transition-new(root) { animation-name: miseui-vt-fade-in !important; transform: none !important; filter: none !important }\n}\n`\n\ntype StartViewTransition = (update: () => void) => { finished: Promise<void> }\n\nfunction ensureStylesheet() {\n  if (typeof document === \"undefined\" || document.getElementById(STYLE_ELEMENT_ID)) return\n  const style = document.createElement(\"style\")\n  style.id = STYLE_ELEMENT_ID\n  style.textContent = PRESET_CSS\n  document.head.append(style)\n}\n\n/**\n * Returns `transition(update)`: runs `update` inside a View Transition when the\n * browser supports it, otherwise immediately. React state changes inside\n * `update` are flushed synchronously so the new frame is captured.\n */\nexport function useViewTransition(preset: ViewTransitionPreset) {\n  useEffect(ensureStylesheet, [])\n\n  return useCallback(\n    (update: () => void) => {\n      const doc = document as Document & { startViewTransition?: StartViewTransition }\n      const start = doc.startViewTransition\n      if (typeof start !== \"function\") {\n        update()\n        return\n      }\n      document.documentElement.dataset.transition = preset\n      const transition = start.call(doc, () => flushSync(update))\n      void transition.finished.finally(() => {\n        delete document.documentElement.dataset.transition\n      })\n    },\n    [preset],\n  )\n}\n",
      "type": "registry:hook"
    }
  ],
  "categories": [
    "transitions"
  ],
  "type": "registry:hook"
}