UNPKG

@storybook/angular

Version:

Storybook for Angular: Develop Angular components in isolation with hot reloading.

133 lines (132 loc) 5.59 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.computesTemplateSourceFromComponent = exports.computesTemplateFromComponent = void 0; const NgComponentAnalyzer_1 = require("./utils/NgComponentAnalyzer"); const separateInputsOutputsAttributes = (ngComponentInputsOutputs, props = {}) => { const inputs = ngComponentInputsOutputs.inputs .filter((i) => i.templateName in props) .map((i) => i.templateName); const outputs = ngComponentInputsOutputs.outputs .filter((o) => o.templateName in props) .map((o) => o.templateName); return { inputs, outputs, otherProps: Object.keys(props).filter((k) => ![...inputs, ...outputs].includes(k)), }; }; /** * Converts a component into a template with inputs/outputs present in initial props * @param component * @param initialProps * @param innerTemplate */ const computesTemplateFromComponent = (component, initialProps, innerTemplate = '') => { const ngComponentMetadata = (0, NgComponentAnalyzer_1.getComponentDecoratorMetadata)(component); const ngComponentInputsOutputs = (0, NgComponentAnalyzer_1.getComponentInputsOutputs)(component); if (!ngComponentMetadata.selector) { // Allow to add renderer component when NgComponent selector is undefined return `<ng-container *ngComponentOutlet="storyComponent"></ng-container>`; } const { inputs: initialInputs, outputs: initialOutputs } = separateInputsOutputsAttributes(ngComponentInputsOutputs, initialProps); const templateInputs = initialInputs.length > 0 ? ` ${initialInputs.map((i) => `[${i}]="${i}"`).join(' ')}` : ''; const templateOutputs = initialOutputs.length > 0 ? ` ${initialOutputs.map((i) => `(${i})="${i}($event)"`).join(' ')}` : ''; return buildTemplate(ngComponentMetadata.selector, innerTemplate, templateInputs, templateOutputs); }; exports.computesTemplateFromComponent = computesTemplateFromComponent; const createAngularInputProperty = ({ propertyName, value, argType, }) => { let templateValue; switch (typeof value) { case 'string': templateValue = `'${value}'`; break; case 'object': templateValue = JSON.stringify(value) .replace(/'/g, '\u2019') .replace(/\\"/g, '\u201D') .replace(/"([^-"]+)":/g, '$1: ') .replace(/"/g, "'") .replace(/\u2019/g, "\\'") .replace(/\u201D/g, "\\'") .split(',') .join(', '); break; default: templateValue = value; } return `[${propertyName}]="${templateValue}"`; }; /** * Converts a component into a template with inputs/outputs present in initial props * @param component * @param initialProps * @param innerTemplate */ const computesTemplateSourceFromComponent = (component, initialProps, argTypes) => { const ngComponentMetadata = (0, NgComponentAnalyzer_1.getComponentDecoratorMetadata)(component); if (!ngComponentMetadata) { return null; } if (!ngComponentMetadata.selector) { // Allow to add renderer component when NgComponent selector is undefined return `<ng-container *ngComponentOutlet="${component.name}"></ng-container>`; } const ngComponentInputsOutputs = (0, NgComponentAnalyzer_1.getComponentInputsOutputs)(component); const { inputs: initialInputs, outputs: initialOutputs } = separateInputsOutputsAttributes(ngComponentInputsOutputs, initialProps); const templateInputs = initialInputs.length > 0 ? ` ${initialInputs .map((propertyName) => createAngularInputProperty({ propertyName, value: initialProps[propertyName], argType: argTypes?.[propertyName], })) .join(' ')}` : ''; const templateOutputs = initialOutputs.length > 0 ? ` ${initialOutputs.map((i) => `(${i})="${i}($event)"`).join(' ')}` : ''; return buildTemplate(ngComponentMetadata.selector, '', templateInputs, templateOutputs); }; exports.computesTemplateSourceFromComponent = computesTemplateSourceFromComponent; const buildTemplate = (selector, innerTemplate, inputs, outputs) => { // https://www.w3.org/TR/2011/WD-html-markup-20110113/syntax.html#syntax-elements const voidElements = [ 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr', ]; const firstSelector = selector.split(',')[0]; const templateReplacers = [ [/(^.*?)(?=[,])/, '$1'], [/(^\..+)/, 'div$1'], [/(^\[.+?])/, 'div$1'], [/([\w[\]]+)(\s*,[\w\s-[\],]+)+/, `$1`], [/#([\w-]+)/, ` id="$1"`], [/((\.[\w-]+)+)/, (_, c) => ` class="${c.split `.`.join ` `.trim()}"`], [/(\[.+?])/g, (_, a) => ` ${a.slice(1, -1)}`], [ /([\S]+)(.*)/, (template, elementSelector) => { return voidElements.some((element) => elementSelector === element) ? template.replace(/([\S]+)(.*)/, `<$1$2${inputs}${outputs} />`) : template.replace(/([\S]+)(.*)/, `<$1$2${inputs}${outputs}>${innerTemplate}</$1>`); }, ], ]; return templateReplacers.reduce((prevSelector, [searchValue, replacer]) => prevSelector.replace(searchValue, replacer), firstSelector); };