npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@guestbell/onboarder

v1.0.18

Published

Nonlinear user onboarding done in react. Think state machine forms - steps in any order

Downloads

12

Readme

Onboarder

There are a lot of react steppers/wizards/onboarding libs out there. Onboarder is different:

  • Tiny
  • Non-linear - Jump between steps, lib predicts rest of the way and time taken
  • 0 dependencies - Build your UI or use our
  • Easy setup
  • Typed API

Install

npm install @guestbell/onboarder --save

or

yarn add @guestbell/onboarder

Demo

Complex UI or Simple example

Getting started

Following example will show you how to create wizard with:

  • Loop step (exit loop based on rules)
  • Step with form validation
  • Step with error message
  1. Put your imports in place
import Onboarder, { Steps, Structure } from "@guestbell/onboarder";
  1. Create state for your steps
type OnboarderState = {
  firstStep: never;
  loopStep: { 
    counter: number; 
    isDirty: boolean; 
    errorMessage?: string 
  };
  afterLoopStep: never;
  textStep: { message: string };
  finalStep: never;
};
  1. Create steps strongly typed with the help of generic Steps type. Each object key is a step
const steps: Steps<OnboarderState> = {
  firstStep: { Component: () => <>First step</> },
  loopStep: {
    Component: ({ setState, state }) => (
      <>
        <div>Loop step</div>
        {state.errorMessage && <div>Error: {state.errorMessage}</div>}
        <button
          onClick={() =>
            setState({ ...state, counter: state.counter + 1, isDirty: true })
          }
        >
          {state.counter.toString()}
        </button>
      </>
    ),
    initialState: {
      counter: 0,
      isDirty: false,
    },
    // Cleanup
    afterNext: ({ state, setState }) => {
      setState({ ...state, isDirty: false, errorMessage: undefined });
    },
    // On the flight validation that fires when you click next
    beforeNext: ({ state, setState }) => {
      if (state.counter < 2) {
        setState({
          ...state,
          errorMessage: "Increment to at least 2 because rules",
        });
        return false;
      }
      return true;
    },
  },
  afterLoopStep: {
    Component: ({ nextStep }) => (
      <>{nextStep === "loopStep" ? "We are looping" : "We're done looping."}</>
    ),
  },
  textStep: {
    Component: ({ setState, state }) => (
      <>
        <input
          value={state.message}
          onChange={(e) => setState({ ...state, message: e.target.value })}
        />
        <br />
        Message: {state.message}
      </>
    ),
    initialState: {
      message: "",
    },
  },
  finalStep: {
    Component: () => <>All done!!!</>,
  },
};
  1. Define structure - this tells the lib how to jump between steps
const structure: Structure<OnboarderState> = {
  firstStep: () => ({ loopStep: 1 }),
  loopStep: (state) => ({
    afterLoopStep: state.loopStep.isDirty ? 1 : -1,
  }),
  afterLoopStep: (state) => ({
    loopStep: state.loopStep?.counter < 3 ? 1 : -1,
    textStep: state.loopStep?.counter >= 3 ? 1 : -2,
  }),
  textStep: (state) => ({
    finalStep: (state.textStep?.message && 1) || -1,
  }),
};

Notice how the object has same (optional) keys like our steps. Each gets passed a global state, and returns an object with same (optional) keys like our steps. Values of this object work like this: a) Negative Number or zero means the step is allowed, but disabled based on a condition b) Positive Number means the step is allowed, actual number gives step priority, smaller number means higher priority c) Undefined or key missing means the step is never allowed 5. Put it all together

<Onboarder
  steps={steps}
  initialStep="firstStep"
  // array because multiple steps can be final
  finalSteps={['finalStep']}
  structure={structure}
  StepContainer={SimpleStepContainer}
/>
  1. Bonus: Add simple UI This example already works, but let's add some simple UI. You do this by providing a StepContainer prop to <Onboarder/>
import { StepContainerComponentProps } from "@guestbell/onboarder";

function SimpleStepContainer<TState extends {}>(
  props: React.PropsWithChildren<StepContainerComponentProps<TState>>
) {
  const {
    children,
    goToNextStep,
    hasNextStep,
    goToUndoStep,
    hasUndoStep,
    hasRedoStep,
    goToRedoStep,
    reset,
  } = props;
  return (
    <div>
      {children}
      <div style={{ marginTop: "1rem" }}>
        <button onClick={reset}>Reset</button>
        <button onClick={goToUndoStep} disabled={!hasUndoStep}>
          Previous
        </button>
        <button onClick={goToRedoStep} disabled={!hasRedoStep}>
          Next
        </button>
        <button onClick={goToNextStep} disabled={!hasNextStep}>
          Continue
        </button>
      </div>
    </div>
  );
}
  1. Done! You can see this example on github

API

Here

FAQ

How can I add my extra props to the step?

Notice that Steps has 2 generic parameters. First is the type of the state, you can use the second generic parameter to introduce extra props to your step.

How can I fire an action before going to next step?

Each step has a beforeNext async function. Use it to handle your logic. Return false if the navigation should be prevented.

How do I clean up step state after navigation?

Each step has a afterNext async function. Use it for cleanup.

Created and sponsored by

  • GuestBell - Customer centric online POS for Hotels and short terms stays.

Contributing

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request :D

License

MIT