UNPKG

2.37 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.argsToTemplate = void 0;
4/**
5 * Converts an object of arguments to a string of property and event bindings and excludes undefined values.
6 * Why? Because Angular treats undefined values in property bindings as an actual value
7 * and does not apply the default value of the property as soon as the binding is set.
8 * This feels counter-intuitive and is a common source of bugs in stories.
9 * @example
10 * ```ts
11 * // component.ts
12 *ㅤ@Component({ selector: 'example' })
13 * export class ExampleComponent {
14 * ㅤ@Input() input1: string = 'Default Input1';
15 * ㅤ@Input() input2: string = 'Default Input2';
16 * ㅤ@Output() click = new EventEmitter();
17 * }
18 *
19 * // component.stories.ts
20 * import { argsToTemplate } from '@storybook/angular';
21 * export const Input1: Story = {
22 * render: (args) => ({
23 * props: args,
24 * // Problem1: <example [input1]="input1" [input2]="input2" (click)="click($event)"></example>
25 * // This will set input2 to undefined and the internal default value will not be used.
26 * // Problem2: <example [input1]="input1" (click)="click($event)"></example>
27 * // The default value of input2 will be used, but it is not overridable by the user via controls.
28 * // Solution: Now the controls will be applicable to both input1 and input2, and the default values will be used if the user does not override them.
29 * template: `<example ${argsToTemplate(args)}"></example>`,
30 * }),
31 * args: {
32 * // In this Story, we want to set the input1 property, and the internal default property of input2 should be used.
33 * input1: 'Input 1',
34 * click: { action: 'clicked' },
35 * },
36 *};
37 * ```
38 */
39function argsToTemplate(args, options = {}) {
40 const includeSet = options.include ? new Set(options.include) : null;
41 const excludeSet = options.exclude ? new Set(options.exclude) : null;
42 return Object.entries(args)
43 .filter(([key]) => args[key] !== undefined)
44 .filter(([key]) => {
45 if (includeSet)
46 return includeSet.has(key);
47 if (excludeSet)
48 return !excludeSet.has(key);
49 return true;
50 })
51 .map(([key, value]) => typeof value === 'function' ? `(${key})="${key}($event)"` : `[${key}]="${key}"`)
52 .join(' ');
53}
54exports.argsToTemplate = argsToTemplate;