How can I create a story for a standalone Angular pipe? #32316
Replies: 2 comments 5 replies
-
Hi @russelporosky! I'm Dosu and I’m helping the storybook team. To create a Storybook story for a standalone Angular pipe and display its TSDoc documentation, make sure you add the pipe to the const meta: Meta<NumberFormatPipe> = {
component: NumberFormatPipe,
decorators: [
moduleMetadata({
imports: [NumberFormatPipe],
}),
],
title: 'ARC/Pipes/Number Format Pipe',
tags: ['pipes'],
};
export default meta;
export const Default: StoryObj<NumberFormatPipe> = {
render: () => ({
template: `
<p>{{ 123456 | numberFormat:'CURRENCY' }}</p>
<p>{{ 0.123456 | numberFormat:'PERCENTAGE' }}</p>
`,
}),
}; If you use a wrapper component, Storybook Docs will show documentation for the wrapper, not the pipe. To surface the pipe's TSDoc, set the pipe as the To reply, just mention @dosu. How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other |
Beta Was this translation helpful? Give feedback.
-
@russelporosky what I do with standalone Pipes is the following:
Example: import { Meta, StoryObj } from '@storybook/angular';
/**
* The numbers pipe helps format numbers.
*/
const meta: Meta<RealNumbersPipe> = {
tags: [
'!dev',
'numbers',
'Pipe',
],
id: 'real-numbers-pipe',
component: RealNumbersPipe,
};
export default meta;
type Story = StoryObj<RealNumbersPipe>;
export const Default: Story = {}; then, the "demo Pipe" as numbersPipeDemo.stories.tsx - set Inputs in the wrapper component and take the wrapper as the storyObj, or, just write the Argtypes manually so users can toggle some stuff of the pipe transform method ... if you won't need to deep dive into the transform method of the pipe, you could also import the "realPipeStory" into this story and set Argtypes: {...realPipeStory.default (or meta??).Argtypes}, i think, to infer. import { Meta, moduleMetadata, StoryObj } from '@storybook/angular';
const meta: Meta = {
tags: ['!dev', '!autodocs'],
id: 'numbers-pipe-demo',
decorators: [
moduleMetadata({
imports: [RealNumbersPipe],
}),
],
argTypes: {
style: {
description: `The number format style to use.
- **decimal**: Formats the number as a decimal number.
- **currency**: Formats the number as a currency value.
- **percent**: Formats the number as a percentage.
`,
control: { type: 'select' },
options: ['decimal', 'currency', 'percent'],
table: {
defaultValue: {
summary: 'config.numberFormatOptions.style',
detail: JSON.stringify(
getConfig().numberFormatOptions.style,
null,
2,
),
},
},
},
withUnitSymbol: {
description: 'Whether to display the unit symbol (e.g., EUR, CHF, %).',
table: {
defaultValue: { summary: 'true' },
},
},
},
};
export default meta;
type Story = StoryObj;
export const Default: Story = {
args: {
exampleValue: 1234567890.1234567,
style: 'currency',
withUnitSymbol: true,
numberFormatOptions: {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
signDisplay: 'never',
},
currencyFormatOptions: {
currency: 'EUR',
currencyDisplay: 'code',
locales: 'de-DE',
},
},
render: (args) => ({
props: args,
template: `<div>{{ ${args['exampleValue']} | realnumbersPipe : '${args['style']}' : ${args['withUnitSymbol']}
: { minimumFractionDigits: ${args['numberFormatOptions'].minimumFractionDigits}, maximumFractionDigits: ${args['numberFormatOptions'].maximumFractionDigits}, signDisplay: '${args['numberFormatOptions'].signDisplay}' }
: {currency: '${args['currencyFormatOptions'].currency}', currencyDisplay: '${args['currencyFormatOptions'].currencyDisplay}', locales: '${args['currencyFormatOptions'].locales}'}
}}</div>`,
}),
}; And then, the final composing into a docs story file (docs.mdx) with all documentation and story toggling in mdx instead of automatic autodocs: import * as NumbersPipe from './NumbersPipe.stories';
import * as Demo from './NumbersPipeDemo.stories';
<Meta of={NumbersPipe} />
<Unstyled>
<Title />
<Subtitle />
<Description />
The [**Default-Values**](/docs/components-configs-defaultconfig--docs) of the **RealNumbersPipe** can be set globally.
<Heading>API</Heading>
<ArgTypes of={NumbersPipe.default} />
<Heading>Usage</Heading>
The pipe can be used in TypeScript files or in HTML templates.
<Heading>Demo-Story</Heading>
Interactive Demo to toggle some options of the NumbersPipe.
<Canvas of={Demo.Default} />
<Controls of={Demo.Default} />
<Source of={Demo.Default} />
</Unstyled> hope this helps! |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Summary
I'd like to create a story to show various flags in a custom pipe, while including all the TSDoc information from the pipe. I find that if I create a wrapper component within the story, the pipe will work but none of the documentation appears. If I don't add a wrapper (or I keep the wrapper and change the render to include it around the sample pipe lines), Storybook will compile fine, but the stories won't display and show an error:
Error: Unexpected "NumberFormatPipe" found in the "declarations" array of the "StorybookComponentModule" NgModule, "NumberFormatPipe" is marked as standalone and can't be declared in any NgModule - did you intend to import it instead (by adding it to the "imports" array)?
.I'm using the latest versions of both Storybook and Angular.
Additional information
This is the story file:
The complete error within the Storybook page is:
Error: Unexpected "SbNumberFormatPipeHost" found in the "declarations" array of the "StorybookComponentModule" NgModule, "SbNumberFormatPipeHost" is marked as standalone and can't be declared in any NgModule - did you intend to import it instead (by adding it to the "imports" array)? at StorybookComponentModule.get (/vendors-node_modules_pnpm_storybook_addon-a11y_9_0_18_storybook_9_0_18__testing-library_dom_1-f0841d.iframe.bundle.js:75492:22)) at getInjectorDef (/vendors-node_modules_pnpm_storybook_addon-a11y_9_0_18_storybook_9_0_18__testing-library_dom_1-f0841d.iframe.bundle.js:80817:56)) at walkProviderTree (/vendors-node_modules_pnpm_storybook_addon-a11y_9_0_18_storybook_9_0_18__testing-library_dom_1-f0841d.iframe.bundle.js:81990:16)) at walkProviderTree (/vendors-node_modules_pnpm_storybook_addon-a11y_9_0_18_storybook_9_0_18__testing-library_dom_1-f0841d.iframe.bundle.js:82028:9)) at /vendors-node_modules_pnpm_storybook_addon-a11y_9_0_18_storybook_9_0_18__testing-library_dom_1-f0841d.iframe.bundle.js:81948:9 at /vendors-node_modules_pnpm_storybook_addon-a11y_9_0_18_storybook_9_0_18__testing-library_dom_1-f0841d.iframe.bundle.js:81575:74 at Array.forEach (<anonymous>)) at deepForEach (/vendors-node_modules_pnpm_storybook_addon-a11y_9_0_18_storybook_9_0_18__testing-library_dom_1-f0841d.iframe.bundle.js:81575:9)) at internalImportProvidersFrom (/vendors-node_modules_pnpm_storybook_addon-a11y_9_0_18_storybook_9_0_18__testing-library_dom_1-f0841d.iframe.bundle.js:81939:3))
Create a reproduction
No response
Beta Was this translation helpful? Give feedback.
All reactions