0
# Story Composition & CSF
1
2
Utilities for creating portable stories, composing story configurations, and working with Component Story Format. These tools enable story reuse across different environments, testing scenarios, and documentation systems.
3
4
## Capabilities
5
6
### Story Composition
7
8
Core functions for creating composed, portable stories from CSF exports.
9
10
```typescript { .api }
11
/**
12
* Creates a composed story function from story and component annotations
13
* @param storyAnnotations - Individual story configuration
14
* @param componentAnnotations - Component-level meta configuration
15
* @param projectAnnotations - Global project configuration
16
* @param defaultConfig - Default fallback configuration
17
* @param exportsName - Name of the story export for debugging
18
* @returns Executable story function with metadata
19
*/
20
function composeStory<TRenderer>(
21
storyAnnotations: StoryAnnotations<TRenderer, any>,
22
componentAnnotations: ComponentAnnotations<TRenderer, any>,
23
projectAnnotations?: ProjectAnnotations<TRenderer>,
24
defaultConfig?: ProjectAnnotations<TRenderer>,
25
exportsName?: string
26
): ComposedStoryFn<TRenderer, any>;
27
28
/**
29
* Composes all stories from a story module
30
* @param storiesImport - Imported stories module (*.stories.js)
31
* @param globalConfig - Global project annotations
32
* @param composeStoryFn - Custom compose function (defaults to composeStory)
33
* @returns Object mapping story names to composed story functions
34
*/
35
function composeStories<TModule>(
36
storiesImport: TModule,
37
globalConfig: ProjectAnnotations<any>,
38
composeStoryFn?: Function
39
): Record<string, ComposedStoryFn<any, any>>;
40
41
interface ComposedStoryFn<TRenderer = any, TArgs = any> {
42
/** Execute the story with optional args override */
43
(args?: Partial<TArgs>): any;
44
/** Story display name */
45
storyName?: string;
46
/** Default story args */
47
args?: TArgs;
48
/** Story parameters */
49
parameters?: Parameters;
50
/** Story arg types */
51
argTypes?: ArgTypes;
52
/** Story ID */
53
id?: string;
54
}
55
```
56
57
**Usage Examples:**
58
59
```typescript
60
import { composeStory, composeStories } from "@storybook/preview-api";
61
import { render, screen } from "@testing-library/react";
62
import type { Meta, StoryObj } from '@storybook/react';
63
64
// Import your stories
65
import * as ButtonStories from './Button.stories';
66
import globalConfig from '../.storybook/preview';
67
68
// Compose individual story
69
const meta: Meta<typeof Button> = ButtonStories.default;
70
const Primary = composeStory(ButtonStories.Primary, meta, globalConfig);
71
72
// Use in tests
73
test('Primary button renders correctly', () => {
74
render(<Primary />);
75
expect(screen.getByRole('button')).toBeInTheDocument();
76
});
77
78
test('Primary button with custom args', () => {
79
render(<Primary args={{ label: 'Custom Label', disabled: true }} />);
80
expect(screen.getByRole('button')).toBeDisabled();
81
});
82
83
// Compose all stories from module
84
const composedStories = composeStories(ButtonStories, globalConfig);
85
86
// Iterate through all stories
87
Object.entries(composedStories).forEach(([name, Story]) => {
88
test(`${name} story renders without errors`, () => {
89
render(<Story />);
90
expect(screen.getByRole('button')).toBeInTheDocument();
91
});
92
});
93
```
94
95
### Project Configuration
96
97
Functions for setting global project annotations and default configurations.
98
99
```typescript { .api }
100
/**
101
* Sets global project annotations for story composition
102
* @param projectAnnotations - Global configuration for all stories
103
*/
104
function setProjectAnnotations<TRenderer>(projectAnnotations: ProjectAnnotations<TRenderer>): void;
105
106
/**
107
* Sets default project annotations as fallback configuration
108
* @param defaultProjectAnnotations - Default configuration when none provided
109
*/
110
function setDefaultProjectAnnotations<TRenderer>(
111
defaultProjectAnnotations: ProjectAnnotations<TRenderer>
112
): void;
113
114
interface ProjectAnnotations<TRenderer = any> {
115
/** Global parameters applied to all stories */
116
parameters?: Parameters;
117
/** Global decorators applied to all stories */
118
decorators?: DecoratorFunction<TRenderer>[];
119
/** Global args applied to all stories */
120
args?: Args;
121
/** Global arg types applied to all stories */
122
argTypes?: ArgTypes;
123
/** Global values available to all stories */
124
globals?: Args;
125
/** Global controls for globals */
126
globalTypes?: GlobalTypes;
127
/** Story rendering function */
128
render?: (args: Args, context: StoryContext<TRenderer>) => any;
129
/** Component rendering function for autodocs */
130
component?: any;
131
}
132
```
133
134
**Usage Examples:**
135
136
```typescript
137
import { setProjectAnnotations } from "@storybook/preview-api";
138
139
// Set global configuration for portable stories
140
setProjectAnnotations({
141
parameters: {
142
actions: { argTypesRegex: '^on[A-Z].*' },
143
controls: {
144
matchers: {
145
color: /(background|color)$/i,
146
date: /Date$/,
147
},
148
},
149
},
150
decorators: [
151
(Story) => (
152
<div style={{ margin: '3rem' }}>
153
<Story />
154
</div>
155
),
156
],
157
globals: {
158
theme: 'light',
159
locale: 'en'
160
}
161
});
162
```
163
164
### Story Processing & Normalization
165
166
Low-level utilities for story preparation, normalization, and processing.
167
168
```typescript { .api }
169
/**
170
* Prepares a story for rendering by processing annotations
171
* @param storyAnnotations - Raw story annotations
172
* @param componentAnnotations - Component meta annotations
173
* @param projectAnnotations - Project-level annotations
174
* @returns Prepared story ready for rendering
175
*/
176
function prepareStory<TRenderer>(
177
storyAnnotations: StoryAnnotations<TRenderer, any>,
178
componentAnnotations: ComponentAnnotations<TRenderer, any>,
179
projectAnnotations: ProjectAnnotations<TRenderer>
180
): PreparedStory<TRenderer>;
181
182
/**
183
* Prepares component meta information
184
* @param componentAnnotations - Raw component annotations
185
* @param projectAnnotations - Project-level annotations
186
* @returns Prepared component meta
187
*/
188
function prepareMeta<TRenderer>(
189
componentAnnotations: ComponentAnnotations<TRenderer, any>,
190
projectAnnotations: ProjectAnnotations<TRenderer>
191
): PreparedMeta<TRenderer>;
192
193
/**
194
* Normalizes story annotations to standard format
195
* @param storyAnnotations - Raw story annotations
196
* @param componentAnnotations - Component meta annotations
197
* @param projectAnnotations - Project-level annotations
198
* @returns Normalized story annotations
199
*/
200
function normalizeStory<TRenderer>(
201
storyAnnotations: StoryAnnotations<TRenderer, any>,
202
componentAnnotations: ComponentAnnotations<TRenderer, any>,
203
projectAnnotations: ProjectAnnotations<TRenderer>
204
): NormalizedStoryAnnotations<TRenderer>;
205
206
/**
207
* Normalizes project annotations to standard format
208
* @param projectAnnotations - Raw project annotations
209
* @returns Normalized project annotations
210
*/
211
function normalizeProjectAnnotations<TRenderer>(
212
projectAnnotations: ProjectAnnotations<TRenderer>
213
): NormalizedProjectAnnotations<TRenderer>;
214
```
215
216
### Configuration Composition
217
218
Utilities for combining and composing multiple configuration objects.
219
220
```typescript { .api }
221
/**
222
* Composes multiple configuration objects safely
223
* @param configs - Configuration objects to combine
224
* @returns Combined configuration object
225
*/
226
function composeConfigs(...configs: any[]): any;
227
228
/**
229
* Composes step runner functions for play function execution
230
* @param runners - Step runner functions to combine
231
* @returns Combined step runner function
232
*/
233
function composeStepRunners(...runners: Function[]): Function;
234
```
235
236
### Args & Parameters Utilities
237
238
Functions for working with story arguments and parameters.
239
240
```typescript { .api }
241
/**
242
* Safely combines argument objects, handling special cases
243
* @param value - Base args object
244
* @param update - Args update to apply
245
* @returns Combined args object
246
*/
247
function combineArgs(value: Args, update: Args): Args;
248
249
/**
250
* Safely combines parameter objects with proper merging
251
* @param parameterSets - Parameter objects to combine
252
* @returns Combined parameters object
253
*/
254
function combineParameters(...parameterSets: Parameters[]): Parameters;
255
256
/**
257
* Filters argTypes based on include/exclude criteria
258
* @param argTypes - ArgTypes object to filter
259
* @param include - Properties to include (RegExp or string array)
260
* @param exclude - Properties to exclude (RegExp or string array)
261
* @returns Filtered argTypes object
262
*/
263
function filterArgTypes(
264
argTypes: ArgTypes,
265
include?: PropDescriptor,
266
exclude?: PropDescriptor
267
): ArgTypes;
268
269
/**
270
* Infers control types from argTypes definitions
271
* @param argTypes - ArgTypes to process
272
* @returns ArgTypes with inferred controls
273
*/
274
function inferControls(argTypes: ArgTypes): ArgTypes;
275
276
/**
277
* Normalizes project annotations to standard format
278
* @param projectAnnotations - Raw project annotations
279
* @returns Normalized project annotations
280
*/
281
function normalizeProjectAnnotations<TRenderer>(
282
projectAnnotations: ProjectAnnotations<TRenderer>
283
): NormalizedProjectAnnotations<TRenderer>;
284
285
type PropDescriptor = string[] | RegExp;
286
```
287
288
### Story Decoration
289
290
Functions for applying decorators to stories.
291
292
```typescript { .api }
293
/**
294
* Applies a decorator to a story function
295
* @param storyFn - Original story function
296
* @param decorator - Decorator to apply
297
* @param bindWithContext - Whether to bind with story context
298
* @returns Decorated story function
299
*/
300
function decorateStory<TRenderer>(
301
storyFn: StoryFn<TRenderer>,
302
decorator: DecoratorFunction<TRenderer>,
303
bindWithContext?: boolean
304
): StoryFn<TRenderer>;
305
306
/**
307
* Default story decoration implementation
308
* @returns Default decorator function
309
*/
310
function defaultDecorateStory<TRenderer>(): DecoratorFunction<TRenderer>;
311
312
/**
313
* Sanitizes story context updates for safety
314
* @param update - Context update object
315
* @returns Sanitized update object
316
*/
317
function sanitizeStoryContextUpdate(update: Partial<StoryContext>): Partial<StoryContext>;
318
```
319
320
### Naming & Organization
321
322
Utilities for story naming and organization.
323
324
```typescript { .api }
325
/**
326
* Determines story title from user input or auto-generation
327
* @param title - User-provided title
328
* @param specifier - File specifier for auto-title
329
* @returns Final story title
330
*/
331
function userOrAutoTitle(title: string | undefined, specifier: string): string;
332
333
/**
334
* Gets title from file specifier for auto-title generation
335
* @param specifier - File path specifier
336
* @returns Generated title
337
*/
338
function userOrAutoTitleFromSpecifier(specifier: string): string;
339
340
/**
341
* Sorts stories using Storybook v7 algorithm
342
* @param stories - Stories to sort
343
* @param storySort - Sort configuration
344
* @returns Sorted stories array
345
*/
346
function sortStoriesV7(stories: any[], storySort: any): any[];
347
```
348
349
**Usage Examples:**
350
351
```typescript
352
import { userOrAutoTitle, userOrAutoTitleFromSpecifier, sortStoriesV7 } from "@storybook/preview-api";
353
354
// Auto-generate title from file path
355
const autoTitle = userOrAutoTitleFromSpecifier('./components/Button/Button.stories.ts');
356
// Result: 'Components/Button'
357
358
// Use user title or auto-generate
359
const finalTitle = userOrAutoTitle('Custom/Button', './components/Button/Button.stories.ts');
360
// Result: 'Custom/Button'
361
362
// Sort stories with custom configuration
363
const sortedStories = sortStoriesV7(stories, {
364
method: 'alphabetical',
365
order: ['Intro', 'Components', '*', 'Examples']
366
});
367
```
368
369
## Types & Interfaces
370
371
```typescript { .api }
372
interface StoryAnnotations<TRenderer = any, TArgs = any> {
373
args?: Partial<TArgs>;
374
argTypes?: ArgTypes;
375
parameters?: Parameters;
376
decorators?: DecoratorFunction<TRenderer>[];
377
render?: (args: TArgs, context: StoryContext<TRenderer>) => any;
378
play?: (context: PlayFunctionContext<TRenderer, TArgs>) => Promise<void> | void;
379
}
380
381
interface ComponentAnnotations<TRenderer = any, TArgs = any> {
382
title?: string;
383
component?: any;
384
args?: Partial<TArgs>;
385
argTypes?: ArgTypes;
386
parameters?: Parameters;
387
decorators?: DecoratorFunction<TRenderer>[];
388
render?: (args: TArgs, context: StoryContext<TRenderer>) => any;
389
}
390
391
interface PreparedStory<TRenderer = any> {
392
id: string;
393
name: string;
394
title: string;
395
args: Args;
396
argTypes: ArgTypes;
397
parameters: Parameters;
398
component: any;
399
renderFn: Function;
400
}
401
402
interface PlayFunctionContext<TRenderer = any, TArgs = any> {
403
args: TArgs;
404
canvasElement: HTMLElement;
405
step: (label: string, play: Function) => Promise<void>;
406
}
407
408
interface NormalizedProjectAnnotations<TRenderer = any> {
409
parameters: Parameters;
410
decorators: DecoratorFunction<TRenderer>[];
411
args: Args;
412
argTypes: ArgTypes;
413
globals: Args;
414
globalTypes: GlobalTypes;
415
render?: Function;
416
component?: any;
417
}
418
```