mirror of
https://github.com/glitch-soc/mastodon.git
synced 2026-03-29 03:00:33 +02:00
Improve Redux Storybook (#37227)
This commit is contained in:
@@ -55,12 +55,31 @@ const preview: Preview = {
|
||||
locale: 'en',
|
||||
},
|
||||
decorators: [
|
||||
(Story, { parameters, globals, args }) => {
|
||||
(Story, { parameters, globals, args, argTypes }) => {
|
||||
// Get the locale from the global toolbar
|
||||
// and merge it with any parameters or args state.
|
||||
const { locale } = globals as { locale: string };
|
||||
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(
|
||||
{
|
||||
@@ -69,7 +88,7 @@ const preview: Preview = {
|
||||
},
|
||||
},
|
||||
state as Record<string, unknown>,
|
||||
argsState as Record<string, unknown>,
|
||||
argsState,
|
||||
);
|
||||
|
||||
const store = configureStore({
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
// 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
|
||||
declare module '@storybook/addon-vitest/vitest-plugin' {
|
||||
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 {};
|
||||
@@ -1,16 +1,28 @@
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||
|
||||
import { accountFactoryState, relationshipsFactory } from '@/testing/factories';
|
||||
|
||||
import { Account } from './index';
|
||||
|
||||
type Props = Omit<ComponentProps<typeof Account>, 'id'> & {
|
||||
name: string;
|
||||
username: string;
|
||||
};
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Account',
|
||||
component: Account,
|
||||
argTypes: {
|
||||
id: {
|
||||
name: {
|
||||
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: {
|
||||
type: 'number',
|
||||
@@ -40,7 +52,8 @@ const meta = {
|
||||
},
|
||||
},
|
||||
args: {
|
||||
id: '1',
|
||||
name: 'Test User',
|
||||
username: 'testuser',
|
||||
size: 46,
|
||||
hidden: 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;
|
||||
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Primary: Story = {
|
||||
args: {
|
||||
id: '1',
|
||||
},
|
||||
};
|
||||
export const Primary: Story = {};
|
||||
|
||||
export const Hidden: Story = {
|
||||
args: {
|
||||
|
||||
@@ -4,20 +4,22 @@ import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||
|
||||
import { Emoji } from './index';
|
||||
|
||||
type EmojiProps = ComponentProps<typeof Emoji> & { state: string };
|
||||
type EmojiProps = ComponentProps<typeof Emoji> & {
|
||||
style: 'auto' | 'native' | 'twemoji';
|
||||
};
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Emoji',
|
||||
component: Emoji,
|
||||
args: {
|
||||
code: '🖤',
|
||||
state: 'auto',
|
||||
style: 'auto',
|
||||
},
|
||||
argTypes: {
|
||||
code: {
|
||||
name: 'Emoji',
|
||||
},
|
||||
state: {
|
||||
style: {
|
||||
control: {
|
||||
type: 'select',
|
||||
labels: {
|
||||
@@ -28,11 +30,7 @@ const meta = {
|
||||
},
|
||||
options: ['auto', 'native', 'twemoji'],
|
||||
name: 'Emoji Style',
|
||||
mapping: {
|
||||
auto: { meta: { emoji_style: 'auto' } },
|
||||
native: { meta: { emoji_style: 'native' } },
|
||||
twemoji: { meta: { emoji_style: 'twemoji' } },
|
||||
},
|
||||
reduxPath: 'meta.emoji_style',
|
||||
},
|
||||
},
|
||||
render(args) {
|
||||
|
||||
Reference in New Issue
Block a user