Improve Redux Storybook (#37227)
This commit is contained in:
parent
7230c2059f
commit
8c2845906c
@ -55,12 +55,31 @@ const preview: Preview = {
|
|||||||
locale: 'en',
|
locale: 'en',
|
||||||
},
|
},
|
||||||
decorators: [
|
decorators: [
|
||||||
(Story, { parameters, globals, args }) => {
|
(Story, { parameters, globals, args, argTypes }) => {
|
||||||
// Get the locale from the global toolbar
|
// Get the locale from the global toolbar
|
||||||
// and merge it with any parameters or args state.
|
// and merge it with any parameters or args state.
|
||||||
const { locale } = globals as { locale: string };
|
const { locale } = globals as { locale: string };
|
||||||
const { state = {} } = parameters;
|
const { state = {} } = parameters;
|
||||||
const { state: argsState = {} } = args;
|
|
||||||
|
const argsState: Record<string, unknown> = {};
|
||||||
|
for (const [key, value] of Object.entries(args)) {
|
||||||
|
const argType = argTypes[key];
|
||||||
|
if (argType?.reduxPath) {
|
||||||
|
const reduxPath = Array.isArray(argType.reduxPath)
|
||||||
|
? argType.reduxPath.map((p) => p.toString())
|
||||||
|
: argType.reduxPath.split('.');
|
||||||
|
|
||||||
|
reduxPath.reduce((acc, key, i) => {
|
||||||
|
if (acc[key] === undefined) {
|
||||||
|
acc[key] = {};
|
||||||
|
}
|
||||||
|
if (i === reduxPath.length - 1) {
|
||||||
|
acc[key] = value;
|
||||||
|
}
|
||||||
|
return acc[key] as Record<string, unknown>;
|
||||||
|
}, argsState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const reducer = reducerWithInitialState(
|
const reducer = reducerWithInitialState(
|
||||||
{
|
{
|
||||||
@ -69,7 +88,7 @@ const preview: Preview = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
state as Record<string, unknown>,
|
state as Record<string, unknown>,
|
||||||
argsState as Record<string, unknown>,
|
argsState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
|
|||||||
@ -1,7 +1,20 @@
|
|||||||
// The addon package.json incorrectly exports types, so we need to override them here.
|
// The addon package.json incorrectly exports types, so we need to override them here.
|
||||||
|
|
||||||
|
import type { RootState } from '@/mastodon/store';
|
||||||
|
|
||||||
// See: https://github.com/storybookjs/storybook/blob/v9.0.4/code/addons/vitest/package.json#L70-L76
|
// See: https://github.com/storybookjs/storybook/blob/v9.0.4/code/addons/vitest/package.json#L70-L76
|
||||||
declare module '@storybook/addon-vitest/vitest-plugin' {
|
declare module '@storybook/addon-vitest/vitest-plugin' {
|
||||||
export * from '@storybook/addon-vitest/dist/vitest-plugin/index';
|
export * from '@storybook/addon-vitest/dist/vitest-plugin/index';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RootPathKeys = keyof RootState;
|
||||||
|
|
||||||
|
declare module 'storybook/internal/csf' {
|
||||||
|
export interface InputType {
|
||||||
|
reduxPath?:
|
||||||
|
| `${RootPathKeys}.${string}`
|
||||||
|
| [RootPathKeys, ...(string | number)[]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
@ -1,16 +1,28 @@
|
|||||||
|
import type { ComponentProps } from 'react';
|
||||||
|
|
||||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||||
|
|
||||||
import { accountFactoryState, relationshipsFactory } from '@/testing/factories';
|
import { accountFactoryState, relationshipsFactory } from '@/testing/factories';
|
||||||
|
|
||||||
import { Account } from './index';
|
import { Account } from './index';
|
||||||
|
|
||||||
|
type Props = Omit<ComponentProps<typeof Account>, 'id'> & {
|
||||||
|
name: string;
|
||||||
|
username: string;
|
||||||
|
};
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: 'Components/Account',
|
title: 'Components/Account',
|
||||||
component: Account,
|
|
||||||
argTypes: {
|
argTypes: {
|
||||||
id: {
|
name: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description: 'ID of the account to display',
|
description: 'The display name of the account',
|
||||||
|
reduxPath: 'accounts.1.display_name_html',
|
||||||
|
},
|
||||||
|
username: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'The username of the account',
|
||||||
|
reduxPath: 'accounts.1.acct',
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
@ -40,7 +52,8 @@ const meta = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
args: {
|
args: {
|
||||||
id: '1',
|
name: 'Test User',
|
||||||
|
username: 'testuser',
|
||||||
size: 46,
|
size: 46,
|
||||||
hidden: false,
|
hidden: false,
|
||||||
minimal: false,
|
minimal: false,
|
||||||
@ -55,17 +68,16 @@ const meta = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} satisfies Meta<typeof Account>;
|
render(args) {
|
||||||
|
return <Account id='1' {...args} />;
|
||||||
|
},
|
||||||
|
} satisfies Meta<Props>;
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
|
|
||||||
type Story = StoryObj<typeof meta>;
|
type Story = StoryObj<typeof meta>;
|
||||||
|
|
||||||
export const Primary: Story = {
|
export const Primary: Story = {};
|
||||||
args: {
|
|
||||||
id: '1',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Hidden: Story = {
|
export const Hidden: Story = {
|
||||||
args: {
|
args: {
|
||||||
|
|||||||
@ -4,20 +4,22 @@ import type { Meta, StoryObj } from '@storybook/react-vite';
|
|||||||
|
|
||||||
import { Emoji } from './index';
|
import { Emoji } from './index';
|
||||||
|
|
||||||
type EmojiProps = ComponentProps<typeof Emoji> & { state: string };
|
type EmojiProps = ComponentProps<typeof Emoji> & {
|
||||||
|
style: 'auto' | 'native' | 'twemoji';
|
||||||
|
};
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: 'Components/Emoji',
|
title: 'Components/Emoji',
|
||||||
component: Emoji,
|
component: Emoji,
|
||||||
args: {
|
args: {
|
||||||
code: '🖤',
|
code: '🖤',
|
||||||
state: 'auto',
|
style: 'auto',
|
||||||
},
|
},
|
||||||
argTypes: {
|
argTypes: {
|
||||||
code: {
|
code: {
|
||||||
name: 'Emoji',
|
name: 'Emoji',
|
||||||
},
|
},
|
||||||
state: {
|
style: {
|
||||||
control: {
|
control: {
|
||||||
type: 'select',
|
type: 'select',
|
||||||
labels: {
|
labels: {
|
||||||
@ -28,11 +30,7 @@ const meta = {
|
|||||||
},
|
},
|
||||||
options: ['auto', 'native', 'twemoji'],
|
options: ['auto', 'native', 'twemoji'],
|
||||||
name: 'Emoji Style',
|
name: 'Emoji Style',
|
||||||
mapping: {
|
reduxPath: 'meta.emoji_style',
|
||||||
auto: { meta: { emoji_style: 'auto' } },
|
|
||||||
native: { meta: { emoji_style: 'native' } },
|
|
||||||
twemoji: { meta: { emoji_style: 'twemoji' } },
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
render(args) {
|
render(args) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user