{"id":19936304,"url":"https://github.com/toss/use-funnel","last_synced_at":"2025-05-14T19:10:24.661Z","repository":{"id":253731544,"uuid":"833559874","full_name":"toss/use-funnel","owner":"toss","description":"A powerful and safe step-by-step state management library at React","archived":false,"fork":false,"pushed_at":"2025-05-12T05:50:09.000Z","size":11969,"stargazers_count":384,"open_issues_count":8,"forks_count":52,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-12T06:36:32.953Z","etag":null,"topics":["funnel","react","wizard-steps"],"latest_commit_sha":null,"homepage":"https://use-funnel.slash.page","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/toss.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-07-25T09:41:54.000Z","updated_at":"2025-05-12T05:50:12.000Z","dependencies_parsed_at":"2024-08-27T08:53:54.597Z","dependency_job_id":"b15cfe1a-e6b6-4172-a3b5-6aedcf16a6e6","html_url":"https://github.com/toss/use-funnel","commit_stats":{"total_commits":59,"total_committers":15,"mean_commits":3.933333333333333,"dds":0.4067796610169492,"last_synced_commit":"0367d4ac0148e06ad713df62ecfdf5753b512cd4"},"previous_names":["toss/use-funnel"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toss%2Fuse-funnel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toss%2Fuse-funnel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toss%2Fuse-funnel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toss%2Fuse-funnel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/toss","download_url":"https://codeload.github.com/toss/use-funnel/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254209859,"owners_count":22032897,"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":["funnel","react","wizard-steps"],"created_at":"2024-11-12T23:25:07.188Z","updated_at":"2025-05-14T19:10:23.269Z","avatar_url":"https://github.com/toss.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# @use-funnel\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://use-funnel.slash.page\" title=\"@use-funnel - A powerful and safe step-by-step state management library\"\u003e\n    \u003cimg src=\"./docs/public/logo.png\" width=\"200\" /\u003e\n    \u003ch2 align=\"center\"\u003e@use-funnel\u003c/h2\u003e\n  \u003c/a\u003e\n  \u003cp style=\"font-size:18px;\"\u003eA powerful and safe step-by-step state management library\u003c/p\u003e\n\u003c/div\u003e\n\n[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/toss/use-funnel/blob/main/LICENSE) [![Discord Badge](https://discord.com/api/guilds/1281071127052943361/widget.png?style=shield)](https://discord.gg/vGXbVjP2nY)\n\n`@use-funnel` is a [React Hook](https://react.dev/reference/rules/rules-of-hooks) that helps you easily implement complex UI flows.\n\n## Core Concepts\n\n### Strong Type Support\n\nBy comparing the type of the current step with the next, you can ensure that only the required states are managed safely.\n\n### State Management by History\n\nManage states based on history, making it easy to handle backward and forward navigation.\n\n### Various Router Support\n\nSupports browser history, react-router, next.js, @react-navigation/native, and more.\n\n## Example\n\nhttps://github.com/user-attachments/assets/8300d4ed-ab02-436e-a5a6-99c8d732e32f\n\n```tsx\nimport { useFunnel } from '@use-funnel/browser';\n\nexport function App() {\n  const funnel = useFunnel\u003c{\n    SelectJob: { jobType?: 'STUDENT' | 'EMPLOYEE' };\n    SelectSchool: { jobType: 'STUDENT'; school?: string };\n    SelectEmployee: { jobType: 'EMPLOYEE'; company?: string };\n    EnterJoinDate: { jobType: 'STUDENT'; school: string } | { jobType: 'EMPLOYEE'; company: string };\n    Confirm: ({ jobType: 'STUDENT'; school: string } | { jobType: 'EMPLOYEE'; company: string }) \u0026 { joinDate: string };\n  }\u003e({\n    id: 'hello-world',\n    initial: {\n      step: 'SelectJob',\n      context: {},\n    },\n  });\n\n  return (\n    \u003cfunnel.Render\n      SelectJob={funnel.Render.with({\n        events: {\n          selectSchool: (_, { history }) =\u003e history.push('SelectSchool', { jobType: 'STUDENT' }),\n          selectEmployee: (_, { history }) =\u003e history.push('SelectEmployee', { jobType: 'EMPLOYEE' }),\n        },\n        render({ dispatch }) {\n          return (\n            \u003cSelectJob\n              onSelectSchool={() =\u003e dispatch('selectSchool')}\n              onSelectEmployee={() =\u003e dispatch('selectEmployee')}\n            /\u003e\n          );\n        },\n      })}\n      SelectSchool={({ history }) =\u003e (\n        \u003cSelectSchool\n          onNext={(school) =\u003e\n            history.push('EnterJoinDate', (prev) =\u003e ({\n              ...prev,\n              school,\n            }))\n          }\n        /\u003e\n      )}\n      SelectEmployee={({ history }) =\u003e (\n        \u003cSelectEmployee\n          onNext={(company) =\u003e\n            history.push('EnterJoinDate', (prev) =\u003e ({\n              ...prev,\n              company,\n            }))\n          }\n        /\u003e\n      )}\n      EnterJoinDate={funnel.Render.overlay({\n        render({ history, close }) {\n          return (\n            \u003cEnterJoinDateBottomSheet\n              onNext={(joinDate) =\u003e history.push('Confirm', { joinDate })}\n              onClose={() =\u003e close()}\n            /\u003e\n          );\n        },\n      })}\n      Confirm={({ context }) =\u003e\n        context.jobType === 'STUDENT' ? (\n          \u003cConfirmStudent school={context.school} joinDate={context.joinDate} /\u003e\n        ) : (\n          \u003cConfirmEmployee company={context.company} joinDate={context.joinDate} /\u003e\n        )\n      }\n    /\u003e\n  );\n}\n\ndeclare function SelectJob(props: { onSelectSchool(): void; onSelectEmployee(): void }): JSX.Element;\ndeclare function SelectSchool(props: { onNext(school: string): void }): JSX.Element;\ndeclare function SelectEmployee(props: { onNext(company: string): void }): JSX.Element;\ndeclare function EnterJoinDateBottomSheet(props: { onNext(joinDate: string): void; onClose(): void }): JSX.Element;\ndeclare function ConfirmStudent(props: { school: string; joinDate: string }): JSX.Element;\ndeclare function ConfirmEmployee(props: { company: string; joinDate: string }): JSX.Element;\n```\n\n## Visit [use-funnel.slash.page](https://use-funnel.slash.page) for docs, guides, API and more!\n\n[English](https://use-funnel.slash.page/en) | [한국어](https://use-funnel.slash.page/ko)\n\n## Contributing\n\nRead our [Contributing Guide](./CONTRIBUTING.md) to familiarize yourself with `@use-funnel` development process, how to suggest bug fixes and improvements, and the steps for building and testing your changes.\n\n\u003ca title=\"Toss\" href=\"https://toss.im\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://static.toss.im/logos/png/4x/logo-toss-reverse.png\"\u003e\n    \u003cimg alt=\"Toss\" src=\"https://static.toss.im/logos/png/4x/logo-toss.png\" width=\"100\"\u003e\n  \u003c/picture\u003e\n\u003c/a\u003e\n\nMIT © Viva Republica, Inc. See [LICENSE](./LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoss%2Fuse-funnel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftoss%2Fuse-funnel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoss%2Fuse-funnel/lists"}