Giter Site home page Giter Site logo

efstajas / svelte-stepper Goto Github PK

View Code? Open in Web Editor NEW
127.0 3.0 2.0 4.27 MB

๐Ÿšถ A simple library for building delightfully animated stepped flows with Svelte.

Home Page: https://svelte-stepper.jason-e.dev

JavaScript 2.79% TypeScript 9.21% HTML 0.79% Svelte 68.46% CSS 18.74%
animations component stepper svelte sveltekit

svelte-stepper's Introduction

๐Ÿšถ Svelte Stepper

GIF of Svelte Stepper in action

A simple library for building delightfully animated stepped flows with Svelte. Svelte Stepper is completely "headless", meaning it steps through whatever components you give it, putting you in full control of container- and step layout, styles and transitions.

๐ŸŒ Interactive demo & docs

Check out an simple demo implementation at svelte-stepper.jason-e.dev.

You can find the code for the above at /src/routes in this repo as a usage example.

โœจ Features

Svelte Stepper comes with a lot of built-in functionality, while still remaining easy-to-use at its core.

Simple & type-safe

Svelte Stepper is written entirely in TypeScript, and all its interfaces are fully type-safe out of the box. To get started, all you need to do is provide a sequence of Svelte components as steps. Every step can receive custom props.

Delightful animations

Svelte Stepper automatically transitions steps in a delightful way, and even smoothly adjusts its height to match each new step component. Of course, you can fully customize all animations.

Context & multi-step forms

Svelte Stepper includes a full context API, which allows you to share data between steps. This enables advanced usecases like building up form data over several steps, and submitting it at the end.

๐Ÿ’พ Installation

Install with NPM or yarn:

npm install @efstajas/svelte-stepper
yarn add @efstajas/svelte-stepper

๐Ÿ‘‹ Getting started

Getting a simple flow going is easy. First, let's create a few Step components.

Creating Steps

A step is simply a normal Svelte component, which can dispatch a number of special events in order to communicate with the stepper. Here's a very simple step with some text and a button that advances the flow to the next step:

<script lang="ts">
  import { createStepController } from '@efstajas/svelte-stepper';

  const stepController = createStepController();
</script>

<h1>My first step</h1>

<button on:click={stepController.nextStep}>Next</button>

As you can see, Svelte Stepper exposes a createStepController function, which you can use to create a stepController. This object contains a number of functions for communicating with the stepper, such as nextStep and previousStep.

Go ahead and create two simple step components so that we can move on to creating our first flow.

Initializing the Stepper

Getting a simple flow going is easy. The core of Svelte Stepper is the Stepper component. Simply import it into your page, and provide an array of your steps using the makeStep utility.

<script lang="ts">
  import { Stepper, makeStep } from '@efstajas/svelte-stepper';

  /* ... import your step components here ... */

  const exampleSteps = [
    makeStep({
      component: MyFirstStep,
      props: undefined
    }),
    makeStep({
      component: MySecondStepWithProps,
      props: {
        foo: 'bar',
      },
    }),
    makeStep({
      component: MyFinalStep,
      props: undefined
    })
  ];
</script>

<Stepper steps={exampleSteps} />

As you can see, you can pass props to your step components using the props property. The type of this property is automatically inferred from the provided step component.

Congratulations! This is everything you need to build a simple flow. Let's have a look at some more advanced features.

A note on padding

The stepper component automatically hides step overflow during transitions in order to prevent steps from overflowing the container during transition, which doesn't look very nice. If you want to add padding around your steps, please pass a padding prop to the Stepper component, instead of wrapping the container in a padded element. This ensures that transitions aren't visually cut off by the step container.

๐ŸŽฅ Animations

Svelte Stepper automatically transitions between your steps with a sleek animation by default. Of course, you can fully customize the entry- and exit transitions for steps.

Customizing the transition duration

If all you want to do is change the duration of the default transition, you can pass a defaultTransitionDuration prop to the stepper. Out of the box, it's set to 300 milliseconds. This prop controls the speed of the stepper container height transition, as well as the step's entry- and exit transitions.

<Stepper
  steps={exampleSteps}
  defaultTransitionDuration={1000}
/>

Using custom transition functions and -parameters

If you want to set fully custom transitions, you can set the stepIntroTransition and stepOutroTransition props on the stepper.

<Stepper
  steps={exampleSteps}
  defaultTransitionDuration={600}
  stepOutroTransition={{
    transitionFn: scale,
    params: () => ({
      duration: 600,
      delay: 0,
      scale: 1,
    }),
  }}
  stepIntroTransition={{
    transitionFn: fly,
    params: (direction) => ({
      duration: 600,
      delay: 0,
      x: direction === 'forward' ? 100 : -100,
    }),
  }}
/>

These props accept an object with transitionFn and params properties. Pass any standard Svelte transition function, and set any custom parameters for it. The params property accepts a function with an optional direction parameter, allowing you to alter the transition parameters based on whether the user is currently navigating forward or backward within the flow.

๐Ÿ’ฝ Context API

Stepped flows frequently collect a bunch of data from the user over multiple steps, and submit it at the end. For exactly this use-case, Svelte Stepper comes with a context system. It allows you to conveniently share a single Svelte writable store between all steps.

To define context, simply write a function that returns a Svelte writable store, and pass it to the Stepper component:

<script lang="ts" context="module">
  export interface MyExampleStepperContext {
    foo: string;
    bar: number;
  }
</script>

<script lang="ts">
  import { Stepper, makeStep } from '@efstajas/svelte-stepper';

  /* ... import your step components here ... */

  const exampleSteps = [
    makeStep({
      component: MyFirstStep,
      props: undefined
    }),
  ];

  const exampleContext: () => Writable<MyExampleStepperContext> = () => writable({
    foo: 'bar',
    bar: 42,
  });
</script>

<Stepper steps={exampleSteps} context={exampleContext} />

In this particular example, we're exporting the type of our context writable from a module, so that we can properly type the context writable in our step components later.

Passing context to the Stepper will make it automatically available to all steps as a context prop:

<script lang="ts">
  import { Writable } from 'svelte/store';
  import { MyExampleStepperContext } from './my-stepper-page.svelte';
  import { createStepController } from '@efstajas/svelte-stepper';

  const stepController = createStepController();

  export let context: Writable<MyExampleStepperContext>;
</script>

<h1>My first step</h1>

<p>
  Foo is {$context.foo} and bar is {$context.bar}.
</p>

<button on:click={context.update((v) => ({ ...v, bar: v.bar + 1}))}>Increment bar</button>

<button on:click={stepController.nextStep}>Next</button>

Using this method, you can incrementally populate a store of data throughout multiple steps.

๐Ÿ“ฌ Stepper Events

The Stepper component emits events allowing you to react to a step change or conclusion of the flow.

<Stepper
  steps={exampleSteps}
  on:conclusion={() => {
    alert('The last step in the flow has called stepController.nextStep()!');
  }}
  on:stepChange={(e) => {
    const { newIndex, of, direction } = e.detail;

    console.log(\`Changed to step \${newIndex + 1} of \${of} going \${direction}\`);
  }}
/>

The stepChange event is emitted when the stepper moves to a new step. It includes metadata on the current step index, the total amount of steps, as well as the direction of the change.

The conclusion event is emitted when the stepper has reached the last step and nextStep is called.

๐Ÿ•บ Side-Steps

Sometimes, you may need to temporarily switch to a different set of steps within a flow. Svelte Stepper includes sidestep functionality for this purpose. Using a side-step, you can easily temporarily launch a different flow, and come back to the original flow at the end.

To trigger a side-step, simply call stepController.sidestep(steps) within a step component, where steps is an array of new steps:

<script lang="ts">
  import { createStepController } from '@efstajas/svelte-stepper';

  import MyFirstSidestepStep from './my-first-sidestep-step.svelte';

  const stepController = createStepController();
</script>

<h1>Launching a sidestep</h1>

<button on:click={() => stepController.sidestep([
  makeStep({
    component: MyFirstSidestepStep,
    props: undefined
  }),
])}>Start sidestep</button>

Within a sidestep, you can use the usual nextStep and previousStep methods to navigate between steps. Once you reach the end of the sidestep flow, the stepper will automatically navigate back to the original flow.

You can also cancel a sidestep anywhere within the sidestep flow by calling stepController.cancelSidestep(). This will end the sidestep flow immediately, and navigate back to where the sidestep was triggered from within the original flow.

svelte-stepper's People

Contributors

efstajas avatar wlockiv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

trasherdk wlockiv

svelte-stepper's Issues

`Cannot find module 'esm-env'`

Cannot find module 'esm-env' imported from '/projectpath/node_modules/@efstajas/svelte-stepper/package/stepper.svelte'

Is this a complaint about too old a version of svelte/kit or lack of TS?

RTL support?

This looks awesome, I'd love to have full RTL layout support in animation.
Right now, the movement animation between pages turns from left to right, it should consider if the document has dir="rtl" and flip it away
Thanks.

Feature Requests

I have a couple of suggestions/ideas. I'm going to try to dig into it soon and see what I can find and maybe do a PR.

stepName prop

	makeStep({
		component: Page6,
		props: undefined,
		stepName: "Location"
	}),

and then do like

	on:stepChange={e => {
		const { newIndex, of, direction, stepName } = e.detail
	}}

This would offer some flexibility in finding steps for conditionals. If I move Page6 to Page8, I wouldn't have to change if (e.detail.stepName === "Location")

Nice To Have

As a "nice to have", if the component emitted on:next and on:prev events. It could be argued that you can already do those functions by looking at forward vs backward etc. The suggestion tho would just take some of the tedium off of it.

Using dispatch

Also, if I dispatch from say the Page6 component, it doesn't get passed up to be caught on the <Stepper /> call. Right now, if I do a thing in there that I'd normally dispatch, unless I've missed something I would instead have to use a separate store or context to go around the component level and pass events up. That could be hairy to detect and pass as the same name. I don't know how it'd be done. An attribute like on:custom (with your dispatches in the detail) would be a simple workaround, but it kinda gets outside of being Svelte-Like.

api section

Docs could use this to explicitly state what the available functions are.

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'map')

I followed the docs and I keep getting this error.

import { Stepper, makeStep } from '@efstajas/svelte-stepper';
	import FirmInfo from 'src/components/styledComponents/onboarding/completeProfile/FirmInfo.svelte';
	import PersonalInfo from 'src/components/styledComponents/onboarding/completeProfile/PersonalInfo.svelte';

	const profileSteps = [
		makeStep({
			component: FirmInfo,
			props: undefined
		}),
		makeStep({
			component: PersonalInfo,
			props: undefined
		})
	];

Step Code:

	import { createStepController } from '@efstajas/svelte-stepper';

	const stepController = createStepController();
</script>

<h1>My first step</h1>

<button on:click={stepController.nextStep}>Next</button>


Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.