storybook
storybook copied to clipboard
How to setup interactions plugin and make it working.
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:
- 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;
};
- Add decorator to
.storybook/preview.ts
export const decorators = [storyResultDecorator]; // can gave more decorators
- 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.