diff --git a/packages/components/src/font-size-picker/stories/index.js b/packages/components/src/font-size-picker/stories/index.js index c124fb03acc559..5036fa390c430b 100644 --- a/packages/components/src/font-size-picker/stories/index.js +++ b/packages/components/src/font-size-picker/stories/index.js @@ -91,20 +91,19 @@ WithSlider.args = { withSlider: true, }; +/** + * With custom font sizes disabled via the `disableCustomFontSizes` prop, the user will + * only be able to pick one of the predefined sizes passed in `fontSizes`. + */ export const WithCustomSizesDisabled = FontSizePickerWithState.bind( {} ); WithCustomSizesDisabled.args = { ...Default.args, disableCustomFontSizes: true, }; -WithCustomSizesDisabled.parameters = { - docs: { - description: { - story: - 'With custom font sizes disabled via the `disableCustomFontSizes` prop, the user will only be able to pick one of the predefined sizes passed in `fontSizes`.', - }, - }, -}; +/** + * When there are more than 5 font size options, the UI is no longer a toggle group. + */ export const WithMoreFontSizes = FontSizePickerWithState.bind( {} ); WithMoreFontSizes.args = { ...Default.args, @@ -142,15 +141,10 @@ WithMoreFontSizes.args = { ], initialValue: 8, }; -WithMoreFontSizes.parameters = { - docs: { - description: { - story: - 'When there are more than 5 font size options, the UI is no longer a toggle group.', - }, - }, -}; +/** + * When units like `px` are specified explicitly, it will be shown as a label hint. + */ export const WithUnits = TwoFontSizePickersWithState.bind( {} ); WithUnits.args = { ...WithMoreFontSizes.args, @@ -160,15 +154,11 @@ WithUnits.args = { } ) ), initialValue: '8px', }; -WithUnits.parameters = { - docs: { - description: { - story: - 'When units like `px` are specified explicitly, it will be shown as a label hint.', - }, - }, -}; +/** + * The label hint will not be shown if it is a complex CSS value. Some examples of complex CSS values + * in this context are CSS functions like `calc()`, `clamp()`, and `var()`. + */ export const WithComplexCSSValues = TwoFontSizePickersWithState.bind( {} ); WithComplexCSSValues.args = { ...Default.args, @@ -207,11 +197,3 @@ WithComplexCSSValues.args = { ], initialValue: '1.125rem', }; -WithComplexCSSValues.parameters = { - docs: { - description: { - story: - 'The label hint will not be shown if it is a complex CSS value. Some examples of complex CSS values in this context are CSS functions like `calc()`, `clamp()`, and `var()`.', - }, - }, -}; diff --git a/storybook/webpack.config.js b/storybook/webpack.config.js index 74f5128e9b1cd3..000c6930574f9b 100644 --- a/storybook/webpack.config.js +++ b/storybook/webpack.config.js @@ -29,10 +29,21 @@ const scssLoaders = ( { isLazy } ) => [ module.exports = ( { config } ) => { config.module.rules.push( { - test: /\/stories\/.+\.js$/, + // Currently does not work with our tsx stories + // See https://github.com/storybookjs/storybook/issues/17275 + test: /\/stories\/.+\.(j|t)sx?$/, loader: require.resolve( '@storybook/source-loader' ), enforce: 'pre', }, + { + // Allows a story description to be written as a doc comment above the exported story + test: /\/stories\/.+\.(j|t)sx?$/, + loader: path.resolve( + __dirname, + './webpack/description-loader.js' + ), + enforce: 'post', + }, { test: /\.scss$/, exclude: /\.lazy\.scss$/, diff --git a/storybook/webpack/description-loader.js b/storybook/webpack/description-loader.js new file mode 100644 index 00000000000000..bb72844836caf0 --- /dev/null +++ b/storybook/webpack/description-loader.js @@ -0,0 +1,94 @@ +/** + * Allows a story description to be written as a doc comment above the exported story. + * + * Based on https://github.com/izhan/storybook-description-loader + * + * @example + * ```jsx + * // This comment will become the description for the story in the generated docs. + * export const MyStory = Template.bind({}); + * ``` + */ + +/** + * External dependencies + */ +const babel = require( '@babel/core' ); + +function createDescriptionNode( name, description ) { + return babel.types.expressionStatement( + babel.types.assignmentExpression( + '=', + babel.types.memberExpression( + babel.types.identifier( name ), + babel.types.identifier( 'story' ) + ), + babel.types.objectExpression( [ + babel.types.objectProperty( + babel.types.identifier( 'parameters' ), + babel.types.objectExpression( [ + babel.types.objectProperty( + babel.types.identifier( 'docs' ), + babel.types.objectExpression( [ + babel.types.objectProperty( + babel.types.identifier( + 'storyDescription' + ), + babel.types.stringLiteral( description ) + ), + ] ) + ), + ] ) + ), + ] ) + ) + ); +} + +function annotateDescriptionPlugin() { + return { + visitor: { + ExportNamedDeclaration( path ) { + if ( path.node.leadingComments ) { + const commentValues = path.node.leadingComments.map( + ( node ) => { + if ( node.type === 'CommentLine' ) { + return node.value.trimLeft(); + } + // else, node.type === 'CommentBlock' + return node.value + .split( '\n' ) + .map( ( line ) => { + // stripping out the whitespace and * from comment blocks + return line.replace( + /^(\s+)?(\*+)?(\s+)?/, + '' + ); + } ) + .join( '\n' ) + .trim(); + } + ); + const description = commentValues.join( '\n' ); + const declaration = path.node.declaration.declarations[ 0 ]; + + path.insertAfter( + createDescriptionNode( + declaration.id.name, + description + ) + ); + } + }, + }, + }; +} + +module.exports = function ( source ) { + const output = babel.transform( source, { + plugins: [ annotateDescriptionPlugin ], + filename: __filename, + sourceType: 'module', + } ); + return output.code; +};