@storybook/angular 7.5.0-alpha.5 → 7.5.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/angular-beta/utils/PropertyExtractor.js +1 -1
- package/dist/client/angular-beta/utils/PropertyExtractor.test.js +12 -0
- package/dist/client/argsToTemplate.d.ts +55 -0
- package/dist/client/argsToTemplate.js +54 -0
- package/dist/client/argsToTemplate.test.d.ts +1 -0
- package/dist/client/argsToTemplate.test.js +95 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +3 -1
- package/package.json +15 -15
|
@@ -130,7 +130,7 @@ PropertyExtractor.analyzeDecorators = (component) => {
|
|
|
130
130
|
const isDirective = decorators.some((d) => _a.isDecoratorInstanceOf(d, 'Directive'));
|
|
131
131
|
const isPipe = decorators.some((d) => _a.isDecoratorInstanceOf(d, 'Pipe'));
|
|
132
132
|
const isDeclarable = isComponent || isDirective || isPipe;
|
|
133
|
-
const isStandalone = isComponent && decorators.some((d) => d.standalone);
|
|
133
|
+
const isStandalone = (isComponent || isDirective) && decorators.some((d) => d.standalone);
|
|
134
134
|
return { isDeclarable, isStandalone };
|
|
135
135
|
};
|
|
136
136
|
PropertyExtractor.isDecoratorInstanceOf = (decorator, name) => {
|
|
@@ -18,6 +18,8 @@ const StandaloneTestComponent = (0, core_1.Component)({ standalone: true })(clas
|
|
|
18
18
|
});
|
|
19
19
|
const TestDirective = (0, core_1.Directive)({})(class {
|
|
20
20
|
});
|
|
21
|
+
const StandaloneTestDirective = (0, core_1.Directive)({ standalone: true })(class {
|
|
22
|
+
});
|
|
21
23
|
const TestModuleWithDeclarations = (0, core_1.NgModule)({ declarations: [TestComponent1] })(class {
|
|
22
24
|
});
|
|
23
25
|
const TestModuleWithImportsAndProviders = (0, core_1.NgModule)({
|
|
@@ -108,6 +110,16 @@ describe('PropertyExtractor', () => {
|
|
|
108
110
|
StandaloneTestComponent,
|
|
109
111
|
]);
|
|
110
112
|
});
|
|
113
|
+
it('should return standalone directives', () => {
|
|
114
|
+
const imports = extractImports({
|
|
115
|
+
imports: [TestModuleWithImportsAndProviders],
|
|
116
|
+
}, StandaloneTestDirective);
|
|
117
|
+
expect(imports).toEqual([
|
|
118
|
+
common_1.CommonModule,
|
|
119
|
+
TestModuleWithImportsAndProviders,
|
|
120
|
+
StandaloneTestDirective,
|
|
121
|
+
]);
|
|
122
|
+
});
|
|
111
123
|
});
|
|
112
124
|
describe('extractDeclarations', () => {
|
|
113
125
|
it('should return an array of declarations that contains `storyComponent`', () => {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for controlling the behavior of the argsToTemplate function.
|
|
3
|
+
*
|
|
4
|
+
* @template T The type of the keys in the target object.
|
|
5
|
+
*/
|
|
6
|
+
export interface ArgsToTemplateOptions<T> {
|
|
7
|
+
/**
|
|
8
|
+
* An array of keys to specifically include in the output.
|
|
9
|
+
* If provided, only the keys from this array will be included in the output,
|
|
10
|
+
* irrespective of the `exclude` option. Undefined values will still be excluded from the output.
|
|
11
|
+
*/
|
|
12
|
+
include?: Array<T>;
|
|
13
|
+
/**
|
|
14
|
+
* An array of keys to specifically exclude from the output.
|
|
15
|
+
* If provided, these keys will be omitted from the output. This option is
|
|
16
|
+
* ignored if the `include` option is also provided
|
|
17
|
+
*/
|
|
18
|
+
exclude?: Array<T>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Converts an object of arguments to a string of property and event bindings and excludes undefined values.
|
|
22
|
+
* Why? Because Angular treats undefined values in property bindings as an actual value
|
|
23
|
+
* and does not apply the default value of the property as soon as the binding is set.
|
|
24
|
+
* This feels counter-intuitive and is a common source of bugs in stories.
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* // component.ts
|
|
28
|
+
*ㅤ@Component({ selector: 'example' })
|
|
29
|
+
* export class ExampleComponent {
|
|
30
|
+
* ㅤ@Input() input1: string = 'Default Input1';
|
|
31
|
+
* ㅤ@Input() input2: string = 'Default Input2';
|
|
32
|
+
* ㅤ@Output() click = new EventEmitter();
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* // component.stories.ts
|
|
36
|
+
* import { argsToTemplate } from '@storybook/angular';
|
|
37
|
+
* export const Input1: Story = {
|
|
38
|
+
* render: (args) => ({
|
|
39
|
+
* props: args,
|
|
40
|
+
* // Problem1: <example [input1]="input1" [input2]="input2" (click)="click($event)"></example>
|
|
41
|
+
* // This will set input2 to undefined and the internal default value will not be used.
|
|
42
|
+
* // Problem2: <example [input1]="input1" (click)="click($event)"></example>
|
|
43
|
+
* // The default value of input2 will be used, but it is not overridable by the user via controls.
|
|
44
|
+
* // 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.
|
|
45
|
+
* template: `<example ${argsToTemplate(args)}"></example>`,
|
|
46
|
+
* }),
|
|
47
|
+
* args: {
|
|
48
|
+
* // In this Story, we want to set the input1 property, and the internal default property of input2 should be used.
|
|
49
|
+
* input1: 'Input 1',
|
|
50
|
+
* click: { action: 'clicked' },
|
|
51
|
+
* },
|
|
52
|
+
*};
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function argsToTemplate<A extends Record<string, any>>(args: A, options?: ArgsToTemplateOptions<keyof A>): string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.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
|
+
*/
|
|
39
|
+
function 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
|
+
}
|
|
54
|
+
exports.argsToTemplate = argsToTemplate;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const argsToTemplate_1 = require("./argsToTemplate"); // adjust path
|
|
4
|
+
describe('argsToTemplate', () => {
|
|
5
|
+
it('should correctly convert args to template string and exclude undefined values', () => {
|
|
6
|
+
const args = {
|
|
7
|
+
prop1: 'value1',
|
|
8
|
+
prop2: undefined,
|
|
9
|
+
prop3: 'value3',
|
|
10
|
+
};
|
|
11
|
+
const options = {};
|
|
12
|
+
const result = (0, argsToTemplate_1.argsToTemplate)(args, options);
|
|
13
|
+
expect(result).toBe('[prop1]="prop1" [prop3]="prop3"');
|
|
14
|
+
});
|
|
15
|
+
it('should include properties from include option', () => {
|
|
16
|
+
const args = {
|
|
17
|
+
prop1: 'value1',
|
|
18
|
+
prop2: 'value2',
|
|
19
|
+
prop3: 'value3',
|
|
20
|
+
};
|
|
21
|
+
const options = {
|
|
22
|
+
include: ['prop1', 'prop3'],
|
|
23
|
+
};
|
|
24
|
+
const result = (0, argsToTemplate_1.argsToTemplate)(args, options);
|
|
25
|
+
expect(result).toBe('[prop1]="prop1" [prop3]="prop3"');
|
|
26
|
+
});
|
|
27
|
+
it('should include non-undefined properties from include option', () => {
|
|
28
|
+
const args = {
|
|
29
|
+
prop1: 'value1',
|
|
30
|
+
prop2: 'value2',
|
|
31
|
+
prop3: undefined,
|
|
32
|
+
};
|
|
33
|
+
const options = {
|
|
34
|
+
include: ['prop1', 'prop3'],
|
|
35
|
+
};
|
|
36
|
+
const result = (0, argsToTemplate_1.argsToTemplate)(args, options);
|
|
37
|
+
expect(result).toBe('[prop1]="prop1"');
|
|
38
|
+
});
|
|
39
|
+
it('should exclude properties from exclude option', () => {
|
|
40
|
+
const args = {
|
|
41
|
+
prop1: 'value1',
|
|
42
|
+
prop2: 'value2',
|
|
43
|
+
prop3: 'value3',
|
|
44
|
+
};
|
|
45
|
+
const options = {
|
|
46
|
+
exclude: ['prop2'],
|
|
47
|
+
};
|
|
48
|
+
const result = (0, argsToTemplate_1.argsToTemplate)(args, options);
|
|
49
|
+
expect(result).toBe('[prop1]="prop1" [prop3]="prop3"');
|
|
50
|
+
});
|
|
51
|
+
it('should exclude properties from exclude option and undefined properties', () => {
|
|
52
|
+
const args = {
|
|
53
|
+
prop1: 'value1',
|
|
54
|
+
prop2: 'value2',
|
|
55
|
+
prop3: undefined,
|
|
56
|
+
};
|
|
57
|
+
const options = {
|
|
58
|
+
exclude: ['prop2'],
|
|
59
|
+
};
|
|
60
|
+
const result = (0, argsToTemplate_1.argsToTemplate)(args, options);
|
|
61
|
+
expect(result).toBe('[prop1]="prop1"');
|
|
62
|
+
});
|
|
63
|
+
it('should prioritize include over exclude when both options are given', () => {
|
|
64
|
+
const args = {
|
|
65
|
+
prop1: 'value1',
|
|
66
|
+
prop2: 'value2',
|
|
67
|
+
prop3: 'value3',
|
|
68
|
+
};
|
|
69
|
+
const options = {
|
|
70
|
+
include: ['prop1', 'prop2'],
|
|
71
|
+
exclude: ['prop2', 'prop3'],
|
|
72
|
+
};
|
|
73
|
+
const result = (0, argsToTemplate_1.argsToTemplate)(args, options);
|
|
74
|
+
expect(result).toBe('[prop1]="prop1" [prop2]="prop2"');
|
|
75
|
+
});
|
|
76
|
+
it('should work when neither include nor exclude options are given', () => {
|
|
77
|
+
const args = {
|
|
78
|
+
prop1: 'value1',
|
|
79
|
+
prop2: 'value2',
|
|
80
|
+
};
|
|
81
|
+
const options = {};
|
|
82
|
+
const result = (0, argsToTemplate_1.argsToTemplate)(args, options);
|
|
83
|
+
expect(result).toBe('[prop1]="prop1" [prop2]="prop2"');
|
|
84
|
+
});
|
|
85
|
+
it('should bind events correctly when value is a function', () => {
|
|
86
|
+
const args = { event1: () => { }, event2: () => { } };
|
|
87
|
+
const result = (0, argsToTemplate_1.argsToTemplate)(args, {});
|
|
88
|
+
expect(result).toEqual('(event1)="event1($event)" (event2)="event2($event)"');
|
|
89
|
+
});
|
|
90
|
+
it('should mix properties and events correctly', () => {
|
|
91
|
+
const args = { input: 'Value1', event1: () => { } };
|
|
92
|
+
const result = (0, argsToTemplate_1.argsToTemplate)(args, {});
|
|
93
|
+
expect(result).toEqual('[input]="input" (event1)="event1($event)"');
|
|
94
|
+
});
|
|
95
|
+
});
|
package/dist/client/index.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export * from './public-api';
|
|
|
3
3
|
export * from './public-types';
|
|
4
4
|
export type { StoryFnAngularReturnType as IStory } from './types';
|
|
5
5
|
export { moduleMetadata, componentWrapperDecorator, applicationConfig } from './decorators';
|
|
6
|
+
export { argsToTemplate } from './argsToTemplate';
|
package/dist/client/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.applicationConfig = exports.componentWrapperDecorator = exports.moduleMetadata = void 0;
|
|
18
|
+
exports.argsToTemplate = exports.applicationConfig = exports.componentWrapperDecorator = exports.moduleMetadata = void 0;
|
|
19
19
|
require("./globals");
|
|
20
20
|
// eslint-disable-next-line import/export
|
|
21
21
|
__exportStar(require("./public-api"), exports);
|
|
@@ -25,6 +25,8 @@ var decorators_1 = require("./decorators");
|
|
|
25
25
|
Object.defineProperty(exports, "moduleMetadata", { enumerable: true, get: function () { return decorators_1.moduleMetadata; } });
|
|
26
26
|
Object.defineProperty(exports, "componentWrapperDecorator", { enumerable: true, get: function () { return decorators_1.componentWrapperDecorator; } });
|
|
27
27
|
Object.defineProperty(exports, "applicationConfig", { enumerable: true, get: function () { return decorators_1.applicationConfig; } });
|
|
28
|
+
var argsToTemplate_1 = require("./argsToTemplate");
|
|
29
|
+
Object.defineProperty(exports, "argsToTemplate", { enumerable: true, get: function () { return argsToTemplate_1.argsToTemplate; } });
|
|
28
30
|
// optimization: stop HMR propagation in webpack
|
|
29
31
|
if (typeof module !== 'undefined')
|
|
30
32
|
module?.hot?.decline();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storybook/angular",
|
|
3
|
-
"version": "7.5.0-alpha.
|
|
3
|
+
"version": "7.5.0-alpha.7",
|
|
4
4
|
"description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"storybook",
|
|
@@ -37,21 +37,21 @@
|
|
|
37
37
|
"prep": "../../../scripts/prepare/tsc.ts"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@storybook/builder-webpack5": "7.5.0-alpha.
|
|
41
|
-
"@storybook/cli": "7.5.0-alpha.
|
|
42
|
-
"@storybook/client-logger": "7.5.0-alpha.
|
|
43
|
-
"@storybook/core-common": "7.5.0-alpha.
|
|
44
|
-
"@storybook/core-events": "7.5.0-alpha.
|
|
45
|
-
"@storybook/core-server": "7.5.0-alpha.
|
|
46
|
-
"@storybook/core-webpack": "7.5.0-alpha.
|
|
47
|
-
"@storybook/docs-tools": "7.5.0-alpha.
|
|
40
|
+
"@storybook/builder-webpack5": "7.5.0-alpha.7",
|
|
41
|
+
"@storybook/cli": "7.5.0-alpha.7",
|
|
42
|
+
"@storybook/client-logger": "7.5.0-alpha.7",
|
|
43
|
+
"@storybook/core-common": "7.5.0-alpha.7",
|
|
44
|
+
"@storybook/core-events": "7.5.0-alpha.7",
|
|
45
|
+
"@storybook/core-server": "7.5.0-alpha.7",
|
|
46
|
+
"@storybook/core-webpack": "7.5.0-alpha.7",
|
|
47
|
+
"@storybook/docs-tools": "7.5.0-alpha.7",
|
|
48
48
|
"@storybook/global": "^5.0.0",
|
|
49
|
-
"@storybook/manager-api": "7.5.0-alpha.
|
|
50
|
-
"@storybook/node-logger": "7.5.0-alpha.
|
|
51
|
-
"@storybook/preview-api": "7.5.0-alpha.
|
|
52
|
-
"@storybook/telemetry": "7.5.0-alpha.
|
|
53
|
-
"@storybook/types": "7.5.0-alpha.
|
|
54
|
-
"@types/node": "^
|
|
49
|
+
"@storybook/manager-api": "7.5.0-alpha.7",
|
|
50
|
+
"@storybook/node-logger": "7.5.0-alpha.7",
|
|
51
|
+
"@storybook/preview-api": "7.5.0-alpha.7",
|
|
52
|
+
"@storybook/telemetry": "7.5.0-alpha.7",
|
|
53
|
+
"@storybook/types": "7.5.0-alpha.7",
|
|
54
|
+
"@types/node": "^18.0.0",
|
|
55
55
|
"@types/react": "^16.14.34",
|
|
56
56
|
"@types/react-dom": "^16.9.14",
|
|
57
57
|
"@types/semver": "^7.3.4",
|