@htc-class/storylite
v2.0.1
Published
> An _incredibly_ bare-bones knock-off of Storybook with several **serious and > fundamental** flaws. But it's FAST! ๐
Downloads
4
Readme
StoryLite
An incredibly bare-bones knock-off of Storybook with several serious and fundamental flaws. But it's FAST! ๐
Installation
npm install @htc-class/storylite
Usage
StoryLite isn't a separate web-app running on a separate port like Storybook. Instead, it's a lite, dev-only drop-in replacement for your app where you can work on your components with the same bundler, stack, etc. Therefore, at the root of your app, you need to conditionally load it, approximately like so:
import React from 'react';
import { queryParam } from '@htc-class/storylite';
import AllStories from '../stories';
import App from './App';
const App: React.FC = () => {
if (process.env.NODE_ENV === `DEVELOPMENT` && queryParam(`storylite`)) {
return <AllStories />;
} else {
return <App />;
}
};
export default App;
The queryParam()
helper shown above is just a convenience function to help you test if
the current URL has a query parameter. So the way to activate and view your StoryLite
session is by adding ?storylite=1
to the browser's address bar. To end your session,
either manually remove the query parameter, or click the close button in the StoryLite UI.
It is recommended that you have a folder called stories/
which will have a directory
structure something like this:
stories/
- ComponentA.stories.tsx
- ComponentB.stories.tsx
- index.tsx
The stories/index.tsx
file will be the place where you gather and list all of your
individual stories. It might look something like this:
import React from 'react';
import { Stories } from '@htc-class/storylite';
import ButtonStories from './Button.stories';
import BlockStories from './Block.stories';
import LoginStories from './Login.stories';
const AllStories: React.FC = () => {
return <Stories stories={[ButtonStories, BlockStories, LoginStories]} />;
};
export default AllStories;
The <Stories />
main component takes an array of StoryMeta
objects, each of which has
a type like this:
export interface StoryMeta {
name: string;
component: React.FC;
layout?: 'centered' | 'fullscreen' | 'padded';
bgColor?: string;
}
Then, as shown above, each component has it's own story file, like
stories/Button.stories.tsx
. Smaller components that you may want to view in multiple
states might have a story file like this, which uses the <StoryGroup />
and <Story />
helper components:
import React from 'react';
import { Story, StoryGroup, StoryMeta } from '@htc-class/storylite';
import Button from '../components/Button';
const ButtonStories: React.FC = () => (
<StoryGroup>
<Story title="Default">
<Button />
</Story>
<Story title="Secondary">
<Button secondary />
</Story>
</StoryGroup>
);
const meta: StoryMeta = {
name: `<Button />`,
component: ButtonStories,
layout: `padded`,
};
export default meta;
Or, if you have a component that is a full-width or full-screen block or element, it probably makes sense to have a dedicated story file with only one permutation, like so:
import { StoryMeta } from '@htc-class/storylite';
import React from 'react';
import Block from '../components/Block';
const BlockStories: React.FC = () => <Block />;
const meta: StoryMeta = {
name: `<Block />`,
component: BlockStories,
layout: `fullscreen`,
};
export default meta;
Of course, you don't technically need separate files for each component, the
BlockStories
example above could be inlined into the main stories/index.tsx
file like
so:
import React from 'react';
import { Stories } from '@htc-class/storylite';
import ButtonStories from './Button.stories';
import LoginStories from './Login.stories';
import Block from '../components/Block';
const AllStories: React.FC = () => {
return (
<Stories
stories={[
ButtonStories,
{
name: `<Block />`,
component: Block,
layout: `fullscreen`,
},
LoginStories,
]}
/>
);
};
export default AllStories;