UNPKG

@storybook/addon-docs

Version:

Document component usage and properties in Markdown

187 lines (151 loc) 4.57 kB
import { addons, useEffect } from '@storybook/addons'; import { SourceType, SNIPPET_RENDERED } from '../../shared'; /** * Check if the sourcecode should be generated. * * @param context StoryContext */ const skipSourceRender = context => { var _context$parameters$d; const sourceParams = context === null || context === void 0 ? void 0 : (_context$parameters$d = context.parameters.docs) === null || _context$parameters$d === void 0 ? void 0 : _context$parameters$d.source; const isArgsStory = context === null || context === void 0 ? void 0 : context.parameters.__isArgsStory; // always render if the user forces it if ((sourceParams === null || sourceParams === void 0 ? void 0 : sourceParams.type) === SourceType.DYNAMIC) { return false; } // never render if the user is forcing the block to render code, or // if the user provides code, or if it's not an args story. return !isArgsStory || (sourceParams === null || sourceParams === void 0 ? void 0 : sourceParams.code) || (sourceParams === null || sourceParams === void 0 ? void 0 : sourceParams.type) === SourceType.CODE; }; /** * Transform a key/value to a svelte declaration as string. * * Default values are ommited * * @param key Key * @param value Value * @param argTypes Component ArgTypes */ function toSvelteProperty(key, value, argTypes) { if (value === undefined || value === null) { return null; } // default value ? if (argTypes[key] && argTypes[key].defaultValue === value) { return null; } if (value === true) { return key; } if (typeof value === 'string') { return `${key}=${JSON.stringify(value)}`; } return `${key}={${JSON.stringify(value)}}`; } /** * Extract a component name. * * @param component Component */ function getComponentName(component) { if (component == null) { return null; } const { __docgen = {} } = component; let { name } = __docgen; if (!name) { return component.name; } if (name.endsWith('.svelte')) { name = name.substring(0, name.length - 7); } return name; } /** * Generate a svelte template. * * @param component Component * @param args Args * @param argTypes ArgTypes * @param slotProperty Property used to simulate a slot */ export function generateSvelteSource(component, args, argTypes, slotProperty) { const name = getComponentName(component); if (!name) { return null; } const props = Object.entries(args).filter(([k]) => k !== slotProperty).map(([k, v]) => toSvelteProperty(k, v, argTypes)).filter(p => p).join(' '); const slotValue = slotProperty ? args[slotProperty] : null; if (slotValue) { return `<${name} ${props}>\n ${slotValue}\n</${name}>`; } return `<${name} ${props}/>`; } /** * Check if the story component is a wrapper to the real component. * * A component can be annoted with @wrapper to indicate that * it's just a wrapper for the real tested component. If it's the case * then the code generated references the real component, not the wrapper. * * moreover, a wrapper can annotate a property with @slot : this property * is then assumed to be an alias to the default slot. * * @param component Component */ function getWrapperProperties(component) { const { __docgen } = component; if (!__docgen) { return { wrapper: false }; } // the component should be declared as a wrapper if (!__docgen.keywords.find(kw => kw.name === 'wrapper')) { return { wrapper: false }; } const slotProp = __docgen.data.find(prop => prop.keywords.find(kw => kw.name === 'slot')); return { wrapper: true, slotProperty: slotProp === null || slotProp === void 0 ? void 0 : slotProp.name }; } /** * Svelte source decorator. * @param storyFn Fn * @param context StoryContext */ export const sourceDecorator = (storyFn, context) => { const channel = addons.getChannel(); const skip = skipSourceRender(context); const story = storyFn(); let source; useEffect(() => { if (!skip && source) { channel.emit(SNIPPET_RENDERED, (context || {}).id, source); } }); if (skip) { return story; } const { parameters = {}, args = {} } = context || {}; let { Component: component = {} } = story; const { wrapper, slotProperty } = getWrapperProperties(component); if (wrapper) { component = parameters.component; } source = generateSvelteSource(component, args, context === null || context === void 0 ? void 0 : context.argTypes, slotProperty); return story; };