storybook: add Button and Spinner examples

This commit is contained in:
Yangshun Tay
2022-10-04 09:04:08 +08:00
parent de33d38e1b
commit 842837fb4e
15 changed files with 340 additions and 116 deletions

View File

@ -1,4 +1,4 @@
import { Button, CounterButton } from '@tih/ui';
import { Button, Spinner } from '@tih/ui';
export default function HomePage() {
return (
@ -8,8 +8,8 @@ export default function HomePage() {
<h1 className="text-center text-4xl font-bold text-red-600">
Homepage
</h1>
<CounterButton />
<Button label="Button text" size="md" variant="primary" />
<Spinner size="md" />
</div>
</div>
</main>

View File

@ -2,7 +2,18 @@ const path = require('path');
module.exports = {
stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.tsx'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
addons: [
{
name: '@storybook/addon-postcss',
options: {
postcssLoaderOptions: {
implementation: require('postcss'),
},
},
},
'@storybook/addon-links',
'@storybook/addon-essentials',
],
framework: '@storybook/react',
core: {
builder: '@storybook/builder-vite',

View File

@ -1 +1,6 @@
import 'tailwindcss/tailwind.css';
import '@tih/ui/dist/styles.css';
export const parameters = {
controls: { expanded: true },
};

View File

@ -14,17 +14,21 @@
"react-dom": "^18.2.0"
},
"devDependencies": {
"@heroicons/react": "^2.0.11",
"@storybook/addon-actions": "^6.4.18",
"@storybook/addon-docs": "^6.4.22",
"@storybook/addon-essentials": "^6.4.18",
"@storybook/addon-links": "^6.4.18",
"@storybook/addon-postcss": "^2.0.0",
"@storybook/builder-vite": "^0.1.33",
"@storybook/react": "^6.4.18",
"@tih/tailwind-config": "*",
"@tih/tsconfig": "*",
"@vitejs/plugin-react": "^1.3.2",
"autoprefixer": "^10.4.12",
"eslint-config-tih": "*",
"serve": "^13.0.2",
"tailwindcss": "^3.1.8",
"typescript": "^4.8.3",
"vite": "^2.9.9"
}

View File

@ -1,13 +1,6 @@
// If you want to use other PostCSS plugins, see the following:
// https://tailwindcss.com/docs/using-with-preprocessors
const config = require('@tih/tailwind-config/tailwind.config.js');
module.exports = {
plugins: {
// Specifying the config is not necessary in most cases, but it is included
// here to share the same config across the entire monorepo
tailwindcss: { config },
tailwindcss: {},
autoprefixer: {},
},
};

View File

@ -1,33 +1,243 @@
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { ComponentMeta } from '@storybook/react';
import { Button } from '@tih/ui';
import {
Button,
ButtonAddOnPosition,
ButtonDisplay,
ButtonSize,
ButtonType,
ButtonVariant,
} from '@tih/ui';
import React from 'react';
import { EnvelopeIcon } from '@heroicons/react/24/solid';
const buttonTypes: ReadonlyArray<ButtonType> = ['button', 'reset', 'submit'];
const buttonSizes: ReadonlyArray<ButtonSize> = ['sm', 'md', 'lg'];
const buttonAddOnPositions: ReadonlyArray<ButtonAddOnPosition> = [
'start',
'end',
];
const buttonDisplays: ReadonlyArray<ButtonDisplay> = ['block', 'inline'];
const buttonVariants: ReadonlyArray<ButtonVariant> = [
'primary',
'secondary',
'tertiary',
'special',
'success',
];
//👇 This default export determines where your story goes in the story list
export default {
/* 👇 The title prop is optional.
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
* to learn how to generate automatic titles
*/
title: 'Button',
component: Button,
argTypes: {
addonPosition: {
options: buttonAddOnPositions,
control: { type: 'select' },
},
display: {
options: buttonDisplays,
control: { type: 'select' },
},
isDisabled: {
control: 'boolean',
},
isLoading: {
control: 'boolean',
},
label: {
control: 'string',
},
size: {
options: buttonSizes,
control: { type: 'select' },
},
type: {
options: buttonTypes,
control: { type: 'select' },
},
variant: {
options: buttonVariants,
control: { type: 'select' },
},
},
} as ComponentMeta<typeof Button>;
//👇 We create a “template” of how args map to rendering
const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />;
export const PrimaryButton = Template.bind({});
PrimaryButton.args = {
label: 'Button text',
size: 'md',
variant: 'primary',
export const Basic = {
args: {
label: 'Click Me',
size: 'md',
variant: 'primary',
},
};
export const SecondaryButton = Template.bind({});
export function Variant() {
return (
<div className="space-x-4">
{buttonVariants.map((variant) => (
<Button key={variant} label="Click Me" size="md" variant={variant} />
))}
</div>
);
}
SecondaryButton.args = {
label: 'Button text',
size: 'md',
variant: 'secondary',
};
export function Size() {
return (
<div className="space-x-4">
{buttonSizes.map((size) => (
<Button key={size} label="Click Me" size={size} variant="primary" />
))}
</div>
);
}
export function Display() {
return (
<div className="space-y-4">
{buttonSizes.map((size) => (
<Button
key={size}
display="block"
label="Click Me"
size={size}
variant="primary"
/>
))}
</div>
);
}
export function Disabled() {
return (
<div className="space-x-4">
{buttonVariants.map((variant) => (
<Button
isDisabled={true}
key={variant}
label="Click Me"
size="md"
variant={variant}
/>
))}
</div>
);
}
export function Loading() {
return (
<div className="space-y-4">
<div className="space-x-4">
{buttonVariants.map((variant) => (
<Button
isLoading={true}
key={variant}
label="Click Me"
size="md"
variant={variant}
/>
))}
</div>
<div className="space-x-4">
{buttonVariants.map((variant) => (
<Button
isDisabled={true}
isLoading={true}
key={variant}
label="Click Me"
size="md"
variant={variant}
/>
))}
</div>
</div>
);
}
export function Icons() {
return (
<div className="space-y-4">
<div className="space-x-4">
{buttonSizes.map((size) => (
<Button
key={size}
icon={EnvelopeIcon}
label="Click Me"
size={size}
variant="primary"
/>
))}
<Button
icon={EnvelopeIcon}
isDisabled={true}
label="Click Me"
size="lg"
variant="primary"
/>
</div>
<div className="space-x-4">
{buttonSizes.map((size) => (
<Button
key={size}
addonPosition="start"
icon={EnvelopeIcon}
label="Click Me"
size={size}
variant="primary"
/>
))}
<Button
addonPosition="start"
icon={EnvelopeIcon}
isDisabled={true}
label="Click Me"
size="lg"
variant="primary"
/>
</div>
<div className="space-y-4">
{buttonSizes.map((size) => (
<Button
key={size}
display="block"
icon={EnvelopeIcon}
label="Click Me"
size={size}
variant="primary"
/>
))}
<Button
display="block"
icon={EnvelopeIcon}
isDisabled={true}
label="Click Me"
size="lg"
variant="primary"
/>
</div>
</div>
);
}
export function HiddenLabel() {
return (
<div className="space-x-4">
{buttonSizes.map((size) => (
<Button
key={size}
icon={EnvelopeIcon}
isLabelHidden={true}
label="Click Me"
size={size}
variant="primary"
/>
))}
<Button
icon={EnvelopeIcon}
isDisabled={true}
isLabelHidden={true}
label="Click Me"
size="lg"
variant="primary"
/>
</div>
);
}

View File

@ -1,20 +0,0 @@
import { CounterButton } from '@tih/ui';
import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs';
<Meta title="Components/Button" component={CounterButton} />
# Button
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec euismod, nisl eget consectetur tempor, nisl nunc egestas nisi, euismod aliquam nisl nunc euismod.
## Props
<ArgsTable of={CounterButton} />
## Examples
<Canvas>
<Story name="Default">
<CounterButton>Hello</CounterButton>
</Story>
</Canvas>

View File

@ -0,0 +1,57 @@
import { ComponentMeta } from '@storybook/react';
import { Spinner, SpinnerColor, SpinnerSize, SpinnerDisplay } from '@tih/ui';
import React from 'react';
const spinnerColors: ReadonlyArray<SpinnerColor> = ['default', 'inherit'];
const spinnerDisplays: ReadonlyArray<SpinnerDisplay> = ['block', 'inline'];
const spinnerSizes: ReadonlyArray<SpinnerSize> = ['xs', 'sm', 'md', 'lg'];
export default {
title: 'Spinner',
component: Spinner,
argTypes: {
color: {
options: spinnerColors,
control: { type: 'select' },
},
display: {
options: spinnerDisplays,
control: { type: 'select' },
},
label: {
control: 'string',
},
size: {
options: spinnerSizes,
control: { type: 'select' },
},
},
} as ComponentMeta<typeof Spinner>;
export const Basic = {
args: {
label: 'Loading data',
size: 'md',
},
};
export function Size() {
return (
<div className="space-x-4">
{spinnerSizes.map((size) => (
<Spinner key={size} label="Loading..." size={size} />
))}
</div>
);
}
export function Display() {
return (
<div className="space-y-4">
{spinnerSizes.map((size) => (
<Spinner key={size} display="block" label="Loading..." size={size} />
))}
</div>
);
}

View File

@ -0,0 +1,7 @@
const config = require('@tih/tailwind-config/tailwind.config.js');
/** @type {import('tailwindcss').Config} */
module.exports = {
...config,
content: [...config.content, './stories/**/*.{js,jsx,ts,tsx,md,mdx}'],
};