pixijs / storybook

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to setup interactions plugin and make it working.

neatbyte-vnobis opened this issue · comments

It will be great to use @storybook/addon-interactions to automate some more complex animations that goes one after another.

There is no point to use @storybook/testing-library for Pixi stories (as it simulates events over the dom elements), but steps logic can be used.

There is one problem that is a blocker to use interactions - how to get a Pixi Container (our component) that is returned from a story.
Default Storybook interactions are using canvasElement which contains rendered component, but it is a DOM element (see docs sample https://storybook.js.org/docs/react/essentials/interactions).

This DOM element is useless for us as we need an object/component returned from a story, so we can trigger certain animation method from it. Sadly, Storybook doesn't provide a way to get a value returned from a story render process.

Bellow is workaround I have made to handle this problem:

  1. Create a decorator to store story render result:
export const storyResultDecorator = (story, context) => {
  // storyResult is the value returned from your Story render
  const storyResult = story();
  
  // store story result into context.canvasElement so it can be get from there in the interaction
  context.canvasElement.storyResult = storyResult;

  // return story result as is
  return storyResult;
};
  1. Add decorator to .storybook/preview.ts
export const decorators = [storyResultDecorator]; // can gave more decorators
  1. Create a story with interaction (do not forget to add animateAction func to a BunnyDemo, in my case it was changing a rotation direction)
import { action } from '@storybook/addon-actions';

import { BunnyDemo } from './BunnyDemo';

export default {
    title: 'Demos-Basic',
    args: {
        bunnySize: 1,
        bunnySpacing: 40,
        someInjectedObject: {
            onBunnyClick: action('onBunnyClick'),
        },
    },
    render: (args: any) => new BunnyDemo(args),
};

// plain func to add a pause
const pause = (time = 0) => new Promise<void>(resolve => setTimeout(() => resolve(), time));

export const Interaction = {
    play: async ({ step, canvasElement: { storyResult } }: any) => {
        await step('Wait for 3 secs', async () => await pause(3000));
    
        await step('Change rotation direction 1', async () => {
            await storyResult.animateAction();
        });

        await step('Wait for 3 secs', async () => await pause(3000));

        await step('Change rotation direction 2', async () => {
            await storyResult.animateAction();
        });

        await step('Wait for 3 secs', async () => await pause(3000));

        await step('Change rotation direction 3', async () => {
            await storyResult.animateAction();
        });
      },
}

Maybe there is a better way to get Story render result in the interaction? Feel free to suggest.