@storybook/angular 7.0.0-beta.32 → 7.0.0-beta.34
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/builders/build-storybook/index.d.ts +1 -1
- package/dist/builders/build-storybook/index.js +2 -2
- package/dist/builders/build-storybook/schema.json +12 -4
- package/dist/builders/start-storybook/index.d.ts +1 -1
- package/dist/builders/start-storybook/index.js +2 -2
- package/dist/builders/start-storybook/schema.json +8 -3
- package/dist/client/angular-beta/AbstractRenderer.d.ts +1 -1
- package/dist/client/angular-beta/AbstractRenderer.js +10 -1
- package/dist/client/angular-beta/StorybookWrapperComponent.js +16 -33
- package/dist/client/angular-beta/utils/NgModulesAnalyzer.d.ts +1 -1
- package/dist/client/angular-beta/utils/NgModulesAnalyzer.js +4 -4
- package/dist/client/angular-beta/utils/NgModulesAnalyzer.test.js +3 -3
- package/dist/client/angular-beta/utils/PropertyExtractor.d.ts +34 -0
- package/dist/client/angular-beta/utils/PropertyExtractor.js +72 -0
- package/dist/client/angular-beta/utils/PropertyExtractor.test.d.ts +1 -0
- package/dist/client/angular-beta/utils/PropertyExtractor.test.js +97 -0
- package/package.json +37 -36
- package/template/stories/core/moduleMetadata/angular-src/open-close-component/open-close.component.css +13 -0
- package/template/stories/core/moduleMetadata/angular-src/open-close-component/open-close.component.html +7 -0
- package/template/stories/core/moduleMetadata/angular-src/open-close-component/open-close.component.ts +39 -0
- package/template/stories/core/moduleMetadata/with-browser-animations.stories.ts +30 -0
|
@@ -6,7 +6,7 @@ import { StyleElement } from '@angular-devkit/build-angular/src/builders/browser
|
|
|
6
6
|
export type StorybookBuilderOptions = JsonObject & {
|
|
7
7
|
browserTarget?: string | null;
|
|
8
8
|
tsConfig?: string;
|
|
9
|
-
|
|
9
|
+
docs: boolean;
|
|
10
10
|
compodoc: boolean;
|
|
11
11
|
compodocArgs: string[];
|
|
12
12
|
styles?: StyleElement[];
|
|
@@ -16,11 +16,11 @@ function commandBuilder(options, context) {
|
|
|
16
16
|
: (0, rxjs_1.of)({});
|
|
17
17
|
return runCompodoc$.pipe((0, operators_1.mapTo)({ tsConfig }));
|
|
18
18
|
}), (0, operators_1.map)(({ tsConfig }) => {
|
|
19
|
-
const { browserTarget, stylePreprocessorOptions, styles, configDir,
|
|
19
|
+
const { browserTarget, stylePreprocessorOptions, styles, configDir, docs, loglevel, outputDir, quiet, webpackStatsJson, disableTelemetry, } = options;
|
|
20
20
|
const standaloneOptions = {
|
|
21
21
|
packageJson: (0, read_pkg_up_1.sync)({ cwd: __dirname }).packageJson,
|
|
22
22
|
configDir,
|
|
23
|
-
|
|
23
|
+
...(docs ? { docs } : {}),
|
|
24
24
|
loglevel,
|
|
25
25
|
outputDir,
|
|
26
26
|
quiet,
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"description": "Suppress verbose build output.",
|
|
35
35
|
"default": false
|
|
36
36
|
},
|
|
37
|
-
"
|
|
37
|
+
"docs": {
|
|
38
38
|
"type": "boolean",
|
|
39
39
|
"description": "Starts Storybook in documentation mode. Learn more about it : https://storybook.js.org/docs/react/writing-docs/build-documentation#preview-storybooks-documentation.",
|
|
40
40
|
"default": false
|
|
@@ -47,13 +47,19 @@
|
|
|
47
47
|
"compodocArgs": {
|
|
48
48
|
"type": "array",
|
|
49
49
|
"description": "Compodoc options : https://compodoc.app/guides/options.html. Options `-p` with tsconfig path and `-d` with workspace root is always given.",
|
|
50
|
-
"default": [
|
|
50
|
+
"default": [
|
|
51
|
+
"-e",
|
|
52
|
+
"json"
|
|
53
|
+
],
|
|
51
54
|
"items": {
|
|
52
55
|
"type": "string"
|
|
53
56
|
}
|
|
54
57
|
},
|
|
55
58
|
"webpackStatsJson": {
|
|
56
|
-
"type": [
|
|
59
|
+
"type": [
|
|
60
|
+
"boolean",
|
|
61
|
+
"string"
|
|
62
|
+
],
|
|
57
63
|
"description": "Write Webpack Stats JSON to disk",
|
|
58
64
|
"default": false
|
|
59
65
|
},
|
|
@@ -104,7 +110,9 @@
|
|
|
104
110
|
}
|
|
105
111
|
},
|
|
106
112
|
"additionalProperties": false,
|
|
107
|
-
"required": [
|
|
113
|
+
"required": [
|
|
114
|
+
"input"
|
|
115
|
+
]
|
|
108
116
|
},
|
|
109
117
|
{
|
|
110
118
|
"type": "string",
|
|
@@ -6,7 +6,7 @@ import { StyleElement } from '@angular-devkit/build-angular/src/builders/browser
|
|
|
6
6
|
export type StorybookBuilderOptions = JsonObject & {
|
|
7
7
|
browserTarget?: string | null;
|
|
8
8
|
tsConfig?: string;
|
|
9
|
-
|
|
9
|
+
docs: boolean;
|
|
10
10
|
compodoc: boolean;
|
|
11
11
|
compodocArgs: string[];
|
|
12
12
|
styles?: StyleElement[];
|
|
@@ -16,12 +16,12 @@ function commandBuilder(options, context) {
|
|
|
16
16
|
: (0, rxjs_1.of)({});
|
|
17
17
|
return runCompodoc$.pipe((0, operators_1.mapTo)({ tsConfig }));
|
|
18
18
|
}), (0, operators_1.map)(({ tsConfig }) => {
|
|
19
|
-
const { browserTarget, stylePreprocessorOptions, styles, ci, configDir,
|
|
19
|
+
const { browserTarget, stylePreprocessorOptions, styles, ci, configDir, docs, host, https, port, quiet, smokeTest, sslCa, sslCert, sslKey, disableTelemetry, } = options;
|
|
20
20
|
const standaloneOptions = {
|
|
21
21
|
packageJson: (0, read_pkg_up_1.sync)({ cwd: __dirname }).packageJson,
|
|
22
22
|
ci,
|
|
23
23
|
configDir,
|
|
24
|
-
|
|
24
|
+
...(docs ? { docs } : {}),
|
|
25
25
|
host,
|
|
26
26
|
https,
|
|
27
27
|
port,
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"description": "Suppress verbose build output.",
|
|
62
62
|
"default": false
|
|
63
63
|
},
|
|
64
|
-
"
|
|
64
|
+
"docs": {
|
|
65
65
|
"type": "boolean",
|
|
66
66
|
"description": "Starts Storybook in documentation mode. Learn more about it : https://storybook.js.org/docs/react/writing-docs/build-documentation#preview-storybooks-documentation.",
|
|
67
67
|
"default": false
|
|
@@ -74,7 +74,10 @@
|
|
|
74
74
|
"compodocArgs": {
|
|
75
75
|
"type": "array",
|
|
76
76
|
"description": "Compodoc options : https://compodoc.app/guides/options.html. Options `-p` with tsconfig path and `-d` with workspace root is always given.",
|
|
77
|
-
"default": [
|
|
77
|
+
"default": [
|
|
78
|
+
"-e",
|
|
79
|
+
"json"
|
|
80
|
+
],
|
|
78
81
|
"items": {
|
|
79
82
|
"type": "string"
|
|
80
83
|
}
|
|
@@ -126,7 +129,9 @@
|
|
|
126
129
|
}
|
|
127
130
|
},
|
|
128
131
|
"additionalProperties": false,
|
|
129
|
-
"required": [
|
|
132
|
+
"required": [
|
|
133
|
+
"input"
|
|
134
|
+
]
|
|
130
135
|
},
|
|
131
136
|
{
|
|
132
137
|
"type": "string",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Subject } from 'rxjs';
|
|
2
|
-
import { ICollection,
|
|
2
|
+
import { ICollection, Parameters, StoryFnAngularReturnType } from '../types';
|
|
3
3
|
type StoryRenderInfo = {
|
|
4
4
|
storyFnAngular: StoryFnAngularReturnType;
|
|
5
5
|
moduleMetadataSnapshot: string;
|
|
@@ -27,6 +27,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
27
27
|
exports.AbstractRenderer = void 0;
|
|
28
28
|
const core_1 = require("@angular/core");
|
|
29
29
|
const platform_browser_1 = require("@angular/platform-browser");
|
|
30
|
+
const animations_1 = require("@angular/platform-browser/animations");
|
|
30
31
|
const rxjs_1 = require("rxjs");
|
|
31
32
|
const telejson_1 = require("telejson");
|
|
32
33
|
const StorybookModule_1 = require("./StorybookModule");
|
|
@@ -71,6 +72,11 @@ class AbstractRenderer {
|
|
|
71
72
|
async render({ storyFnAngular, forced, parameters, component, targetDOMNode, }) {
|
|
72
73
|
const targetSelector = this.generateTargetSelectorFromStoryId(targetDOMNode.id);
|
|
73
74
|
const newStoryProps$ = new rxjs_1.BehaviorSubject(storyFnAngular.props);
|
|
75
|
+
const hasAnimationsDefined = !!storyFnAngular.moduleMetadata?.imports?.includes(animations_1.BrowserAnimationsModule);
|
|
76
|
+
if (hasAnimationsDefined && storyFnAngular?.moduleMetadata?.imports) {
|
|
77
|
+
// eslint-disable-next-line no-param-reassign
|
|
78
|
+
storyFnAngular.moduleMetadata.imports = storyFnAngular.moduleMetadata.imports.filter((importedModule) => importedModule !== animations_1.BrowserAnimationsModule);
|
|
79
|
+
}
|
|
74
80
|
if (!this.fullRendererRequired({
|
|
75
81
|
storyFnAngular,
|
|
76
82
|
moduleMetadata: {
|
|
@@ -89,7 +95,10 @@ class AbstractRenderer {
|
|
|
89
95
|
this.initAngularRootElement(targetDOMNode, targetSelector);
|
|
90
96
|
const application = (0, StorybookModule_1.getApplication)({ storyFnAngular, component, targetSelector });
|
|
91
97
|
const applicationRef = await (0, platform_browser_1.bootstrapApplication)(application, {
|
|
92
|
-
providers: [
|
|
98
|
+
providers: [
|
|
99
|
+
...(hasAnimationsDefined ? [(0, animations_1.provideAnimations)()] : []),
|
|
100
|
+
(0, StorybookProvider_1.storyPropsProvider)(newStoryProps$),
|
|
101
|
+
],
|
|
93
102
|
});
|
|
94
103
|
applicationRefs.add(applicationRef);
|
|
95
104
|
await this.afterFullRender();
|
|
@@ -13,13 +13,12 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.createStorybookWrapperComponent = exports.componentNgModules = void 0;
|
|
16
|
-
const common_1 = require("@angular/common");
|
|
17
16
|
const core_1 = require("@angular/core");
|
|
18
17
|
const rxjs_1 = require("rxjs");
|
|
19
18
|
const operators_1 = require("rxjs/operators");
|
|
20
19
|
const StorybookProvider_1 = require("./StorybookProvider");
|
|
21
20
|
const NgComponentAnalyzer_1 = require("./utils/NgComponentAnalyzer");
|
|
22
|
-
const
|
|
21
|
+
const PropertyExtractor_1 = require("./utils/PropertyExtractor");
|
|
23
22
|
const getNonInputsOutputsProps = (ngComponentInputsOutputs, props = {}) => {
|
|
24
23
|
const inputs = ngComponentInputsOutputs.inputs
|
|
25
24
|
.filter((i) => i.templateName in props)
|
|
@@ -29,6 +28,7 @@ const getNonInputsOutputsProps = (ngComponentInputsOutputs, props = {}) => {
|
|
|
29
28
|
.map((o) => o.templateName);
|
|
30
29
|
return Object.keys(props).filter((k) => ![...inputs, ...outputs].includes(k));
|
|
31
30
|
};
|
|
31
|
+
// component modules cache
|
|
32
32
|
exports.componentNgModules = new Map();
|
|
33
33
|
/**
|
|
34
34
|
* Wraps the story template into a component
|
|
@@ -40,39 +40,26 @@ const createStorybookWrapperComponent = (selector, template, storyComponent, sty
|
|
|
40
40
|
// In ivy, a '' selector is not allowed, therefore we need to just set it to anything if
|
|
41
41
|
// storyComponent was not provided.
|
|
42
42
|
const viewChildSelector = storyComponent ?? '__storybook-noop';
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
ProviderModule = __decorate([
|
|
53
|
-
(0, core_1.NgModule)({
|
|
54
|
-
providers: [provider],
|
|
55
|
-
})
|
|
56
|
-
], ProviderModule);
|
|
57
|
-
exports.componentNgModules.set(provider, ProviderModule);
|
|
58
|
-
}
|
|
59
|
-
return exports.componentNgModules.get(provider);
|
|
60
|
-
});
|
|
61
|
-
if (!exports.componentNgModules.get(storyComponent)) {
|
|
62
|
-
const declarations = [
|
|
63
|
-
...(requiresComponentDeclaration ? [storyComponent] : []),
|
|
64
|
-
...(moduleMetadata.declarations ?? []),
|
|
65
|
-
];
|
|
43
|
+
const imports = (0, PropertyExtractor_1.extractImports)(moduleMetadata);
|
|
44
|
+
const declarations = (0, PropertyExtractor_1.extractDeclarations)(moduleMetadata, storyComponent);
|
|
45
|
+
const providers = (0, PropertyExtractor_1.extractProviders)(moduleMetadata);
|
|
46
|
+
// Only create a new module if it doesn't already exist
|
|
47
|
+
// This is to prevent the module from being recreated on every story change
|
|
48
|
+
// Declarations & Imports are only added once
|
|
49
|
+
// Providers are added on every story change to allow for story-specific providers
|
|
50
|
+
let ngModule = exports.componentNgModules.get(storyComponent);
|
|
51
|
+
if (!ngModule) {
|
|
66
52
|
let StorybookComponentModule = class StorybookComponentModule {
|
|
67
53
|
};
|
|
68
54
|
StorybookComponentModule = __decorate([
|
|
69
55
|
(0, core_1.NgModule)({
|
|
70
56
|
declarations,
|
|
71
|
-
imports
|
|
72
|
-
exports: [...declarations, ...
|
|
57
|
+
imports,
|
|
58
|
+
exports: [...declarations, ...imports],
|
|
73
59
|
})
|
|
74
60
|
], StorybookComponentModule);
|
|
75
61
|
exports.componentNgModules.set(storyComponent, StorybookComponentModule);
|
|
62
|
+
ngModule = exports.componentNgModules.get(storyComponent);
|
|
76
63
|
}
|
|
77
64
|
let StorybookWrapperComponent = class StorybookWrapperComponent {
|
|
78
65
|
constructor(storyProps$, changeDetectorRef) {
|
|
@@ -142,12 +129,8 @@ const createStorybookWrapperComponent = (selector, template, storyComponent, sty
|
|
|
142
129
|
selector,
|
|
143
130
|
template,
|
|
144
131
|
standalone: true,
|
|
145
|
-
imports: [
|
|
146
|
-
|
|
147
|
-
exports.componentNgModules.get(storyComponent),
|
|
148
|
-
...providersNgModules,
|
|
149
|
-
...(isStandalone ? [storyComponent] : []),
|
|
150
|
-
],
|
|
132
|
+
imports: [ngModule],
|
|
133
|
+
providers,
|
|
151
134
|
styles,
|
|
152
135
|
schemas: moduleMetadata.schemas,
|
|
153
136
|
}),
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Checks recursively if the component has already been declared in all import Module
|
|
5
5
|
*/
|
|
6
|
-
export declare const
|
|
6
|
+
export declare const isComponentAlreadyDeclared: (componentToFind: any, moduleDeclarations: any[], moduleImports: any[]) => boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.isComponentAlreadyDeclared = void 0;
|
|
4
4
|
const core_1 = require("@angular/core");
|
|
5
5
|
const reflectionCapabilities = new core_1.ɵReflectionCapabilities();
|
|
6
6
|
/**
|
|
@@ -8,7 +8,7 @@ const reflectionCapabilities = new core_1.ɵReflectionCapabilities();
|
|
|
8
8
|
*
|
|
9
9
|
* Checks recursively if the component has already been declared in all import Module
|
|
10
10
|
*/
|
|
11
|
-
const
|
|
11
|
+
const isComponentAlreadyDeclared = (componentToFind, moduleDeclarations, moduleImports) => {
|
|
12
12
|
if (moduleDeclarations &&
|
|
13
13
|
moduleDeclarations.some((declaration) => declaration === componentToFind)) {
|
|
14
14
|
// Found component in declarations array
|
|
@@ -23,10 +23,10 @@ const isComponentAlreadyDeclaredInModules = (componentToFind, moduleDeclarations
|
|
|
23
23
|
// Not an NgModule
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
|
-
return (0, exports.
|
|
26
|
+
return (0, exports.isComponentAlreadyDeclared)(componentToFind, extractedNgModuleMetadata.declarations, extractedNgModuleMetadata.imports);
|
|
27
27
|
});
|
|
28
28
|
};
|
|
29
|
-
exports.
|
|
29
|
+
exports.isComponentAlreadyDeclared = isComponentAlreadyDeclared;
|
|
30
30
|
const extractNgModuleMetadata = (importItem) => {
|
|
31
31
|
const target = importItem && importItem.ngModule ? importItem.ngModule : importItem;
|
|
32
32
|
const decorators = reflectionCapabilities.annotations(target);
|
|
@@ -12,12 +12,12 @@ const AlphaModule = (0, core_1.NgModule)({ imports: [BetaModule] })(class {
|
|
|
12
12
|
});
|
|
13
13
|
describe('isComponentAlreadyDeclaredInModules', () => {
|
|
14
14
|
it('should return true when the component is already declared in one of modules', () => {
|
|
15
|
-
expect((0, NgModulesAnalyzer_1.
|
|
15
|
+
expect((0, NgModulesAnalyzer_1.isComponentAlreadyDeclared)(FooComponent, [], [AlphaModule])).toEqual(true);
|
|
16
16
|
});
|
|
17
17
|
it('should return true if the component is in moduleDeclarations', () => {
|
|
18
|
-
expect((0, NgModulesAnalyzer_1.
|
|
18
|
+
expect((0, NgModulesAnalyzer_1.isComponentAlreadyDeclared)(BarComponent, [BarComponent], [AlphaModule])).toEqual(true);
|
|
19
19
|
});
|
|
20
20
|
it('should return false if the component is not declared', () => {
|
|
21
|
-
expect((0, NgModulesAnalyzer_1.
|
|
21
|
+
expect((0, NgModulesAnalyzer_1.isComponentAlreadyDeclared)(BarComponent, [], [AlphaModule])).toEqual(false);
|
|
22
22
|
});
|
|
23
23
|
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Provider } from '@angular/core';
|
|
2
|
+
import { NgModuleMetadata } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Extract Imports from NgModule
|
|
5
|
+
*
|
|
6
|
+
* CommonModule is always imported
|
|
7
|
+
*
|
|
8
|
+
* metadata.imports are flattened deeply and extracted into a new array
|
|
9
|
+
*
|
|
10
|
+
* - If ModuleWithProviders (e.g. forRoot() & forChild() ) is used, the ngModule is extracted without providers.
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
13
|
+
export declare const extractImports: (metadata: NgModuleMetadata) => any[];
|
|
14
|
+
/**
|
|
15
|
+
* Extract providers from NgModule
|
|
16
|
+
*
|
|
17
|
+
* - A new array is returned with:
|
|
18
|
+
* - metadata.providers
|
|
19
|
+
* - providers from each **ModuleWithProviders** (e.g. forRoot() & forChild() )
|
|
20
|
+
*
|
|
21
|
+
* - Use this in combination with extractImports to get all providers for a specific module
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
export declare const extractProviders: (metadata: NgModuleMetadata) => Provider[];
|
|
25
|
+
/**
|
|
26
|
+
* Extract declarations from NgModule
|
|
27
|
+
*
|
|
28
|
+
* - If a story component is provided, it will be added to the declarations array if:
|
|
29
|
+
* - It is a component or directive or pipe
|
|
30
|
+
* - It is not already declared
|
|
31
|
+
* - It is not a standalone component
|
|
32
|
+
*
|
|
33
|
+
*/
|
|
34
|
+
export declare const extractDeclarations: (metadata: NgModuleMetadata, storyComponent?: any) => any[];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractDeclarations = exports.extractProviders = exports.extractImports = void 0;
|
|
4
|
+
const common_1 = require("@angular/common");
|
|
5
|
+
const NgComponentAnalyzer_1 = require("./NgComponentAnalyzer");
|
|
6
|
+
const NgModulesAnalyzer_1 = require("./NgModulesAnalyzer");
|
|
7
|
+
const uniqueArray = (arr) => {
|
|
8
|
+
return arr.flat(Number.MAX_VALUE).filter((value, index, self) => self.indexOf(value) === index);
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Extract Imports from NgModule
|
|
12
|
+
*
|
|
13
|
+
* CommonModule is always imported
|
|
14
|
+
*
|
|
15
|
+
* metadata.imports are flattened deeply and extracted into a new array
|
|
16
|
+
*
|
|
17
|
+
* - If ModuleWithProviders (e.g. forRoot() & forChild() ) is used, the ngModule is extracted without providers.
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
const extractImports = (metadata) => {
|
|
21
|
+
const imports = [common_1.CommonModule];
|
|
22
|
+
const modules = (metadata.imports || []).flat(Number.MAX_VALUE);
|
|
23
|
+
const withProviders = modules.filter((moduleDef) => !!moduleDef?.ngModule);
|
|
24
|
+
const withoutProviders = modules.filter((moduleDef) => !withProviders.includes(moduleDef));
|
|
25
|
+
return uniqueArray([
|
|
26
|
+
imports,
|
|
27
|
+
withoutProviders,
|
|
28
|
+
withProviders.map((moduleDef) => moduleDef.ngModule),
|
|
29
|
+
]);
|
|
30
|
+
};
|
|
31
|
+
exports.extractImports = extractImports;
|
|
32
|
+
/**
|
|
33
|
+
* Extract providers from NgModule
|
|
34
|
+
*
|
|
35
|
+
* - A new array is returned with:
|
|
36
|
+
* - metadata.providers
|
|
37
|
+
* - providers from each **ModuleWithProviders** (e.g. forRoot() & forChild() )
|
|
38
|
+
*
|
|
39
|
+
* - Use this in combination with extractImports to get all providers for a specific module
|
|
40
|
+
*
|
|
41
|
+
*/
|
|
42
|
+
const extractProviders = (metadata) => {
|
|
43
|
+
const providers = (metadata.providers || []);
|
|
44
|
+
const moduleProviders = (metadata.imports || [])
|
|
45
|
+
.flat(Number.MAX_VALUE)
|
|
46
|
+
.filter((moduleDef) => !!moduleDef?.ngModule)
|
|
47
|
+
.map((moduleDef) => moduleDef.providers || []);
|
|
48
|
+
return uniqueArray([].concat(moduleProviders, providers));
|
|
49
|
+
};
|
|
50
|
+
exports.extractProviders = extractProviders;
|
|
51
|
+
/**
|
|
52
|
+
* Extract declarations from NgModule
|
|
53
|
+
*
|
|
54
|
+
* - If a story component is provided, it will be added to the declarations array if:
|
|
55
|
+
* - It is a component or directive or pipe
|
|
56
|
+
* - It is not already declared
|
|
57
|
+
* - It is not a standalone component
|
|
58
|
+
*
|
|
59
|
+
*/
|
|
60
|
+
const extractDeclarations = (metadata, storyComponent) => {
|
|
61
|
+
const declarations = metadata.declarations || [];
|
|
62
|
+
if (storyComponent) {
|
|
63
|
+
const isStandalone = (0, NgComponentAnalyzer_1.isStandaloneComponent)(storyComponent);
|
|
64
|
+
const isDeclared = (0, NgModulesAnalyzer_1.isComponentAlreadyDeclared)(storyComponent, declarations, metadata.imports);
|
|
65
|
+
const requiresDeclaration = (0, NgComponentAnalyzer_1.isDeclarable)(storyComponent) && !isDeclared && !isStandalone;
|
|
66
|
+
if (requiresDeclaration) {
|
|
67
|
+
declarations.push(storyComponent);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return uniqueArray(declarations);
|
|
71
|
+
};
|
|
72
|
+
exports.extractDeclarations = extractDeclarations;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const common_1 = require("@angular/common");
|
|
4
|
+
const core_1 = require("@angular/core");
|
|
5
|
+
const PropertyExtractor_1 = require("./PropertyExtractor");
|
|
6
|
+
const TEST_TOKEN = new core_1.InjectionToken('testToken');
|
|
7
|
+
const TestTokenProvider = { provide: TEST_TOKEN, useValue: 123 };
|
|
8
|
+
const TestService = (0, core_1.Injectable)()(class {
|
|
9
|
+
});
|
|
10
|
+
const TestComponent1 = (0, core_1.Component)({})(class {
|
|
11
|
+
});
|
|
12
|
+
const TestComponent2 = (0, core_1.Component)({})(class {
|
|
13
|
+
});
|
|
14
|
+
const StandaloneTestComponent = (0, core_1.Component)({ standalone: true })(class {
|
|
15
|
+
});
|
|
16
|
+
const TestDirective = (0, core_1.Directive)({})(class {
|
|
17
|
+
});
|
|
18
|
+
const TestModuleWithDeclarations = (0, core_1.NgModule)({ declarations: [TestComponent1] })(class {
|
|
19
|
+
});
|
|
20
|
+
const TestModuleWithImportsAndProviders = (0, core_1.NgModule)({
|
|
21
|
+
imports: [TestModuleWithDeclarations],
|
|
22
|
+
providers: [TestTokenProvider],
|
|
23
|
+
})(class {
|
|
24
|
+
});
|
|
25
|
+
describe('PropertyExtractor', () => {
|
|
26
|
+
describe('extractImports', () => {
|
|
27
|
+
it('should return an array of imports', () => {
|
|
28
|
+
const imports = (0, PropertyExtractor_1.extractImports)({ imports: [TestModuleWithImportsAndProviders] });
|
|
29
|
+
expect(imports).toEqual([common_1.CommonModule, TestModuleWithImportsAndProviders]);
|
|
30
|
+
});
|
|
31
|
+
it('should return an array of unique imports without providers', () => {
|
|
32
|
+
const imports = (0, PropertyExtractor_1.extractImports)({
|
|
33
|
+
imports: [
|
|
34
|
+
TestModuleWithImportsAndProviders,
|
|
35
|
+
{ ngModule: TestModuleWithImportsAndProviders, providers: [] },
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
expect(imports).toEqual([common_1.CommonModule, TestModuleWithImportsAndProviders]);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe('extractDeclarations', () => {
|
|
42
|
+
it('should return an array of declarations', () => {
|
|
43
|
+
const declarations = (0, PropertyExtractor_1.extractDeclarations)({ declarations: [TestComponent1] }, TestComponent2);
|
|
44
|
+
expect(declarations).toEqual([TestComponent1, TestComponent2]);
|
|
45
|
+
});
|
|
46
|
+
it('should ignore pre-declared components', () => {
|
|
47
|
+
// TestComponent1 is declared as part of TestModuleWithDeclarations
|
|
48
|
+
// TestModuleWithDeclarations is imported by TestModuleWithImportsAndProviders
|
|
49
|
+
const declarations = (0, PropertyExtractor_1.extractDeclarations)({
|
|
50
|
+
imports: [TestModuleWithImportsAndProviders],
|
|
51
|
+
declarations: [TestComponent2, StandaloneTestComponent, TestDirective],
|
|
52
|
+
}, TestComponent1);
|
|
53
|
+
expect(declarations).toEqual([TestComponent2, StandaloneTestComponent, TestDirective]);
|
|
54
|
+
});
|
|
55
|
+
it('should ignore standalone components', () => {
|
|
56
|
+
const declarations = (0, PropertyExtractor_1.extractDeclarations)({
|
|
57
|
+
imports: [TestModuleWithImportsAndProviders],
|
|
58
|
+
declarations: [TestComponent1, TestComponent2, TestDirective],
|
|
59
|
+
}, StandaloneTestComponent);
|
|
60
|
+
expect(declarations).toEqual([TestComponent1, TestComponent2, TestDirective]);
|
|
61
|
+
});
|
|
62
|
+
it('should ignore non components/directives/pipes', () => {
|
|
63
|
+
const declarations = (0, PropertyExtractor_1.extractDeclarations)({
|
|
64
|
+
imports: [TestModuleWithImportsAndProviders],
|
|
65
|
+
declarations: [TestComponent1, TestComponent2, StandaloneTestComponent],
|
|
66
|
+
}, TestService);
|
|
67
|
+
expect(declarations).toEqual([TestComponent1, TestComponent2, StandaloneTestComponent]);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('extractProviders', () => {
|
|
71
|
+
it('should return an array of providers', () => {
|
|
72
|
+
const providers = (0, PropertyExtractor_1.extractProviders)({
|
|
73
|
+
providers: [TestService],
|
|
74
|
+
});
|
|
75
|
+
expect(providers).toEqual([TestService]);
|
|
76
|
+
});
|
|
77
|
+
it('should return an array of providers extracted from ModuleWithProviders', () => {
|
|
78
|
+
const providers = (0, PropertyExtractor_1.extractProviders)({
|
|
79
|
+
imports: [{ ngModule: TestModuleWithImportsAndProviders, providers: [TestService] }],
|
|
80
|
+
});
|
|
81
|
+
expect(providers).toEqual([TestService]);
|
|
82
|
+
});
|
|
83
|
+
it('should return an array of unique providers', () => {
|
|
84
|
+
const providers = (0, PropertyExtractor_1.extractProviders)({
|
|
85
|
+
imports: [{ ngModule: TestModuleWithImportsAndProviders, providers: [TestService] }],
|
|
86
|
+
providers: [TestService, { provide: TEST_TOKEN, useValue: 123 }],
|
|
87
|
+
});
|
|
88
|
+
expect(providers).toEqual([
|
|
89
|
+
TestService,
|
|
90
|
+
{
|
|
91
|
+
provide: new core_1.InjectionToken('testToken'),
|
|
92
|
+
useValue: 123,
|
|
93
|
+
},
|
|
94
|
+
]);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storybook/angular",
|
|
3
|
-
"version": "7.0.0-beta.
|
|
3
|
+
"version": "7.0.0-beta.34",
|
|
4
4
|
"description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"storybook",
|
|
@@ -36,20 +36,20 @@
|
|
|
36
36
|
"prep": "../../../scripts/prepare/tsc.ts"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@storybook/builder-webpack5": "7.0.0-beta.
|
|
40
|
-
"@storybook/cli": "7.0.0-beta.
|
|
41
|
-
"@storybook/client-logger": "7.0.0-beta.
|
|
42
|
-
"@storybook/core-client": "7.0.0-beta.
|
|
43
|
-
"@storybook/core-common": "7.0.0-beta.
|
|
44
|
-
"@storybook/core-events": "7.0.0-beta.
|
|
45
|
-
"@storybook/core-server": "7.0.0-beta.
|
|
46
|
-
"@storybook/core-webpack": "7.0.0-beta.
|
|
47
|
-
"@storybook/docs-tools": "7.0.0-beta.
|
|
39
|
+
"@storybook/builder-webpack5": "7.0.0-beta.34",
|
|
40
|
+
"@storybook/cli": "7.0.0-beta.34",
|
|
41
|
+
"@storybook/client-logger": "7.0.0-beta.34",
|
|
42
|
+
"@storybook/core-client": "7.0.0-beta.34",
|
|
43
|
+
"@storybook/core-common": "7.0.0-beta.34",
|
|
44
|
+
"@storybook/core-events": "7.0.0-beta.34",
|
|
45
|
+
"@storybook/core-server": "7.0.0-beta.34",
|
|
46
|
+
"@storybook/core-webpack": "7.0.0-beta.34",
|
|
47
|
+
"@storybook/docs-tools": "7.0.0-beta.34",
|
|
48
48
|
"@storybook/global": "^5.0.0",
|
|
49
|
-
"@storybook/manager-api": "7.0.0-beta.
|
|
50
|
-
"@storybook/node-logger": "7.0.0-beta.
|
|
51
|
-
"@storybook/preview-api": "7.0.0-beta.
|
|
52
|
-
"@storybook/types": "7.0.0-beta.
|
|
49
|
+
"@storybook/manager-api": "7.0.0-beta.34",
|
|
50
|
+
"@storybook/node-logger": "7.0.0-beta.34",
|
|
51
|
+
"@storybook/preview-api": "7.0.0-beta.34",
|
|
52
|
+
"@storybook/types": "7.0.0-beta.34",
|
|
53
53
|
"@types/node": "^16.0.0",
|
|
54
54
|
"@types/react": "^16.14.34",
|
|
55
55
|
"@types/react-dom": "^16.9.14",
|
|
@@ -67,16 +67,17 @@
|
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@angular-devkit/architect": "^0.1500.4",
|
|
70
|
-
"@angular-devkit/build-angular": "^15.
|
|
71
|
-
"@angular-devkit/core": "^15.
|
|
72
|
-
"@angular/
|
|
73
|
-
"@angular/
|
|
74
|
-
"@angular/
|
|
75
|
-
"@angular/compiler
|
|
76
|
-
"@angular/
|
|
77
|
-
"@angular/
|
|
78
|
-
"@angular/
|
|
79
|
-
"@angular/platform-browser
|
|
70
|
+
"@angular-devkit/build-angular": "^15.1.1",
|
|
71
|
+
"@angular-devkit/core": "^15.1.1",
|
|
72
|
+
"@angular/animations": "^15.1.1",
|
|
73
|
+
"@angular/cli": "^15.1.1",
|
|
74
|
+
"@angular/common": "^15.1.1",
|
|
75
|
+
"@angular/compiler": "^15.1.1",
|
|
76
|
+
"@angular/compiler-cli": "^15.1.1",
|
|
77
|
+
"@angular/core": "^15.1.1",
|
|
78
|
+
"@angular/forms": "^15.1.1",
|
|
79
|
+
"@angular/platform-browser": "^15.1.1",
|
|
80
|
+
"@angular/platform-browser-dynamic": "^15.1.1",
|
|
80
81
|
"@types/rimraf": "^3.0.2",
|
|
81
82
|
"@types/tmp": "^0.2.3",
|
|
82
83
|
"cross-spawn": "^7.0.3",
|
|
@@ -90,17 +91,17 @@
|
|
|
90
91
|
"zone.js": "^0.12.0"
|
|
91
92
|
},
|
|
92
93
|
"peerDependencies": {
|
|
93
|
-
"@angular-devkit/architect": ">=0.1400.0",
|
|
94
|
-
"@angular-devkit/build-angular": ">=14.0.0",
|
|
95
|
-
"@angular-devkit/core": ">=14.0.0",
|
|
96
|
-
"@angular/cli": ">=14.0.0",
|
|
97
|
-
"@angular/common": ">=14.0.0",
|
|
98
|
-
"@angular/compiler": ">=14.0.0",
|
|
99
|
-
"@angular/compiler-cli": ">=14.0.0",
|
|
100
|
-
"@angular/core": ">=14.0.0",
|
|
101
|
-
"@angular/forms": ">=14.0.0",
|
|
102
|
-
"@angular/platform-browser": ">=14.0.0",
|
|
103
|
-
"@angular/platform-browser-dynamic": ">=14.0.0",
|
|
94
|
+
"@angular-devkit/architect": ">=0.1400.0 < 0.1600.0",
|
|
95
|
+
"@angular-devkit/build-angular": ">=14.1.0 < 16.0.0",
|
|
96
|
+
"@angular-devkit/core": ">=14.1.0 < 16.0.0",
|
|
97
|
+
"@angular/cli": ">=14.1.0 < 16.0.0",
|
|
98
|
+
"@angular/common": ">=14.1.0 < 16.0.0",
|
|
99
|
+
"@angular/compiler": ">=14.1.0 < 16.0.0",
|
|
100
|
+
"@angular/compiler-cli": ">=14.1.0 < 16.0.0",
|
|
101
|
+
"@angular/core": ">=14.1.0 < 16.0.0",
|
|
102
|
+
"@angular/forms": ">=14.1.0 < 16.0.0",
|
|
103
|
+
"@angular/platform-browser": ">=14.1.0 < 16.0.0",
|
|
104
|
+
"@angular/platform-browser-dynamic": ">=14.1.0 < 16.0.0",
|
|
104
105
|
"@babel/core": "*",
|
|
105
106
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
|
106
107
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
|
@@ -123,5 +124,5 @@
|
|
|
123
124
|
"bundler": {
|
|
124
125
|
"tsConfig": "tsconfig.build.json"
|
|
125
126
|
},
|
|
126
|
-
"gitHead": "
|
|
127
|
+
"gitHead": "b8c17b23e92257c5a09b592dc6b557ba7b94ccea"
|
|
127
128
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
3
|
+
import { trigger, state, style, transition, animate } from '@angular/animations';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'app-open-close',
|
|
7
|
+
animations: [
|
|
8
|
+
trigger('openClose', [
|
|
9
|
+
// ...
|
|
10
|
+
state(
|
|
11
|
+
'open',
|
|
12
|
+
style({
|
|
13
|
+
height: '200px',
|
|
14
|
+
opacity: 1,
|
|
15
|
+
backgroundColor: 'yellow',
|
|
16
|
+
})
|
|
17
|
+
),
|
|
18
|
+
state(
|
|
19
|
+
'closed',
|
|
20
|
+
style({
|
|
21
|
+
height: '100px',
|
|
22
|
+
opacity: 0.8,
|
|
23
|
+
backgroundColor: 'blue',
|
|
24
|
+
})
|
|
25
|
+
),
|
|
26
|
+
transition('open => closed', [animate('0.1s')]),
|
|
27
|
+
transition('closed => open', [animate('0.1s')]),
|
|
28
|
+
]),
|
|
29
|
+
],
|
|
30
|
+
templateUrl: 'open-close.component.html',
|
|
31
|
+
styleUrls: ['open-close.component.css'],
|
|
32
|
+
})
|
|
33
|
+
export class OpenCloseComponent {
|
|
34
|
+
isOpen = true;
|
|
35
|
+
|
|
36
|
+
toggle() {
|
|
37
|
+
this.isOpen = !this.isOpen;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Meta, StoryFn } from '@storybook/angular';
|
|
2
|
+
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
|
3
|
+
import { within, userEvent } from '@storybook/testing-library';
|
|
4
|
+
import { expect } from '@storybook/jest';
|
|
5
|
+
import { OpenCloseComponent } from './angular-src/open-close-component/open-close.component';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
component: OpenCloseComponent,
|
|
9
|
+
parameters: {
|
|
10
|
+
chromatic: { delay: 100 },
|
|
11
|
+
},
|
|
12
|
+
} as Meta;
|
|
13
|
+
|
|
14
|
+
export const WithBrowserAnimations: StoryFn = () => ({
|
|
15
|
+
template: `<app-open-close></app-open-close>`,
|
|
16
|
+
moduleMetadata: {
|
|
17
|
+
declarations: [OpenCloseComponent],
|
|
18
|
+
imports: [BrowserAnimationsModule],
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
WithBrowserAnimations.play = async ({ canvasElement }) => {
|
|
23
|
+
const canvas = within(canvasElement);
|
|
24
|
+
const opened = canvas.getByText('The box is now Open!');
|
|
25
|
+
expect(opened).toBeDefined();
|
|
26
|
+
const submitButton = canvas.getByRole('button');
|
|
27
|
+
await userEvent.click(submitButton);
|
|
28
|
+
const closed = canvas.getByText('The box is now Closed!');
|
|
29
|
+
expect(closed).toBeDefined();
|
|
30
|
+
};
|