Skip to content

Commit c30f136

Browse files
committed
doc: add documentation how to write stories in shared components
1 parent 819d361 commit c30f136

1 file changed

Lines changed: 153 additions & 0 deletions

File tree

packages/shared-components/README.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,159 @@ 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 {
188+
MyComponentView,
189+
type MyComponentViewSnapshot,
190+
type MyComponentViewActions
191+
} from "./MyComponentView";
192+
import { useMockedViewModel } from "../../useMockedViewModel";
193+
194+
// Combine snapshot and actions for easier typing
195+
type MyComponentProps = MyComponentViewSnapshot & MyComponentViewActions;
196+
197+
// Wrapper component that creates a mocked ViewModel
198+
const MyComponentViewWrapper = ({
199+
onAction,
200+
...rest
201+
}: MyComponentProps): JSX.Element => {
202+
const vm = useMockedViewModel(rest, {
203+
onAction,
204+
});
205+
return <MyComponentView vm={vm} />;
206+
};
207+
208+
export default {
209+
title: "Category/MyComponentView",
210+
component: MyComponentViewWrapper,
211+
tags: ["autodocs"],
212+
args: {
213+
// Snapshot properties (state)
214+
title: "Default Title",
215+
isLoading: false,
216+
// Action properties (callbacks)
217+
onAction: fn(),
218+
},
219+
} as Meta<typeof MyComponentViewWrapper>;
220+
221+
const Template: StoryFn<typeof MyComponentViewWrapper> = (args) =>
222+
<MyComponentViewWrapper {...args} />;
223+
224+
export const Default = Template.bind({});
225+
226+
export const Loading = Template.bind({});
227+
Loading.args = {
228+
isLoading: true,
229+
};
230+
```
231+
232+
#### Linking Figma Designs
233+
234+
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.
235+
236+
1. **Get the Figma URL**: Open your design in Figma, click "Share" → "Copy link"
237+
2. **Add to story parameters**: Include the `design` object in the meta's `parameters`
238+
3. **Supported URL formats**:
239+
- File links: `https://www.figma.com/file/...`
240+
- Design links: `https://www.figma.com/design/...`
241+
- Specific node: `https://www.figma.com/design/...?node-id=123-456`
242+
243+
Example with Figma integration:
244+
245+
```tsx
246+
export default {
247+
title: "Room List/RoomListSearchView",
248+
component: RoomListSearchViewWrapper,
249+
tags: ["autodocs"],
250+
args: {
251+
// ... your args
252+
},
253+
parameters: {
254+
design: {
255+
type: "figma",
256+
url: "https://www.figma.com/design/vlmt46QDdE4dgXDiyBJXqp/ER-33-Left-Panel?node-id=98-1979",
257+
},
258+
},
259+
} as Meta<typeof RoomListSearchViewWrapper>;
260+
```
261+
262+
The Figma design will appear in the "Design" tab in Storybook, allowing side-by-side comparison.
263+
264+
```
265+
266+
#### Best Practices
267+
268+
1. **Cover all states**: Create stories for default, loading, error, and edge cases
269+
2. **Use semantic names**: Story names should describe what they demonstrate
270+
3. **Include interactions**: Use `fn()` for all callbacks to enable interaction testing
271+
4. **Document stories**: Add JSDoc comments to explain non-obvious story purposes
272+
5. **Keep it simple**: Each story should demonstrate one specific state or variant
273+
6. **Test accessibility**: Visual regression tests will check for AXE violations
274+
7. **Link Figma designs**: Always include the Figma design link in parameters when available
275+
8. **Mock dependencies**: Use `useMockedViewModel` for MVVM or mock external dependencies
276+
124277
### Tests
125278
126279
Two types of tests are available: unit tests and visual regression tests.

0 commit comments

Comments
 (0)