Skip to content

Commit 50d8fd2

Browse files
authored
doc: add documentation how to write stories in shared components (#31831)
1 parent d0c800a commit 50d8fd2

1 file changed

Lines changed: 134 additions & 0 deletions

File tree

packages/shared-components/README.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,140 @@ Most components should be written as [MVVM pattern](../../docs/MVVM.md) view
121121
components. See existing components for examples. The exceptions are low level
122122
components that don't need a view model.
123123

124+
### Write Storybook Stories
125+
126+
All components should have accompanying Storybook stories for documentation and visual testing. Stories are written in TypeScript using the [Component Story Format (CSF)](https://storybook.js.org/docs/api/csf).
127+
128+
#### Story File Structure
129+
130+
Place the story file next to the component with the `.stories.tsx` extension:
131+
132+
```
133+
MyComponent/
134+
├── MyComponent.tsx
135+
├── MyComponent.module.css
136+
└── MyComponent.stories.tsx
137+
```
138+
139+
#### Regular Component Stories
140+
141+
For regular React components (non-MVVM), create stories by defining a meta object and story variations:
142+
143+
```tsx
144+
import type { Meta, StoryObj } from "@storybook/react-vite";
145+
import { fn } from "storybook/test";
146+
import { MyComponent } from "./MyComponent";
147+
148+
const meta = {
149+
title: "Category/MyComponent",
150+
component: MyComponent,
151+
tags: ["autodocs"],
152+
args: {
153+
// Default args for all stories
154+
label: "Default Label",
155+
onClick: fn(), // Mock function for tracking interactions
156+
},
157+
} satisfies Meta<typeof MyComponent>;
158+
159+
export default meta;
160+
type Story = StoryObj<typeof meta>;
161+
162+
// Default story uses the default args
163+
export const Default: Story = {};
164+
165+
// Override specific args for variations
166+
export const WithCustomLabel: Story = {
167+
args: {
168+
label: "Custom Label",
169+
},
170+
};
171+
172+
export const Disabled: Story = {
173+
args: {
174+
disabled: true,
175+
},
176+
};
177+
```
178+
179+
#### MVVM Component Stories
180+
181+
For MVVM components, create a wrapper component that uses `useMockedViewModel`:
182+
183+
```tsx
184+
import React, { type JSX } from "react";
185+
import { fn } from "storybook/test";
186+
import type { Meta, StoryFn } from "@storybook/react-vite";
187+
import { MyComponentView, type MyComponentViewSnapshot, type MyComponentViewActions } from "./MyComponentView";
188+
import { useMockedViewModel } from "../../useMockedViewModel";
189+
190+
// Combine snapshot and actions for easier typing
191+
type MyComponentProps = MyComponentViewSnapshot & MyComponentViewActions;
192+
193+
// Wrapper component that creates a mocked ViewModel
194+
const MyComponentViewWrapper = ({ onAction, ...rest }: MyComponentProps): JSX.Element => {
195+
const vm = useMockedViewModel(rest, {
196+
onAction,
197+
});
198+
return <MyComponentView vm={vm} />;
199+
};
200+
201+
export default {
202+
title: "Category/MyComponentView",
203+
component: MyComponentViewWrapper,
204+
tags: ["autodocs"],
205+
args: {
206+
// Snapshot properties (state)
207+
title: "Default Title",
208+
isLoading: false,
209+
// Action properties (callbacks)
210+
onAction: fn(),
211+
},
212+
} as Meta<typeof MyComponentViewWrapper>;
213+
214+
const Template: StoryFn<typeof MyComponentViewWrapper> = (args) => <MyComponentViewWrapper {...args} />;
215+
216+
export const Default = Template.bind({});
217+
218+
export const Loading = Template.bind({});
219+
Loading.args = {
220+
isLoading: true,
221+
};
222+
```
223+
224+
Thanks to this approach, we can directly use primitives in the story arguments instead of a view model object.
225+
226+
#### Linking Figma Designs
227+
228+
This package uses [@storybook/addon-designs](https://github.com/storybookjs/addon-designs) to embed Figma designs directly in Storybook. This helps developers compare their implementation with the design specs.
229+
230+
1. **Get the Figma URL**: Open your design in Figma, click "Share" → "Copy link"
231+
2. **Add to story parameters**: Include the `design` object in the meta's `parameters`
232+
3. **Supported URL formats**:
233+
- File links: `https://www.figma.com/file/...`
234+
- Design links: `https://www.figma.com/design/...`
235+
- Specific node: `https://www.figma.com/design/...?node-id=123-456`
236+
237+
Example with Figma integration:
238+
239+
```tsx
240+
export default {
241+
title: "Room List/RoomListSearchView",
242+
component: RoomListSearchViewWrapper,
243+
tags: ["autodocs"],
244+
args: {
245+
// ... your args
246+
},
247+
parameters: {
248+
design: {
249+
type: "figma",
250+
url: "https://www.figma.com/design/vlmt46QDdE4dgXDiyBJXqp/ER-33-Left-Panel?node-id=98-1979",
251+
},
252+
},
253+
} as Meta<typeof RoomListSearchViewWrapper>;
254+
```
255+
256+
The Figma design will appear in the "Design" tab in Storybook.
257+
124258
### Tests
125259

126260
Two types of tests are available: unit tests and visual regression tests.

0 commit comments

Comments
 (0)