Skip to content

Commit 695136b

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

1 file changed

Lines changed: 142 additions & 0 deletions

File tree

packages/shared-components/README.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,148 @@ 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+
Thanks to this approach, we can directly use primitives in the story arguments instead of a view model object.
233+
234+
#### Linking Figma Designs
235+
236+
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.
237+
238+
1. **Get the Figma URL**: Open your design in Figma, click "Share" → "Copy link"
239+
2. **Add to story parameters**: Include the `design` object in the meta's `parameters`
240+
3. **Supported URL formats**:
241+
- File links: `https://www.figma.com/file/...`
242+
- Design links: `https://www.figma.com/design/...`
243+
- Specific node: `https://www.figma.com/design/...?node-id=123-456`
244+
245+
Example with Figma integration:
246+
247+
```tsx
248+
export default {
249+
title: "Room List/RoomListSearchView",
250+
component: RoomListSearchViewWrapper,
251+
tags: ["autodocs"],
252+
args: {
253+
// ... your args
254+
},
255+
parameters: {
256+
design: {
257+
type: "figma",
258+
url: "https://www.figma.com/design/vlmt46QDdE4dgXDiyBJXqp/ER-33-Left-Panel?node-id=98-1979",
259+
},
260+
},
261+
} as Meta<typeof RoomListSearchViewWrapper>;
262+
```
263+
264+
The Figma design will appear in the "Design" tab in Storybook.
265+
124266
### Tests
125267

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

0 commit comments

Comments
 (0)