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

storybook-animate

v1.0.0

Published

<a href="https://github.com/storybooks/storybook" target="_blank"><img src="https://raw.githubusercontent.com/storybooks/brand/master/badge/badge-storybook.svg"></a>![twitter link](https://img.shields.io/badge/[email protected])[![npm version]

Downloads

165

Readme

twitter linknpm version

Storybook-Animate

Storybook is great for designing indivdual states of your application's components. But your users don't see your app as individual states, but a series of states that flow together over time. If storybook lets you design the frames, Storybook-Animate lets you create the flipbook!

Simplicity Breeds Creativity

Where you used to provide a story of a single component with props:

storiesOf('Thermometer', module)
  .add('Healthy Temperature', () => (
    <Thermometer scale="F" temp={98.6}>
  ))

You can animate the component with a propStream

storiesOf('Thermometer', module)
  .add('Healthy Temperature', () => (
    <Animate
      component={Thermometer}
      propStream={climbingTemp}
    />
  ))

And here is the beautiful result:

Try clicking on the animation to restart it, or using <Animate loop={true} ... /> to just sit back and admire your animation :)

Dive into Streams

A propStream is an RxJS Observable, created any way you like. But to ease you in, Storybook-Animate includes some helpers to supplement those provided by Polyrhythm:

const climbingTemp = sequenceOf(
  after(0.0, { temp: 86 }),
  after(1000, { temp: 92 }),
  after(1000, { temp: 96 }),
  after(1000, { temp: 99 }),
  after(1000, { temp: 100.5 }),
  after(1000, { temp: 102.2 })
).combineWith({scale: "F"})

Storybook Your API calls, Loading States, API Errors

Sometimes your users see loading states for a lot longer than you are able to during development—why not have stories for those loading states too? Feel their pain, and design to improve upon it right there in your UX design tool.

Like this example from a recent Storybook:

Imagine an oversimplified auto-complete component such as this one.

import { searchApi } from './anotherFile'

function AutoComplete() {
  const [results, setResults] = useState([])
  return (
    <input onChange={(e) => {
      searchApi(e.target.text)
        .then(results => setResults(results))
    }/>
    { /* render results */ }
  )
}

It calls searchApi, a Promise-returning function, to get results, which are objects like {text: 'Boom', value: 25}. It then changes internal state with those results to cause a re-render. To simulate a slow state, the first thing we must do is make the component default to using the search function it used before, but make it overridable as a prop.

import {searchApi} from './anotherFile'
function AutoComplete({ searchFunction = searchApi }) {
  ...
}

Now it will call searchApi by default unless another function is provided. Let's provide one. Here's a mock function that, after a delay of 3000 msec, returns the array we'd get from the real service.

const slowSearch = term => after(3000, [
  {text: 'Abacus', value: 1},
  {text: 'AbbA', value: 2}
])).toPromise()

And now let's hand this function in to AutoComplete in our stories. Now AutoComplete can display the results we want, when we want them!

storiesOf('Autocomplete', module)
  .add('Regular Loading', () => (
    <AutoComplete/>
  ))
  .add('Slow Loading', () => (
    <AutoComplete searchFunction={slowSearch} />
  ))

Why not add mock functions for failed lookups as well? This will make you think, and plan for it. All without leaving Storybook, thanks to Storybook-Animate, and RxJS Observables.

Want to use this with the Knobs addon?

If you have a story that is driven by an Observable, such as one using <Animate> you may wish to use knobs to change that Observable's values, by incorporating the knob's value into the Observable's values.

Or, you may want to use a knob to produce all the values of that Observable. Either way is possible.

For the case of modifying an Observable by a knob value, this is done by applying a map to every value, in which the knobs value is read. (You may have to read the knob's value once up-front, before the Observable produces a value, to make the knob appear in the Storybook UI).

Story ClimbingLoop:

  <Animate
    component={Thermometer}
    propStream={climbingTemp}
  />

Story KnobControlsScale:

  <Animate
    component={Thermometer}
    propStream={climbingTemp.pipe(
      map(({ temp }) => ({
        temp,
        scale: select("Scale", { C: "C", F: "F" }, "F")
      }))
    )}
  />

Each time the climbingTemp Observable has a value, Animate will render <Thermometer> with the scale the knob is set to.

What if we want the temperature to be entirely controlled by a knob? We can use <WithObservableKnob> to create a knob, plus an Observable of its values, and render a component with those values.

Story KnobControlsTemperature

<WithObservableKnob
  knob={[number, "Temp", 98]}
  render={knobTemps => (
    <Animate
      component={Thermometer}
      propStream={knobTemps.pipe(
        map(v => ({ temp: v, scale: "F" }))
      )}
    />
  )}
/>

The Sky's The Limit!

You can combine Storybook-Animate with other means of animations. CSS animations, React Transition Groups internal to your components - you are only limited by what you can come up with!

Got ideas that we haven't thought of? Search for an issue or open one if you don't see it.

Examples

The Thermometer example is in the stories/ folder of this project. Feel free to post a link to what you've built with it too, we can include it here!

twitter link