{"id":17458117,"url":"https://github.com/pocesar/react-native-stager","last_synced_at":"2025-03-21T03:33:32.147Z","repository":{"id":57340430,"uuid":"99264092","full_name":"pocesar/react-native-stager","owner":"pocesar","description":"A performant wizard-like multi stages component for React Native without a router","archived":false,"fork":false,"pushed_at":"2018-10-29T02:02:14.000Z","size":242,"stargazers_count":16,"open_issues_count":3,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-18T06:28:07.158Z","etag":null,"topics":["performant","react","react-native","react-native-component","typescript","wizard","wizard-steps"],"latest_commit_sha":null,"homepage":"","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/pocesar.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}},"created_at":"2017-08-03T18:39:25.000Z","updated_at":"2020-01-05T19:11:36.000Z","dependencies_parsed_at":"2022-08-29T16:30:17.659Z","dependency_job_id":null,"html_url":"https://github.com/pocesar/react-native-stager","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocesar%2Freact-native-stager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocesar%2Freact-native-stager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocesar%2Freact-native-stager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocesar%2Freact-native-stager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pocesar","download_url":"https://codeload.github.com/pocesar/react-native-stager/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221811374,"owners_count":16884305,"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":["performant","react","react-native","react-native-component","typescript","wizard","wizard-steps"],"created_at":"2024-10-18T03:54:44.893Z","updated_at":"2024-10-28T09:17:18.767Z","avatar_url":"https://github.com/pocesar.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/pocesar/react-native-stager.svg?branch=master)](https://travis-ci.org/pocesar/react-native-stager) [![Coverage Status](https://coveralls.io/repos/github/pocesar/react-native-stager/badge.svg?branch=master)](https://coveralls.io/github/pocesar/react-native-stager?branch=master) [![npm version](https://badge.fury.io/js/react-native-stager.svg)](https://badge.fury.io/js/react-native-stager)\n\n# react-native-stager\n\nA performant wizard-like multi stages component for React Native without a router\n\n## Why?\n\nUsing a router solution to create a multi-step wizard-like interface is good, but sometimes you want\nto keep all your state in just one parent component without having to rely on `redux` for example,\nenter the `Stager`\n\n## How?\n\n```jsx\nimport React from 'react'\nimport { View, TouchableOpacity, Text } from 'react-native'\nimport Stager, { Stage } from 'react-native-stager'\n\nclass MyWizard extends React.Component {\n  render() {\n    return (\n      \u003cStager onChange={(stage, direction) =\u003e {\n        // stage == step 1 || step 2\n        // direction = 1 = next | -1 = prev | 0 = reset / initial\n      }}\u003e\n        \u003cStage key=\"step 1\" continue={() =\u003e true}\u003e\n          {({ instance, context }) =\u003e (\n            \u003cView\u003e\n              \u003cTouchableOpacity onPress={context.notify}\u003e\n                \u003cText\u003e{'Hello'}\u003c/Text\u003e\n              \u003c/TouchableOpacity\u003e\n            \u003c/View\u003e\n          )}\n        \u003c/Stage\u003e\n\n        \u003cStage key=\"step 2\" noPrevious loaded={(cb) =\u003e this.setState({ loaded: true }, cb)}\u003e\n          {() =\u003e (\n            \u003cText\u003e{'World'}\u003c/Text\u003e\n          )}\n        \u003c/Stage\u003e\n      \u003c/Stager\u003e\n    )\n  }\n}\n\nexport default MyWizard\n```\n\n## Components and API\n\n`Stager`\n\nThe root component that will hold the steps. Accepts an `onChange` prop that receives the transitioning stage name and the direction (-1 = prev / 1 = next / 0 = reset/initial).\nCan be safely nested.\n\n```tsx\n\u003cStager onChange={(stage, direction) =\u003e {\n  // do something nice\n  }}\u003e\n\u003cStager\u003e\n```\n\n`Stage`\n\nNeed to set inside `Stager`. Can use `continue`, `noPrevious` and `loaded` props.\nNotice that the children must always be a function. The `key` prop is required.\n\nIt receives an object with `instance` (this current `Stage`) and\n`context` (the current `Stager`)\n\n```tsx\n\u003cStager\u003e\n  \u003cStage key=\"step 1\"\u003e\n    {({ instance, context }) =\u003e (\n      \u003cText\u003e{'This is step 1'}\u003c/Text\u003e\n    )}\n  \u003c/Stage\u003e\n\u003c/Stager\u003e\n```\n\nWhen using `continue`, you always need to signal to the `Stage` that it should re-evaluate the\n`continue` function, to see if you're able to continue. This is so the component doesn't\nre-render everytime everytime a children changes.\n\n```tsx\n\u003cStager\u003e\n  \u003cStage\n    key=\"step 1\"\n    continue={() =\u003e this.state.canContinue}\n    \u003e\n    {({ instance, context }) =\u003e (\n      \u003cView\u003e\n        \u003cText\u003e{'This is step 1'}\u003c/Text\u003e\n        \u003cButton title=\"can continue\" onPress={() =\u003e {\n          this.setState({\n            canContinue: true\n          }, instance.refresh)\n        }} /\u003e\n      \u003c/View\u003e\n    )}\n  \u003c/Stage\u003e\n\n  \u003cStage\n    key=\"step 2\"\n    loaded={(cb) =\u003e this.setState({ canContinue: false }, cb)}\n    continue={() =\u003e this.state.canContinue}\n    \u003e\n    {({ instance, context }) =\u003e (\n      \u003cView\u003e\n        \u003cText\u003e{'This is step 1'}\u003c/Text\u003e\n        \u003cButton title=\"can continue\" onPress={() =\u003e {\n          this.setState({\n            canContinue: true\n          }, instance.refresh)\n        }} /\u003e\n      \u003c/View\u003e\n    )}\n  \u003c/Stage\u003e\n\u003c/Stager\u003e\n```\n\n`StageButtons`\n\nThe internal implementation of the StageButtons are merely for a quick prototype standpoint (to get the stage going),\nand you should style if using your own. It doesn't matter where you put them, they will always be below the current\nactive stage. Notice that you CAN set the style to use `position: absolute` and place it anywhere in the stage.\n\n```tsx\n\u003cStager\u003e\n  \u003cStageButtons\u003e\n    {({ context }) =\u003e (\n      \u003cView\u003e\n        \u003cButton title=\"\u003c\" onPress={context.prev} /\u003e\n        \u003cButton title=\"\u003e\" onPress={context.next} /\u003e\n      \u003c/View\u003e\n    )}\n  \u003c/StageButtons\u003e\n\u003c/Stager\u003e\n```\n\n`StageProgress`\n\nThe same thing with `StageButtons`, it's just an ugly placeholder to show functionality. Replace it with your own\n\n```tsx\n\u003cStager\u003e\n  \u003cStageProgress\u003e\n    {({ context }) =\u003e (\n      \u003cView key=\"progress\" style={styles.progressView}\u003e\n        \u003cView  style={styles.progressOutterFlex}\u003e\n          \u003cView style={styles.progressFlex}\u003e\n            {context.state.stages.map((stage, index) =\u003e (\n                \u003cView key={index} style={[\n                  styles.progressIndicator,\n                  {\n                    flex: (1 / context.state.stages.length) / 2,\n                  },\n                  {\n                    backgroundColor: context.state.currentStage \u0026\u0026 context.state.stages.indexOf(stage) \u003c= context.state.stages.indexOf(context.state.currentStage) ? 'blue' : 'gray'\n                  }\n                 ]} /\u003e\n              )\n            )}\n          \u003c/View\u003e\n          \u003cView style={styles.progressPad} /\u003e\n        \u003c/View\u003e\n      \u003c/View\u003e\n    )}\n  \u003c/StageProgress\u003e\n\u003c/Stager\u003e\n```\n\n\n## Caveats\n\n* Since you need to use function children, your `shouldComponentUpdate` might go crazy. To counter that\nassign a class member for your function that returns your component\n* The default progress and prev / next buttons are dull, and most likely won't match your application\nstyle. For that, use `StageProgress` and `StageButtons` wherever you feel like it\n* Children `Stage` won't automatically update (since `Stage` has `shouldComponentUpdate` to return `false`), so you\nneed, on the `instance`, to call `refresh` whenever you need to update your prev / next buttons\n\n## License\n\nMIT","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpocesar%2Freact-native-stager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpocesar%2Freact-native-stager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpocesar%2Freact-native-stager/lists"}