{"id":22220280,"url":"https://github.com/funtechinc/mekuri","last_synced_at":"2025-07-27T15:32:50.737Z","repository":{"id":175763516,"uuid":"654012072","full_name":"FunTechInc/mekuri","owner":"FunTechInc","description":"📕 Page transition animation for React","archived":false,"fork":false,"pushed_at":"2024-05-24T08:04:32.000Z","size":25881,"stargazers_count":60,"open_issues_count":2,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-10-15T11:33:03.769Z","etag":null,"topics":["hooks","nextjs","pagetransition","react","remix","remix-run"],"latest_commit_sha":null,"homepage":"https://mekuri.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FunTechInc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-15T07:57:32.000Z","updated_at":"2024-09-28T05:37:41.000Z","dependencies_parsed_at":"2024-01-17T06:46:08.026Z","dependency_job_id":"7a27e193-35cd-4020-9693-8016620a64e4","html_url":"https://github.com/FunTechInc/mekuri","commit_stats":{"total_commits":94,"total_committers":2,"mean_commits":47.0,"dds":"0.021276595744680882","last_synced_commit":"7ee01c9998f05f02f0053a7b11e1a63b93428498"},"previous_names":["funtechinc/mekuri"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FunTechInc%2Fmekuri","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FunTechInc%2Fmekuri/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FunTechInc%2Fmekuri/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FunTechInc%2Fmekuri/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FunTechInc","download_url":"https://codeload.github.com/FunTechInc/mekuri/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227817190,"owners_count":17824199,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hooks","nextjs","pagetransition","react","remix","remix-run"],"created_at":"2024-12-02T23:07:49.288Z","updated_at":"2024-12-02T23:07:50.136Z","avatar_url":"https://github.com/FunTechInc.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mekuri\n\n![mekuri](public/app-head.jpg)\n\n`mekuri` is React package for page transition animations with `wait` and `sync` modes, supporting `popstate` and `scroll restoration`.\n\nCustomize animations per component with the `useMekuri` hook and use with libraries like `GSAP`. It integrates with Next.js and Remix; can also be integrated with Next.js `App Router`, but for stable operation it is recommended to use Pages Router rather than App Router. [Next.js Pages Router demo](https://github.com/FunTechInc/mekuri-demo-pages)\n\n```bash\n$ npm i @funtech-inc/mekuri\n```\n\n\u003cp align=\"middle\"\u003e\n  \u003ca href=\"https://mekuri.vercel.app/\"\u003e\u003cimg src=\"public/mekuri-desktop.gif\" width=\"400\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://mekuri.vercel.app/\"\u003e\u003cimg src=\"public/mekuri-mobile.gif\" width=\"400\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n### Features 📕\n\n-  `wait` and `sync` modes\n-  `scrollRestoration` in popstate.\n-  When in `sync` mode, routing is possible in `wait` mode when in popstate.\n-  Supports frameworks such as `Next.js` and `Remix`. Can also integrate with `Next.js App Router`.\n-  `useMekuri` hook for each component.\n-  Integration into smooth scrolling libraries such as [lenis](https://github.com/darkroomengineering/lenis) is also possible.\n\n# Usage\n\n```tsx\nexport default function App({ Component, pageProps }: AppProps) {\n   const { pathname } = useRouter();\n   return (\n      \u003cMekuriContext trigger={pathname}\u003e\n         \u003cSomeAnimationComponent\u003e\n            \u003cMekuri\u003e\n               \u003cComponent\n                  key={`${pathname + performance.now()}`}\n                  {...pageProps}\n               /\u003e\n            \u003c/Mekuri\u003e\n         \u003c/SomeAnimationComponent\u003e\n      \u003c/MekuriContext\u003e\n   );\n}\n```\n\n## MekuriContext\n\nThe context to wrap the whole thing in. Set the `trigger` to a `state` to switch content. You can use `pathname` if you want to use it as a page transition.\n\n## Mekuri\n\nUnmounting of children can be delayed by wrapping them in a `Mekuri` component.\n\n## useMekuri\n\nHooks that can be called within `MekuriContext`. Callbacks include `onOnce`, `onLeave`, `onEnter`, `onAfterSyncEnter`, `onEveryLeave` and `onEveryEnter`.\n\n```tsx\nconst SomeAnimationComponent = ({\n   children,\n}: {\n   children: React.ReactNode;\n}) =\u003e {\n   const ref = useRef\u003cHTMLDivElement\u003e(null);\n   useMekuri({\n      onLeave: (props: MekuriCallbackProps) =\u003e {\n         gsap.to(ref.current, {\n            opacity: 0,\n         });\n      },\n      onEnter: (props: MekuriCallbackProps) =\u003e {\n         gsap.to(ref.current, {\n            opacity: 1,\n         });\n      },\n   });\n   return \u003cdiv ref={ref}\u003e{children}\u003c/div\u003e;\n};\n```\n\nEach callback has `MekuriCallbackProps` as an argument.\n\n```ts\ntype MekuriCallbackProps = {\n   prevTrigger: Trigger | null | undefined;\n   currentTrigger: Trigger | null | undefined;\n   nextTrigger: Trigger | null | undefined;\n   /** Returns the Y position before leaving the page */\n   yPosBeforeLeave: number;\n   /** If # is attached to the URL when transitioning, the distance to that ID is returned. */\n   getHashPos: ReturnHashPosReturn;\n   /** intersectionObserver (\n      targetRef: React.RefObject\u003cHTMLElement\u003e,\n      callback: (isIntersecting: boolean) =\u003e void\n   ) =\u003e void\n * */\n   intersectionObserver: HandleIntersectionObserver;\n   /** mekuri renders based on timeout. Therefore, there are cases where the next component is rendered before the chunked Stylesheet updated by Next.js is loaded. `onStylesheetLoad` ensures that functions are executed after the Stylesheet is loaded. `onStylesheetLoad` ensures that the function is executed after the Stylesheet is loaded */\n   onStylesheetLoad: (callback: () =\u003e void) =\u003e void;\n   /**  Whether the transition is by popstate */\n   isPopstate: boolean;\n};\n```\n\n## useMekuriDuration\n\nIt is possible to receive the `duration` set in the `MekuriContext`.\n\n```tsx\nconst { millisecond, second } = useMekuriDuration();\n```\n\n## useMekuriTrigger\n\n`phase` : `enter` | `leave` , Specify the phase to subscribe to trigger updates\n\n```tsx\nconst trigger = useMekuriTrigger(phase);\n```\n\n# integrate with Next.js App Router\n\nSince the key cannot be obtained by changing children during app router page transition, it is necessary to import `LayoutRouterContext` from next and pass the context to `MekuriFreezer`.\n\nFor more information on `App Router` page transition animations, see the following issue.\n[See this issue](https://github.com/vercel/next.js/issues/49279#issuecomment-1675782002)\n\n## MekuriFreezer\n\n```tsx\n\"use client\";\nimport { MekuriFreezer, Mekuri } from \"@/packages/mekuri/src\";\n// import { LayoutRouterContext } from \"next/dist/shared/lib/app-router-context\";\n// Next.js ^13.5.2\nimport { LayoutRouterContext } from \"next/dist/shared/lib/app-router-context.shared-runtime\";\nimport { usePathname } from \"next/navigation\";\n\nexport const PageTransitionLayout = ({\n   children,\n}: {\n   children: React.ReactNode;\n}) =\u003e {\n   const pathname = usePathname();\n   return (\n      \u003cMekuri\u003e\n         \u003cMekuriFreezer\n            key={`${pathname + performance.now()}`}\n            routerContext={LayoutRouterContext}\u003e\n            {children}\n         \u003c/MekuriFreezer\u003e\n      \u003c/Mekuri\u003e\n   );\n};\n```\n\n# integrate with Remix\n\n```tsx\nexport default function App() {\n   const location = useLocation();\n   const outlet = useOutlet();\n   return (\n      \u003chtml lang=\"en\" className=\"h-full\"\u003e\n         \u003chead\u003e\u003c/head\u003e\n         \u003cbody className=\"h-full\"\u003e\n            \u003cMekuriContext trigger={location.pathname}\u003e\n               \u003cSomeAnimationComponent\u003e\n                  \u003cMekuri\u003e\n                     \u003cdiv key={location.pathname}\u003e{outlet}\u003c/div\u003e\n                  \u003c/Mekuri\u003e\n               \u003c/SomeAnimationComponent\u003e\n            \u003c/MekuriContext\u003e\n            \u003cScrollRestoration /\u003e\n            \u003cScripts /\u003e\n            \u003cLiveReload /\u003e\n         \u003c/body\u003e\n      \u003c/html\u003e\n   );\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffuntechinc%2Fmekuri","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffuntechinc%2Fmekuri","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffuntechinc%2Fmekuri/lists"}