@storybook/angular 7.0.0-rc.9 → 7.0.1
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/README.md +85 -0
- package/dist/client/angular-beta/AbstractRenderer.js +14 -12
- package/dist/client/angular-beta/StorybookModule.d.ts +3 -1
- package/dist/client/angular-beta/StorybookModule.js +10 -2
- package/dist/client/angular-beta/StorybookModule.test.js +17 -0
- package/dist/client/angular-beta/StorybookWrapperComponent.d.ts +10 -4
- package/dist/client/angular-beta/StorybookWrapperComponent.js +2 -5
- package/dist/client/angular-beta/utils/PropertyExtractor.d.ts +4 -4
- package/dist/client/angular-beta/utils/PropertyExtractor.js +46 -20
- package/dist/client/angular-beta/utils/PropertyExtractor.test.js +14 -14
- package/dist/client/decorateStory.test.js +0 -31
- package/dist/client/decorators.d.ts +9 -0
- package/dist/client/decorators.js +25 -1
- package/dist/client/decorators.test.js +44 -4
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +2 -1
- package/dist/client/types.d.ts +15 -6
- package/dist/server/framework-preset-angular-docs.js +1 -5
- package/package.json +15 -15
- package/template/stories/basics/component-with-ng-on-destroy/component-with-on-destroy.stories.ts +2 -4
- package/template/stories/core/applicationConfig/with-browser-animations.stories.ts +40 -0
- package/template/stories/core/applicationConfig/with-noop-browser-animations.stories.ts +35 -0
- package/template/stories/others/ngx-translate/README.stories.mdx +22 -15
- package/dist/client/angular/app.component.d.ts +0 -38
- package/dist/client/angular/app.component.js +0 -141
- package/dist/client/angular/app.token.d.ts +0 -3
- package/dist/client/angular/app.token.js +0 -5
- package/template/stories/core/moduleMetadata/with-browser-animations.stories.ts +0 -30
- package/template/stories/core/moduleMetadata/with-noop-browser-animations.stories.ts +0 -27
package/README.md
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
- [Setup Compodoc](#setup-compodoc)
|
|
8
8
|
- [Automatic setup](#automatic-setup)
|
|
9
9
|
- [Manual setup](#manual-setup)
|
|
10
|
+
- [moduleMetadata decorator](#modulemetadata-decorator)
|
|
11
|
+
- [applicationConfig decorator](#applicationconfig-decorator)
|
|
10
12
|
- [FAQ](#faq)
|
|
11
13
|
- [How do I migrate to a Angular Storybook builder?](#how-do-i-migrate-to-a-angular-storybook-builder)
|
|
12
14
|
- [Do you have only one Angular project in your workspace?](#do-you-have-only-one-angular-project-in-your-workspace)
|
|
@@ -165,6 +167,89 @@ const preview: Preview = {
|
|
|
165
167
|
export default preview;
|
|
166
168
|
```
|
|
167
169
|
|
|
170
|
+
## moduleMetadata decorator
|
|
171
|
+
|
|
172
|
+
If your component has dependencies on other Angular directives and modules, these can be supplied using the moduleMetadata decorator either for all stories or for individual stories.
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
import { StoryFn, Meta, moduleMetadata } from '@storybook/angular';
|
|
176
|
+
import { SomeComponent } from './some.component';
|
|
177
|
+
|
|
178
|
+
export default {
|
|
179
|
+
component: SomeComponent,
|
|
180
|
+
decorators: [
|
|
181
|
+
// Apply metadata to all stories
|
|
182
|
+
moduleMetadata({
|
|
183
|
+
// import necessary ngModules or standalone components
|
|
184
|
+
imports: [...],
|
|
185
|
+
// declare components that are used in the template
|
|
186
|
+
declarations: [...],
|
|
187
|
+
// List of providers that should be available to the root component and all its children.
|
|
188
|
+
providers: [...],
|
|
189
|
+
}),
|
|
190
|
+
],
|
|
191
|
+
} as Meta;
|
|
192
|
+
|
|
193
|
+
const Template = (): StoryFn => (args) => ({
|
|
194
|
+
props: args,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
export const Base = Template();
|
|
198
|
+
|
|
199
|
+
export const WithCustomProvider = Template();
|
|
200
|
+
WithCustomProvider.decorators = [
|
|
201
|
+
// Apply metadata to a specific story
|
|
202
|
+
moduleMetadata({
|
|
203
|
+
imports: [...],
|
|
204
|
+
declarations: [...],
|
|
205
|
+
providers: [...]
|
|
206
|
+
}),
|
|
207
|
+
];
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## applicationConfig decorator
|
|
211
|
+
|
|
212
|
+
If your component relies on application-wide providers, like the ones defined by BrowserAnimationsModule or any other modules which use the forRoot pattern to provide a ModuleWithProviders, you can use the applicationConfig decorator on the meta default export to provide them to the [bootstrapApplication function](https://angular.io/guide/standalone-components#configuring-dependency-injection), which we use to bootstrap the component in Storybook.
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
|
|
216
|
+
import { StoryObj, Meta, applicationConfig } from '@storybook/angular';
|
|
217
|
+
import { BrowserAnimationsModule, provideAnimations } from '@angular/platform-browser/animations';
|
|
218
|
+
import { importProvidersFrom } from '@angular/core';
|
|
219
|
+
import { ChipsModule } from './angular-src/chips.module';
|
|
220
|
+
|
|
221
|
+
const meta: Meta = {
|
|
222
|
+
component: ChipsGroupComponent,
|
|
223
|
+
decorators: [
|
|
224
|
+
// Apply application config to all stories
|
|
225
|
+
applicationConfig({
|
|
226
|
+
// List of providers and environment providers that should be available to the root component and all its children.
|
|
227
|
+
providers: [
|
|
228
|
+
...
|
|
229
|
+
// Import application-wide providers from a module
|
|
230
|
+
importProvidersFrom(BrowserAnimationsModule)
|
|
231
|
+
// Or use provide-style functions if available instead, e.g.
|
|
232
|
+
provideAnimations()
|
|
233
|
+
],
|
|
234
|
+
}),
|
|
235
|
+
],
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
export default meta;
|
|
239
|
+
|
|
240
|
+
type Story = StoryObj<typeof ChipsGroupComponent>;
|
|
241
|
+
|
|
242
|
+
export const WithCustomApplicationProvider: Story = {
|
|
243
|
+
render: () => ({
|
|
244
|
+
// Apply application config to a specific story
|
|
245
|
+
applicationConfig: {
|
|
246
|
+
// The providers will be merged with the ones defined in the applicationConfig decorators providers array of the global meta object
|
|
247
|
+
providers: [...]
|
|
248
|
+
}
|
|
249
|
+
})
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
168
253
|
## FAQ
|
|
169
254
|
|
|
170
255
|
### How do I migrate to a Angular Storybook builder?
|
|
@@ -90,18 +90,20 @@ class AbstractRenderer {
|
|
|
90
90
|
this.storyProps$ = newStoryProps$;
|
|
91
91
|
this.initAngularRootElement(targetDOMNode, targetSelector);
|
|
92
92
|
const analyzedMetadata = new PropertyExtractor_1.PropertyExtractor(storyFnAngular.moduleMetadata, component);
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
93
|
+
const application = (0, StorybookModule_1.getApplication)({
|
|
94
|
+
storyFnAngular,
|
|
95
|
+
component,
|
|
96
|
+
targetSelector,
|
|
97
|
+
analyzedMetadata,
|
|
98
|
+
});
|
|
99
|
+
const applicationRef = await (0, platform_browser_1.bootstrapApplication)(application, {
|
|
100
|
+
...storyFnAngular.applicationConfig,
|
|
101
|
+
providers: [
|
|
102
|
+
(0, StorybookProvider_1.storyPropsProvider)(newStoryProps$),
|
|
103
|
+
...analyzedMetadata.applicationProviders,
|
|
104
|
+
...(storyFnAngular.applicationConfig?.providers ?? []),
|
|
105
|
+
],
|
|
106
|
+
});
|
|
105
107
|
applicationRefs.add(applicationRef);
|
|
106
108
|
await this.afterFullRender();
|
|
107
109
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { StoryFnAngularReturnType } from '../types';
|
|
2
|
-
|
|
2
|
+
import { PropertyExtractor } from './utils/PropertyExtractor';
|
|
3
|
+
export declare const getApplication: ({ storyFnAngular, component, targetSelector, analyzedMetadata, }: {
|
|
3
4
|
storyFnAngular: StoryFnAngularReturnType;
|
|
4
5
|
component?: any;
|
|
5
6
|
targetSelector: string;
|
|
7
|
+
analyzedMetadata: PropertyExtractor;
|
|
6
8
|
}) => import("@angular/core").Type<any>;
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getApplication = void 0;
|
|
4
4
|
const StorybookWrapperComponent_1 = require("./StorybookWrapperComponent");
|
|
5
5
|
const ComputesTemplateFromComponent_1 = require("./ComputesTemplateFromComponent");
|
|
6
|
-
const getApplication = ({ storyFnAngular, component, targetSelector, }) => {
|
|
6
|
+
const getApplication = ({ storyFnAngular, component, targetSelector, analyzedMetadata, }) => {
|
|
7
7
|
const { props, styles, moduleMetadata = {} } = storyFnAngular;
|
|
8
8
|
let { template } = storyFnAngular;
|
|
9
9
|
const hasTemplate = !hasNoTemplate(template);
|
|
@@ -13,7 +13,15 @@ const getApplication = ({ storyFnAngular, component, targetSelector, }) => {
|
|
|
13
13
|
/**
|
|
14
14
|
* Create a component that wraps generated template and gives it props
|
|
15
15
|
*/
|
|
16
|
-
return (0, StorybookWrapperComponent_1.createStorybookWrapperComponent)(
|
|
16
|
+
return (0, StorybookWrapperComponent_1.createStorybookWrapperComponent)({
|
|
17
|
+
moduleMetadata,
|
|
18
|
+
selector: targetSelector,
|
|
19
|
+
template,
|
|
20
|
+
storyComponent: component,
|
|
21
|
+
styles,
|
|
22
|
+
initialProps: props,
|
|
23
|
+
analyzedMetadata,
|
|
24
|
+
});
|
|
17
25
|
};
|
|
18
26
|
exports.getApplication = getApplication;
|
|
19
27
|
function hasNoTemplate(template) {
|
|
@@ -14,6 +14,7 @@ const testing_1 = require("@angular/core/testing");
|
|
|
14
14
|
const rxjs_1 = require("rxjs");
|
|
15
15
|
const StorybookModule_1 = require("./StorybookModule");
|
|
16
16
|
const StorybookProvider_1 = require("./StorybookProvider");
|
|
17
|
+
const PropertyExtractor_1 = require("./utils/PropertyExtractor");
|
|
17
18
|
describe('StorybookModule', () => {
|
|
18
19
|
describe('getStorybookModuleMetadata', () => {
|
|
19
20
|
describe('with simple component', () => {
|
|
@@ -70,10 +71,12 @@ describe('StorybookModule', () => {
|
|
|
70
71
|
localProperty: 'localProperty',
|
|
71
72
|
localFunction: () => 'localFunction',
|
|
72
73
|
};
|
|
74
|
+
const analyzedMetadata = new PropertyExtractor_1.PropertyExtractor({}, FooComponent);
|
|
73
75
|
const application = (0, StorybookModule_1.getApplication)({
|
|
74
76
|
storyFnAngular: { props },
|
|
75
77
|
component: FooComponent,
|
|
76
78
|
targetSelector: 'my-selector',
|
|
79
|
+
analyzedMetadata,
|
|
77
80
|
});
|
|
78
81
|
const { fixture } = await configureTestingModule({
|
|
79
82
|
imports: [application],
|
|
@@ -96,10 +99,12 @@ describe('StorybookModule', () => {
|
|
|
96
99
|
expectedOutputBindingValue = value;
|
|
97
100
|
},
|
|
98
101
|
};
|
|
102
|
+
const analyzedMetadata = new PropertyExtractor_1.PropertyExtractor({}, FooComponent);
|
|
99
103
|
const application = (0, StorybookModule_1.getApplication)({
|
|
100
104
|
storyFnAngular: { props },
|
|
101
105
|
component: FooComponent,
|
|
102
106
|
targetSelector: 'my-selector',
|
|
107
|
+
analyzedMetadata,
|
|
103
108
|
});
|
|
104
109
|
const { fixture } = await configureTestingModule({
|
|
105
110
|
imports: [application],
|
|
@@ -117,10 +122,12 @@ describe('StorybookModule', () => {
|
|
|
117
122
|
inputBindingPropertyName: '',
|
|
118
123
|
};
|
|
119
124
|
const storyProps$ = new rxjs_1.BehaviorSubject(initialProps);
|
|
125
|
+
const analyzedMetadata = new PropertyExtractor_1.PropertyExtractor({}, FooComponent);
|
|
120
126
|
const application = (0, StorybookModule_1.getApplication)({
|
|
121
127
|
storyFnAngular: { props: initialProps },
|
|
122
128
|
component: FooComponent,
|
|
123
129
|
targetSelector: 'my-selector',
|
|
130
|
+
analyzedMetadata,
|
|
124
131
|
});
|
|
125
132
|
const { fixture } = await configureTestingModule({
|
|
126
133
|
imports: [application],
|
|
@@ -155,10 +162,12 @@ describe('StorybookModule', () => {
|
|
|
155
162
|
},
|
|
156
163
|
};
|
|
157
164
|
const storyProps$ = new rxjs_1.BehaviorSubject(initialProps);
|
|
165
|
+
const analyzedMetadata = new PropertyExtractor_1.PropertyExtractor({}, FooComponent);
|
|
158
166
|
const application = (0, StorybookModule_1.getApplication)({
|
|
159
167
|
storyFnAngular: { props: initialProps },
|
|
160
168
|
component: FooComponent,
|
|
161
169
|
targetSelector: 'my-selector',
|
|
170
|
+
analyzedMetadata,
|
|
162
171
|
});
|
|
163
172
|
const { fixture } = await configureTestingModule({
|
|
164
173
|
imports: [application],
|
|
@@ -188,6 +197,7 @@ describe('StorybookModule', () => {
|
|
|
188
197
|
input: 'input',
|
|
189
198
|
};
|
|
190
199
|
const storyProps$ = new rxjs_1.BehaviorSubject(initialProps);
|
|
200
|
+
const analyzedMetadata = new PropertyExtractor_1.PropertyExtractor({}, FooComponent);
|
|
191
201
|
const application = (0, StorybookModule_1.getApplication)({
|
|
192
202
|
storyFnAngular: {
|
|
193
203
|
props: initialProps,
|
|
@@ -195,6 +205,7 @@ describe('StorybookModule', () => {
|
|
|
195
205
|
},
|
|
196
206
|
component: FooComponent,
|
|
197
207
|
targetSelector: 'my-selector',
|
|
208
|
+
analyzedMetadata,
|
|
198
209
|
});
|
|
199
210
|
const { fixture } = await configureTestingModule({
|
|
200
211
|
imports: [application],
|
|
@@ -217,10 +228,12 @@ describe('StorybookModule', () => {
|
|
|
217
228
|
setter: 'init',
|
|
218
229
|
};
|
|
219
230
|
const storyProps$ = new rxjs_1.BehaviorSubject(initialProps);
|
|
231
|
+
const analyzedMetadata = new PropertyExtractor_1.PropertyExtractor({}, FooComponent);
|
|
220
232
|
const application = (0, StorybookModule_1.getApplication)({
|
|
221
233
|
storyFnAngular: { props: initialProps },
|
|
222
234
|
component: FooComponent,
|
|
223
235
|
targetSelector: 'my-selector',
|
|
236
|
+
analyzedMetadata,
|
|
224
237
|
});
|
|
225
238
|
const { fixture } = await configureTestingModule({
|
|
226
239
|
imports: [application],
|
|
@@ -246,6 +259,7 @@ describe('StorybookModule', () => {
|
|
|
246
259
|
], WithoutSelectorComponent);
|
|
247
260
|
it('should display the component', async () => {
|
|
248
261
|
const props = {};
|
|
262
|
+
const analyzedMetadata = new PropertyExtractor_1.PropertyExtractor({ entryComponents: [WithoutSelectorComponent] }, WithoutSelectorComponent);
|
|
249
263
|
const application = (0, StorybookModule_1.getApplication)({
|
|
250
264
|
storyFnAngular: {
|
|
251
265
|
props,
|
|
@@ -253,6 +267,7 @@ describe('StorybookModule', () => {
|
|
|
253
267
|
},
|
|
254
268
|
component: WithoutSelectorComponent,
|
|
255
269
|
targetSelector: 'my-selector',
|
|
270
|
+
analyzedMetadata,
|
|
256
271
|
});
|
|
257
272
|
const { fixture } = await configureTestingModule({
|
|
258
273
|
imports: [application],
|
|
@@ -271,10 +286,12 @@ describe('StorybookModule', () => {
|
|
|
271
286
|
template: `Should not be displayed`,
|
|
272
287
|
})
|
|
273
288
|
], FooComponent);
|
|
289
|
+
const analyzedMetadata = new PropertyExtractor_1.PropertyExtractor({}, FooComponent);
|
|
274
290
|
const application = (0, StorybookModule_1.getApplication)({
|
|
275
291
|
storyFnAngular: { template: '' },
|
|
276
292
|
component: FooComponent,
|
|
277
293
|
targetSelector: 'my-selector',
|
|
294
|
+
analyzedMetadata,
|
|
278
295
|
});
|
|
279
296
|
const { fixture } = await configureTestingModule({
|
|
280
297
|
imports: [application],
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { Type } from '@angular/core';
|
|
2
2
|
import { ICollection, NgModuleMetadata } from '../types';
|
|
3
|
+
import { PropertyExtractor } from './utils/PropertyExtractor';
|
|
3
4
|
export declare const componentNgModules: Map<any, Type<any>>;
|
|
4
5
|
/**
|
|
5
6
|
* Wraps the story template into a component
|
|
6
|
-
*
|
|
7
|
-
* @param storyComponent
|
|
8
|
-
* @param initialProps
|
|
9
7
|
*/
|
|
10
|
-
export declare const createStorybookWrapperComponent: (selector
|
|
8
|
+
export declare const createStorybookWrapperComponent: ({ selector, template, storyComponent, styles, moduleMetadata, initialProps, analyzedMetadata, }: {
|
|
9
|
+
selector: string;
|
|
10
|
+
template: string;
|
|
11
|
+
storyComponent: Type<unknown> | undefined;
|
|
12
|
+
styles: string[];
|
|
13
|
+
moduleMetadata: NgModuleMetadata;
|
|
14
|
+
initialProps?: ICollection;
|
|
15
|
+
analyzedMetadata?: PropertyExtractor;
|
|
16
|
+
}) => Type<any>;
|
|
@@ -32,15 +32,11 @@ const getNonInputsOutputsProps = (ngComponentInputsOutputs, props = {}) => {
|
|
|
32
32
|
exports.componentNgModules = new Map();
|
|
33
33
|
/**
|
|
34
34
|
* Wraps the story template into a component
|
|
35
|
-
*
|
|
36
|
-
* @param storyComponent
|
|
37
|
-
* @param initialProps
|
|
38
35
|
*/
|
|
39
|
-
const createStorybookWrapperComponent = (selector, template, storyComponent, styles, moduleMetadata, initialProps) => {
|
|
36
|
+
const createStorybookWrapperComponent = ({ selector, template, storyComponent, styles, moduleMetadata, initialProps, analyzedMetadata, }) => {
|
|
40
37
|
// In ivy, a '' selector is not allowed, therefore we need to just set it to anything if
|
|
41
38
|
// storyComponent was not provided.
|
|
42
39
|
const viewChildSelector = storyComponent ?? '__storybook-noop';
|
|
43
|
-
const analyzedMetadata = new PropertyExtractor_1.PropertyExtractor(moduleMetadata, storyComponent);
|
|
44
40
|
const { imports, declarations, providers } = analyzedMetadata;
|
|
45
41
|
// Only create a new module if it doesn't already exist
|
|
46
42
|
// This is to prevent the module from being recreated on every story change
|
|
@@ -60,6 +56,7 @@ const createStorybookWrapperComponent = (selector, template, storyComponent, sty
|
|
|
60
56
|
exports.componentNgModules.set(storyComponent, StorybookComponentModule);
|
|
61
57
|
ngModule = exports.componentNgModules.get(storyComponent);
|
|
62
58
|
}
|
|
59
|
+
PropertyExtractor_1.PropertyExtractor.warnImportsModuleWithProviders(analyzedMetadata);
|
|
63
60
|
let StorybookWrapperComponent = class StorybookWrapperComponent {
|
|
64
61
|
constructor(storyProps$, changeDetectorRef) {
|
|
65
62
|
this.storyProps$ = storyProps$;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { InjectionToken, NgModule, Provider, ɵReflectionCapabilities as ReflectionCapabilities } from '@angular/core';
|
|
1
|
+
import { importProvidersFrom, InjectionToken, NgModule, Provider, ɵReflectionCapabilities as ReflectionCapabilities } from '@angular/core';
|
|
2
2
|
import { NgModuleMetadata } from '../../types';
|
|
3
3
|
export declare const reflectionCapabilities: ReflectionCapabilities;
|
|
4
4
|
export declare const REMOVED_MODULES: InjectionToken<unknown>;
|
|
@@ -9,21 +9,21 @@ export declare class PropertyExtractor implements NgModuleMetadata {
|
|
|
9
9
|
declarations?: any[];
|
|
10
10
|
imports?: any[];
|
|
11
11
|
providers?: Provider[];
|
|
12
|
-
|
|
12
|
+
applicationProviders?: Array<Provider | ReturnType<typeof importProvidersFrom>>;
|
|
13
13
|
constructor(metadata: NgModuleMetadata, component?: any);
|
|
14
|
+
static warnImportsModuleWithProviders(propertyExtractor: PropertyExtractor): void;
|
|
14
15
|
private init;
|
|
15
16
|
/**
|
|
16
17
|
* Analyze NgModule Metadata
|
|
17
18
|
*
|
|
18
19
|
* - Removes Restricted Imports
|
|
19
20
|
* - Extracts providers from ModuleWithProviders
|
|
20
|
-
* - Flattens imports
|
|
21
21
|
* - Returns a new NgModuleMetadata object
|
|
22
22
|
*
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
private analyzeMetadata;
|
|
26
|
-
static analyzeRestricted: (ngModule: NgModule) =>
|
|
26
|
+
static analyzeRestricted: (ngModule: NgModule) => [boolean] | [boolean, Provider];
|
|
27
27
|
static analyzeDecorators: (component: any) => {
|
|
28
28
|
isDeclarable: boolean;
|
|
29
29
|
isStandalone: boolean;
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
var _a;
|
|
3
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
7
|
exports.PropertyExtractor = exports.uniqueArray = exports.REMOVED_MODULES = exports.reflectionCapabilities = void 0;
|
|
8
|
+
/* eslint-disable no-console */
|
|
5
9
|
const common_1 = require("@angular/common");
|
|
6
10
|
const core_1 = require("@angular/core");
|
|
7
11
|
const platform_browser_1 = require("@angular/platform-browser");
|
|
8
12
|
const animations_1 = require("@angular/platform-browser/animations");
|
|
13
|
+
const ts_dedent_1 = __importDefault(require("ts-dedent"));
|
|
9
14
|
const NgModulesAnalyzer_1 = require("./NgModulesAnalyzer");
|
|
10
15
|
exports.reflectionCapabilities = new core_1.ɵReflectionCapabilities();
|
|
11
16
|
exports.REMOVED_MODULES = new core_1.InjectionToken('REMOVED_MODULES');
|
|
@@ -28,7 +33,6 @@ class PropertyExtractor {
|
|
|
28
33
|
*
|
|
29
34
|
* - Removes Restricted Imports
|
|
30
35
|
* - Extracts providers from ModuleWithProviders
|
|
31
|
-
* - Flattens imports
|
|
32
36
|
* - Returns a new NgModuleMetadata object
|
|
33
37
|
*
|
|
34
38
|
*
|
|
@@ -36,27 +40,41 @@ class PropertyExtractor {
|
|
|
36
40
|
this.analyzeMetadata = (metadata) => {
|
|
37
41
|
const declarations = [...(metadata?.declarations || [])];
|
|
38
42
|
const providers = [...(metadata?.providers || [])];
|
|
39
|
-
const
|
|
43
|
+
const applicationProviders = [];
|
|
40
44
|
const imports = [...(metadata?.imports || [])].reduce((acc, imported) => {
|
|
41
45
|
// remove ngModule and use only its providers if it is restricted
|
|
42
46
|
// (e.g. BrowserModule, BrowserAnimationsModule, NoopAnimationsModule, ...etc)
|
|
43
47
|
const [isRestricted, restrictedProviders] = PropertyExtractor.analyzeRestricted(imported);
|
|
44
48
|
if (isRestricted) {
|
|
45
|
-
|
|
49
|
+
applicationProviders.unshift(restrictedProviders || []);
|
|
46
50
|
return acc;
|
|
47
51
|
}
|
|
48
52
|
acc.push(imported);
|
|
49
53
|
return acc;
|
|
50
54
|
}, []);
|
|
51
|
-
return { ...metadata, imports, providers,
|
|
55
|
+
return { ...metadata, imports, providers, applicationProviders, declarations };
|
|
52
56
|
};
|
|
53
57
|
this.init();
|
|
54
58
|
}
|
|
59
|
+
// With the new way of mounting standalone components to the DOM via bootstrapApplication API,
|
|
60
|
+
// we should now pass ModuleWithProviders to the providers array of the bootstrapApplication function.
|
|
61
|
+
static warnImportsModuleWithProviders(propertyExtractor) {
|
|
62
|
+
const hasModuleWithProvidersImport = propertyExtractor.imports.some((importedModule) => 'ngModule' in importedModule);
|
|
63
|
+
if (hasModuleWithProvidersImport) {
|
|
64
|
+
console.warn((0, ts_dedent_1.default)(`
|
|
65
|
+
Storybook Warning:
|
|
66
|
+
moduleMetadata property 'imports' contains one or more ModuleWithProviders, likely the result of a 'Module.forRoot()'-style call.
|
|
67
|
+
In Storybook 7.0 we use Angular's new 'bootstrapApplication' API to mount the component to the DOM, which accepts a list of providers to set up application-wide providers.
|
|
68
|
+
Use the 'applicationConfig' decorator from '@storybook/angular' to pass your ModuleWithProviders to the 'providers' property in combination with the importProvidersFrom helper function from '@angular/core' to extract all the necessary providers.
|
|
69
|
+
Visit https://angular.io/guide/standalone-components#configuring-dependency-injection for more information
|
|
70
|
+
`));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
55
73
|
init() {
|
|
56
74
|
const analyzed = this.analyzeMetadata(this.metadata);
|
|
57
75
|
this.imports = (0, exports.uniqueArray)([common_1.CommonModule, analyzed.imports]);
|
|
58
76
|
this.providers = (0, exports.uniqueArray)(analyzed.providers);
|
|
59
|
-
this.
|
|
77
|
+
this.applicationProviders = (0, exports.uniqueArray)(analyzed.applicationProviders);
|
|
60
78
|
this.declarations = (0, exports.uniqueArray)(analyzed.declarations);
|
|
61
79
|
if (this.component) {
|
|
62
80
|
const { isDeclarable, isStandalone } = PropertyExtractor.analyzeDecorators(this.component);
|
|
@@ -73,28 +91,36 @@ class PropertyExtractor {
|
|
|
73
91
|
exports.PropertyExtractor = PropertyExtractor;
|
|
74
92
|
_a = PropertyExtractor;
|
|
75
93
|
PropertyExtractor.analyzeRestricted = (ngModule) => {
|
|
76
|
-
/**
|
|
77
|
-
* BrowserModule is restricted,
|
|
78
|
-
* because bootstrapApplication API, which mounts the component to the DOM,
|
|
79
|
-
* automatically imports BrowserModule
|
|
80
|
-
*/
|
|
81
94
|
if (ngModule === platform_browser_1.BrowserModule) {
|
|
95
|
+
console.warn((0, ts_dedent_1.default) `
|
|
96
|
+
Storybook Warning:
|
|
97
|
+
You have imported the "BrowserModule", which is not necessary anymore.
|
|
98
|
+
In Storybook v7.0 we are using Angular's new bootstrapApplication API to mount an Angular application to the DOM.
|
|
99
|
+
Note that the BrowserModule providers are automatically included when starting an application with bootstrapApplication()
|
|
100
|
+
Please remove the "BrowserModule" from the list of imports in your moduleMetadata definition to remove this warning.
|
|
101
|
+
`);
|
|
82
102
|
return [true];
|
|
83
103
|
}
|
|
84
|
-
/**
|
|
85
|
-
* BrowserAnimationsModule imports BrowserModule, which is restricted,
|
|
86
|
-
* because bootstrapApplication API, which mounts the component to the DOM,
|
|
87
|
-
* automatically imports BrowserModule
|
|
88
|
-
*/
|
|
89
104
|
if (ngModule === animations_1.BrowserAnimationsModule) {
|
|
105
|
+
console.warn((0, ts_dedent_1.default) `
|
|
106
|
+
Storybook Warning:
|
|
107
|
+
You have added the "BrowserAnimationsModule" to the list of "imports" in your moduleMetadata definition of your Story.
|
|
108
|
+
In Storybook 7.0 we use Angular's new 'bootstrapApplication' API to mount the component to the DOM, which accepts a list of providers to set up application-wide providers.
|
|
109
|
+
Use the 'applicationConfig' decorator from '@storybook/angular' and add the "provideAnimations" function to the list of "providers".
|
|
110
|
+
If your Angular version does not support "provide-like" functions, use the helper function importProvidersFrom instead to set up animations. For this case, please add "importProvidersFrom(BrowserAnimationsModule)" to the list of providers of your applicationConfig definition.
|
|
111
|
+
Please visit https://angular.io/guide/standalone-components#configuring-dependency-injection for more information.
|
|
112
|
+
`);
|
|
90
113
|
return [true, (0, animations_1.provideAnimations)()];
|
|
91
114
|
}
|
|
92
|
-
/**
|
|
93
|
-
* NoopAnimationsModule imports BrowserModule, which is restricted,
|
|
94
|
-
* because bootstrapApplication API, which mounts the component to the DOM,
|
|
95
|
-
* automatically imports BrowserModule
|
|
96
|
-
*/
|
|
97
115
|
if (ngModule === animations_1.NoopAnimationsModule) {
|
|
116
|
+
console.warn((0, ts_dedent_1.default) `
|
|
117
|
+
Storybook Warning:
|
|
118
|
+
You have added the "NoopAnimationsModule" to the list of "imports" in your moduleMetadata definition of your Story.
|
|
119
|
+
In Storybook v7.0 we are using Angular's new bootstrapApplication API to mount an Angular application to the DOM, which accepts a list of providers to set up application-wide providers.
|
|
120
|
+
Use the 'applicationConfig' decorator from '@storybook/angular' and add the "provideNoopAnimations" function to the list of "providers".
|
|
121
|
+
If your Angular version does not support "provide-like" functions, use the helper function importProvidersFrom instead to set up noop animations and to extract all necessary providers from NoopAnimationsModule. For this case, please add "importProvidersFrom(NoopAnimationsModule)" to the list of providers of your applicationConfig definition.
|
|
122
|
+
Please visit https://angular.io/guide/standalone-components#configuring-dependency-injection for more information.
|
|
123
|
+
`);
|
|
98
124
|
return [true, (0, animations_1.provideNoopAnimations)()];
|
|
99
125
|
}
|
|
100
126
|
return [false];
|
|
@@ -40,9 +40,9 @@ const extractProviders = (metadata, component) => {
|
|
|
40
40
|
const { providers } = new PropertyExtractor_1.PropertyExtractor(metadata, component);
|
|
41
41
|
return providers;
|
|
42
42
|
};
|
|
43
|
-
const
|
|
44
|
-
const {
|
|
45
|
-
return
|
|
43
|
+
const extractApplicationProviders = (metadata, component) => {
|
|
44
|
+
const { applicationProviders } = new PropertyExtractor_1.PropertyExtractor(metadata, component);
|
|
45
|
+
return applicationProviders;
|
|
46
46
|
};
|
|
47
47
|
describe('PropertyExtractor', () => {
|
|
48
48
|
describe('analyzeMetadata', () => {
|
|
@@ -50,46 +50,46 @@ describe('PropertyExtractor', () => {
|
|
|
50
50
|
const metadata = {
|
|
51
51
|
imports: [platform_browser_1.BrowserModule],
|
|
52
52
|
};
|
|
53
|
-
const { imports, providers,
|
|
53
|
+
const { imports, providers, applicationProviders } = analyzeMetadata(metadata);
|
|
54
54
|
expect(imports.flat(Number.MAX_VALUE)).toEqual([common_1.CommonModule]);
|
|
55
55
|
expect(providers.flat(Number.MAX_VALUE)).toEqual([]);
|
|
56
|
-
expect(
|
|
56
|
+
expect(applicationProviders.flat(Number.MAX_VALUE)).toEqual([]);
|
|
57
57
|
});
|
|
58
58
|
it('should remove BrowserAnimationsModule and use its providers instead', () => {
|
|
59
59
|
const metadata = {
|
|
60
60
|
imports: [animations_1.BrowserAnimationsModule],
|
|
61
61
|
};
|
|
62
|
-
const { imports, providers,
|
|
62
|
+
const { imports, providers, applicationProviders } = analyzeMetadata(metadata);
|
|
63
63
|
expect(imports.flat(Number.MAX_VALUE)).toEqual([common_1.CommonModule]);
|
|
64
64
|
expect(providers.flat(Number.MAX_VALUE)).toEqual([]);
|
|
65
|
-
expect(
|
|
65
|
+
expect(applicationProviders.flat(Number.MAX_VALUE)).toEqual((0, animations_1.provideAnimations)());
|
|
66
66
|
});
|
|
67
67
|
it('should remove NoopAnimationsModule and use its providers instead', () => {
|
|
68
68
|
const metadata = {
|
|
69
69
|
imports: [animations_1.NoopAnimationsModule],
|
|
70
70
|
};
|
|
71
|
-
const { imports, providers,
|
|
71
|
+
const { imports, providers, applicationProviders } = analyzeMetadata(metadata);
|
|
72
72
|
expect(imports.flat(Number.MAX_VALUE)).toEqual([common_1.CommonModule]);
|
|
73
73
|
expect(providers.flat(Number.MAX_VALUE)).toEqual([]);
|
|
74
|
-
expect(
|
|
74
|
+
expect(applicationProviders.flat(Number.MAX_VALUE)).toEqual((0, animations_1.provideNoopAnimations)());
|
|
75
75
|
});
|
|
76
76
|
it('should remove Browser/Animations modules recursively', () => {
|
|
77
77
|
const metadata = {
|
|
78
78
|
imports: [animations_1.BrowserAnimationsModule, platform_browser_1.BrowserModule],
|
|
79
79
|
};
|
|
80
|
-
const { imports, providers,
|
|
80
|
+
const { imports, providers, applicationProviders } = analyzeMetadata(metadata);
|
|
81
81
|
expect(imports.flat(Number.MAX_VALUE)).toEqual([common_1.CommonModule]);
|
|
82
82
|
expect(providers.flat(Number.MAX_VALUE)).toEqual([]);
|
|
83
|
-
expect(
|
|
83
|
+
expect(applicationProviders.flat(Number.MAX_VALUE)).toEqual((0, animations_1.provideAnimations)());
|
|
84
84
|
});
|
|
85
85
|
it('should not destructure Angular official module', () => {
|
|
86
86
|
const metadata = {
|
|
87
87
|
imports: [test_module_1.WithOfficialModule],
|
|
88
88
|
};
|
|
89
|
-
const { imports, providers,
|
|
89
|
+
const { imports, providers, applicationProviders } = analyzeMetadata(metadata);
|
|
90
90
|
expect(imports.flat(Number.MAX_VALUE)).toEqual([common_1.CommonModule, test_module_1.WithOfficialModule]);
|
|
91
91
|
expect(providers.flat(Number.MAX_VALUE)).toEqual([]);
|
|
92
|
-
expect(
|
|
92
|
+
expect(applicationProviders.flat(Number.MAX_VALUE)).toEqual([]);
|
|
93
93
|
});
|
|
94
94
|
});
|
|
95
95
|
describe('extractImports', () => {
|
|
@@ -132,7 +132,7 @@ describe('PropertyExtractor', () => {
|
|
|
132
132
|
expect(providers).toEqual([TestService]);
|
|
133
133
|
});
|
|
134
134
|
it('should return an array of singletons extracted', () => {
|
|
135
|
-
const singeltons =
|
|
135
|
+
const singeltons = extractApplicationProviders({
|
|
136
136
|
imports: [animations_1.BrowserAnimationsModule],
|
|
137
137
|
});
|
|
138
138
|
expect(singeltons).toEqual((0, animations_1.provideAnimations)());
|
|
@@ -169,37 +169,6 @@ describe('decorateStory', () => {
|
|
|
169
169
|
userDefinedTemplate: false,
|
|
170
170
|
});
|
|
171
171
|
});
|
|
172
|
-
it('should include legacy story components in decorators', () => {
|
|
173
|
-
const decorators = [
|
|
174
|
-
(s) => {
|
|
175
|
-
const story = s();
|
|
176
|
-
return {
|
|
177
|
-
...story,
|
|
178
|
-
template: `<parent>${story.template}</parent>`,
|
|
179
|
-
};
|
|
180
|
-
},
|
|
181
|
-
(s) => {
|
|
182
|
-
const story = s();
|
|
183
|
-
return {
|
|
184
|
-
...story,
|
|
185
|
-
template: `<grandparent>${story.template}</grandparent>`,
|
|
186
|
-
};
|
|
187
|
-
},
|
|
188
|
-
(s) => {
|
|
189
|
-
const story = s();
|
|
190
|
-
return {
|
|
191
|
-
...story,
|
|
192
|
-
template: `<great-grandparent>${story.template}</great-grandparent>`,
|
|
193
|
-
};
|
|
194
|
-
},
|
|
195
|
-
];
|
|
196
|
-
const decorated = (0, decorateStory_1.default)(() => ({ component: FooComponent }), decorators);
|
|
197
|
-
expect(decorated(makeContext({}))).toEqual({
|
|
198
|
-
template: '<great-grandparent><grandparent><parent><foo></foo></parent></grandparent></great-grandparent>',
|
|
199
|
-
component: FooComponent,
|
|
200
|
-
userDefinedTemplate: false,
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
172
|
it('should keep template with an empty value', () => {
|
|
204
173
|
const decorators = [
|
|
205
174
|
(0, decorators_1.componentWrapperDecorator)(ParentComponent),
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { Type } from '@angular/core';
|
|
2
|
+
import { ApplicationConfig } from '@angular/platform-browser';
|
|
2
3
|
import { DecoratorFunction, StoryContext } from '@storybook/types';
|
|
3
4
|
import { ICollection, NgModuleMetadata, AngularRenderer } from './types';
|
|
4
5
|
export declare const moduleMetadata: <TArgs = any>(metadata: Partial<NgModuleMetadata>) => DecoratorFunction<AngularRenderer, TArgs>;
|
|
6
|
+
/**
|
|
7
|
+
* Decorator to set the config options which are available during the application bootstrap operation
|
|
8
|
+
*/
|
|
9
|
+
export declare function applicationConfig<TArgs = any>(
|
|
10
|
+
/**
|
|
11
|
+
* Set of config options available during the application bootstrap operation.
|
|
12
|
+
*/
|
|
13
|
+
config: ApplicationConfig): DecoratorFunction<AngularRenderer, TArgs>;
|
|
5
14
|
export declare const componentWrapperDecorator: <TArgs = any>(element: Type<unknown> | ((story: string) => string), props?: ICollection | ((storyContext: StoryContext<AngularRenderer, TArgs>) => ICollection)) => DecoratorFunction<AngularRenderer, TArgs>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.componentWrapperDecorator = exports.moduleMetadata = void 0;
|
|
3
|
+
exports.componentWrapperDecorator = exports.applicationConfig = exports.moduleMetadata = void 0;
|
|
4
4
|
const ComputesTemplateFromComponent_1 = require("./angular-beta/ComputesTemplateFromComponent");
|
|
5
5
|
const NgComponentAnalyzer_1 = require("./angular-beta/utils/NgComponentAnalyzer");
|
|
6
6
|
// We use `any` here as the default type rather than `Args` because we need something that is
|
|
@@ -24,6 +24,30 @@ const moduleMetadata = (metadata) => (storyFn) => {
|
|
|
24
24
|
};
|
|
25
25
|
};
|
|
26
26
|
exports.moduleMetadata = moduleMetadata;
|
|
27
|
+
/**
|
|
28
|
+
* Decorator to set the config options which are available during the application bootstrap operation
|
|
29
|
+
*/
|
|
30
|
+
function applicationConfig(
|
|
31
|
+
/**
|
|
32
|
+
* Set of config options available during the application bootstrap operation.
|
|
33
|
+
*/
|
|
34
|
+
config) {
|
|
35
|
+
return (storyFn) => {
|
|
36
|
+
const story = storyFn();
|
|
37
|
+
const storyConfig = story.applicationConfig;
|
|
38
|
+
return {
|
|
39
|
+
...story,
|
|
40
|
+
applicationConfig: storyConfig || config
|
|
41
|
+
? {
|
|
42
|
+
...config,
|
|
43
|
+
...storyConfig,
|
|
44
|
+
providers: [...(config?.providers || []), ...(storyConfig?.providers || [])],
|
|
45
|
+
}
|
|
46
|
+
: undefined,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
exports.applicationConfig = applicationConfig;
|
|
27
51
|
const componentWrapperDecorator = (element, props) => (storyFn, storyContext) => {
|
|
28
52
|
const story = storyFn();
|
|
29
53
|
const currentProps = typeof props === 'function' ? props(storyContext) : props;
|
|
@@ -39,18 +39,58 @@ let MockComponent = class MockComponent {
|
|
|
39
39
|
MockComponent = __decorate([
|
|
40
40
|
(0, core_1.Component)({})
|
|
41
41
|
], MockComponent);
|
|
42
|
+
describe('applicationConfig', () => {
|
|
43
|
+
const provider1 = () => { };
|
|
44
|
+
const provider2 = () => { };
|
|
45
|
+
it('should apply global config', () => {
|
|
46
|
+
expect((0, decorators_1.applicationConfig)({
|
|
47
|
+
providers: [provider1],
|
|
48
|
+
})(() => ({}), defaultContext)).toEqual({
|
|
49
|
+
applicationConfig: {
|
|
50
|
+
providers: [provider1],
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
it('should apply story config', () => {
|
|
55
|
+
expect((0, decorators_1.applicationConfig)({
|
|
56
|
+
providers: [],
|
|
57
|
+
})(() => ({
|
|
58
|
+
applicationConfig: {
|
|
59
|
+
providers: [provider2],
|
|
60
|
+
},
|
|
61
|
+
}), {
|
|
62
|
+
...defaultContext,
|
|
63
|
+
})).toEqual({
|
|
64
|
+
applicationConfig: {
|
|
65
|
+
providers: [provider2],
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
it('should merge global and story config', () => {
|
|
70
|
+
expect((0, decorators_1.applicationConfig)({
|
|
71
|
+
providers: [provider1],
|
|
72
|
+
})(() => ({
|
|
73
|
+
applicationConfig: {
|
|
74
|
+
providers: [provider2],
|
|
75
|
+
},
|
|
76
|
+
}), {
|
|
77
|
+
...defaultContext,
|
|
78
|
+
})).toEqual({
|
|
79
|
+
applicationConfig: {
|
|
80
|
+
providers: [provider1, provider2],
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
});
|
|
42
85
|
describe('moduleMetadata', () => {
|
|
43
86
|
it('should add metadata to a story without it', () => {
|
|
44
87
|
const result = (0, decorators_1.moduleMetadata)({
|
|
45
88
|
imports: [MockModule],
|
|
46
89
|
providers: [MockService],
|
|
47
|
-
})(() => ({
|
|
48
|
-
component: MockComponent,
|
|
49
|
-
}),
|
|
90
|
+
})(() => ({}),
|
|
50
91
|
// deepscan-disable-next-line
|
|
51
92
|
defaultContext);
|
|
52
93
|
expect(result).toEqual({
|
|
53
|
-
component: MockComponent,
|
|
54
94
|
moduleMetadata: {
|
|
55
95
|
declarations: [],
|
|
56
96
|
entryComponents: [],
|
package/dist/client/index.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ import './globals';
|
|
|
2
2
|
export * from './public-api';
|
|
3
3
|
export * from './public-types';
|
|
4
4
|
export type { StoryFnAngularReturnType as IStory } from './types';
|
|
5
|
-
export { moduleMetadata, componentWrapperDecorator } from './decorators';
|
|
5
|
+
export { moduleMetadata, componentWrapperDecorator, applicationConfig } from './decorators';
|
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.componentWrapperDecorator = exports.moduleMetadata = void 0;
|
|
18
|
+
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);
|
|
@@ -24,5 +24,6 @@ __exportStar(require("./public-types"), exports);
|
|
|
24
24
|
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
|
+
Object.defineProperty(exports, "applicationConfig", { enumerable: true, get: function () { return decorators_1.applicationConfig; } });
|
|
27
28
|
// optimization: stop HMR propagation in webpack
|
|
28
29
|
module?.hot?.decline();
|
package/dist/client/types.d.ts
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
1
|
+
import { Provider } from '@angular/core';
|
|
2
|
+
import { ApplicationConfig } from '@angular/platform-browser';
|
|
1
3
|
import { Parameters as DefaultParameters, StoryContext as DefaultStoryContext, WebRenderer } from '@storybook/types';
|
|
2
4
|
export interface NgModuleMetadata {
|
|
5
|
+
/**
|
|
6
|
+
* List of components, directives, and pipes that belong to your component.
|
|
7
|
+
*/
|
|
3
8
|
declarations?: any[];
|
|
4
9
|
entryComponents?: any[];
|
|
10
|
+
/**
|
|
11
|
+
* List of modules that should be available to the root Storybook Component and all its children.
|
|
12
|
+
* If you want to register application providers or if you want to use the forRoot() pattern, please use the `applicationConfig` decorator in combination with the importProvidersFrom helper function from @angular/core instead.
|
|
13
|
+
*/
|
|
5
14
|
imports?: any[];
|
|
6
15
|
schemas?: any[];
|
|
7
|
-
|
|
8
|
-
|
|
16
|
+
/**
|
|
17
|
+
* List of providers that should be available on the root component and all its children.
|
|
18
|
+
* Use the `applicationConfig` decorator to register environemt and application-wide providers.
|
|
19
|
+
*/
|
|
20
|
+
providers?: Provider[];
|
|
9
21
|
}
|
|
10
22
|
export interface ICollection {
|
|
11
23
|
[p: string]: any;
|
|
12
24
|
}
|
|
13
25
|
export interface StoryFnAngularReturnType {
|
|
14
|
-
/** @deprecated `component` story input is deprecated, and will be removed in Storybook 7.0. */
|
|
15
|
-
component?: any;
|
|
16
26
|
props?: ICollection;
|
|
17
|
-
/** @deprecated `propsMeta` story input is deprecated, and will be removed in Storybook 7.0. */
|
|
18
|
-
propsMeta?: ICollection;
|
|
19
27
|
moduleMetadata?: NgModuleMetadata;
|
|
28
|
+
applicationConfig?: ApplicationConfig;
|
|
20
29
|
template?: string;
|
|
21
30
|
styles?: string[];
|
|
22
31
|
userDefinedTemplate?: boolean;
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.previewAnnotations = void 0;
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
4
|
const docs_tools_1 = require("@storybook/docs-tools");
|
|
9
5
|
const previewAnnotations = (entry = [], options) => {
|
|
10
6
|
if (!(0, docs_tools_1.hasDocsOrControls)(options))
|
|
11
7
|
return entry;
|
|
12
|
-
return [...entry,
|
|
8
|
+
return [...entry, require.resolve('../client/docs/config')];
|
|
13
9
|
};
|
|
14
10
|
exports.previewAnnotations = previewAnnotations;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storybook/angular",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.1",
|
|
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.
|
|
40
|
-
"@storybook/cli": "7.0.
|
|
41
|
-
"@storybook/client-logger": "7.0.
|
|
42
|
-
"@storybook/core-client": "7.0.
|
|
43
|
-
"@storybook/core-common": "7.0.
|
|
44
|
-
"@storybook/core-events": "7.0.
|
|
45
|
-
"@storybook/core-server": "7.0.
|
|
46
|
-
"@storybook/core-webpack": "7.0.
|
|
47
|
-
"@storybook/docs-tools": "7.0.
|
|
39
|
+
"@storybook/builder-webpack5": "7.0.1",
|
|
40
|
+
"@storybook/cli": "7.0.1",
|
|
41
|
+
"@storybook/client-logger": "7.0.1",
|
|
42
|
+
"@storybook/core-client": "7.0.1",
|
|
43
|
+
"@storybook/core-common": "7.0.1",
|
|
44
|
+
"@storybook/core-events": "7.0.1",
|
|
45
|
+
"@storybook/core-server": "7.0.1",
|
|
46
|
+
"@storybook/core-webpack": "7.0.1",
|
|
47
|
+
"@storybook/docs-tools": "7.0.1",
|
|
48
48
|
"@storybook/global": "^5.0.0",
|
|
49
|
-
"@storybook/manager-api": "7.0.
|
|
50
|
-
"@storybook/node-logger": "7.0.
|
|
51
|
-
"@storybook/preview-api": "7.0.
|
|
52
|
-
"@storybook/types": "7.0.
|
|
49
|
+
"@storybook/manager-api": "7.0.1",
|
|
50
|
+
"@storybook/node-logger": "7.0.1",
|
|
51
|
+
"@storybook/preview-api": "7.0.1",
|
|
52
|
+
"@storybook/types": "7.0.1",
|
|
53
53
|
"@types/node": "^16.0.0",
|
|
54
54
|
"@types/react": "^16.14.34",
|
|
55
55
|
"@types/react-dom": "^16.9.14",
|
|
@@ -123,5 +123,5 @@
|
|
|
123
123
|
"bundler": {
|
|
124
124
|
"tsConfig": "tsconfig.build.json"
|
|
125
125
|
},
|
|
126
|
-
"gitHead": "
|
|
126
|
+
"gitHead": "2fe0c39167a40d6856f5cbc2ab927b3b65fc384b"
|
|
127
127
|
}
|
package/template/stories/basics/component-with-ng-on-destroy/component-with-on-destroy.stories.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OnDestroy, OnInit, Component } from '@angular/core';
|
|
2
|
-
import { Meta,
|
|
2
|
+
import { Meta, StoryObj } from '@storybook/angular';
|
|
3
3
|
|
|
4
4
|
@Component({
|
|
5
5
|
selector: 'on-destroy',
|
|
@@ -37,6 +37,4 @@ export default {
|
|
|
37
37
|
},
|
|
38
38
|
} as Meta;
|
|
39
39
|
|
|
40
|
-
export const SimpleComponent:
|
|
41
|
-
component: OnDestroyComponent,
|
|
42
|
-
});
|
|
40
|
+
export const SimpleComponent: StoryObj = {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Meta, StoryObj, applicationConfig } 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 { importProvidersFrom } from '@angular/core';
|
|
6
|
+
import { OpenCloseComponent } from '../moduleMetadata/angular-src/open-close-component/open-close.component';
|
|
7
|
+
|
|
8
|
+
const meta: Meta = {
|
|
9
|
+
component: OpenCloseComponent,
|
|
10
|
+
decorators: [
|
|
11
|
+
applicationConfig({
|
|
12
|
+
providers: [importProvidersFrom(BrowserAnimationsModule)],
|
|
13
|
+
}),
|
|
14
|
+
],
|
|
15
|
+
parameters: {
|
|
16
|
+
chromatic: { delay: 100 },
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default meta;
|
|
21
|
+
|
|
22
|
+
type Story = StoryObj<typeof OpenCloseComponent>;
|
|
23
|
+
|
|
24
|
+
export const WithBrowserAnimations: Story = {
|
|
25
|
+
render: () => ({
|
|
26
|
+
template: `<app-open-close></app-open-close>`,
|
|
27
|
+
moduleMetadata: {
|
|
28
|
+
declarations: [OpenCloseComponent],
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
play: async ({ canvasElement }) => {
|
|
32
|
+
const canvas = within(canvasElement);
|
|
33
|
+
const opened = canvas.getByText('The box is now Open!');
|
|
34
|
+
expect(opened).toBeDefined();
|
|
35
|
+
const submitButton = canvas.getByRole('button');
|
|
36
|
+
await userEvent.click(submitButton);
|
|
37
|
+
const closed = canvas.getByText('The box is now Closed!');
|
|
38
|
+
expect(closed).toBeDefined();
|
|
39
|
+
},
|
|
40
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/angular';
|
|
2
|
+
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
|
3
|
+
import { within, userEvent } from '@storybook/testing-library';
|
|
4
|
+
import { expect } from '@storybook/jest';
|
|
5
|
+
import { importProvidersFrom } from '@angular/core';
|
|
6
|
+
import { OpenCloseComponent } from '../moduleMetadata/angular-src/open-close-component/open-close.component';
|
|
7
|
+
|
|
8
|
+
const meta: Meta = {
|
|
9
|
+
component: OpenCloseComponent,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default meta;
|
|
13
|
+
|
|
14
|
+
type Story = StoryObj<typeof OpenCloseComponent>;
|
|
15
|
+
|
|
16
|
+
export const WithNoopBrowserAnimations: Story = {
|
|
17
|
+
render: () => ({
|
|
18
|
+
template: `<app-open-close></app-open-close>`,
|
|
19
|
+
applicationConfig: {
|
|
20
|
+
providers: [importProvidersFrom(NoopAnimationsModule)],
|
|
21
|
+
},
|
|
22
|
+
moduleMetadata: {
|
|
23
|
+
declarations: [OpenCloseComponent],
|
|
24
|
+
},
|
|
25
|
+
}),
|
|
26
|
+
play: async ({ canvasElement }) => {
|
|
27
|
+
const canvas = within(canvasElement);
|
|
28
|
+
const opened = canvas.getByText('The box is now Open!');
|
|
29
|
+
expect(opened).toBeDefined();
|
|
30
|
+
const submitButton = canvas.getByRole('button');
|
|
31
|
+
await userEvent.click(submitButton);
|
|
32
|
+
const closed = canvas.getByText('The box is now Closed!');
|
|
33
|
+
expect(closed).toBeDefined();
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -15,7 +15,7 @@ Here is a simple example with a storybook decorator that you can place in the `p
|
|
|
15
15
|
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
|
16
16
|
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
|
17
17
|
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
|
18
|
-
import { moduleMetadata } from '@storybook/angular';
|
|
18
|
+
import { moduleMetadata, applicationConfig } from '@storybook/angular';
|
|
19
19
|
|
|
20
20
|
function createTranslateLoader(http: HttpClient) {
|
|
21
21
|
return new TranslateHttpLoader(http, '/assets/i18n/', '.json');
|
|
@@ -24,23 +24,30 @@ function createTranslateLoader(http: HttpClient) {
|
|
|
24
24
|
const TranslateModuleDecorator = (storyFunc, context) => {
|
|
25
25
|
const { locale } = context.globals;
|
|
26
26
|
|
|
27
|
-
return
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
return applicationConfig({
|
|
28
|
+
providers: [
|
|
29
|
+
importProvidersFrom(
|
|
30
|
+
HttpClientModule,
|
|
31
|
+
TranslateModule.forRoot({
|
|
32
|
+
defaultLanguage: locale,
|
|
33
|
+
loader: {
|
|
34
|
+
provide: TranslateLoader,
|
|
35
|
+
useFactory: createTranslateLoader,
|
|
36
|
+
deps: [HttpClient],
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
)
|
|
40
|
+
]
|
|
39
41
|
})(storyFunc, context);
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
// for `preview.ts`
|
|
43
|
-
export const decorators = [
|
|
45
|
+
export const decorators = [
|
|
46
|
+
moduleMetadata({
|
|
47
|
+
imports: [TranslateModule],
|
|
48
|
+
}),
|
|
49
|
+
TranslateModuleDecorator,
|
|
50
|
+
];
|
|
44
51
|
```
|
|
45
52
|
|
|
46
53
|
If the `TranslateModule.forRoot` is made by another module you can try to set this provider `DEFAULT_LANGUAGE`
|
|
@@ -51,7 +58,7 @@ import { DEFAULT_LANGUAGE } from '@ngx-translate/core';
|
|
|
51
58
|
const TranslateModuleDecorator = (storyFunc, context) => {
|
|
52
59
|
const { locale } = context.globals;
|
|
53
60
|
|
|
54
|
-
return
|
|
61
|
+
return applicationConfig({
|
|
55
62
|
providers: [{ provide: DEFAULT_LANGUAGE, useValue: locale }],
|
|
56
63
|
})(storyFunc, context);
|
|
57
64
|
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { ViewContainerRef, ChangeDetectorRef, OnInit, ComponentFactoryResolver, OnDestroy } from '@angular/core';
|
|
2
|
-
import { Observable, Subscription } from 'rxjs';
|
|
3
|
-
import { StoryFnAngularReturnType } from '../types';
|
|
4
|
-
export declare class AppComponent implements OnInit, OnDestroy {
|
|
5
|
-
private cfr;
|
|
6
|
-
private changeDetectorRef;
|
|
7
|
-
private data;
|
|
8
|
-
target: ViewContainerRef;
|
|
9
|
-
readonly previousValues: {
|
|
10
|
-
[key: string]: any;
|
|
11
|
-
};
|
|
12
|
-
subscription: Subscription;
|
|
13
|
-
propSubscriptions: Map<any, {
|
|
14
|
-
prop: any;
|
|
15
|
-
sub: Subscription;
|
|
16
|
-
}>;
|
|
17
|
-
constructor(cfr: ComponentFactoryResolver, changeDetectorRef: ChangeDetectorRef, data: Observable<StoryFnAngularReturnType>);
|
|
18
|
-
ngOnInit(): void;
|
|
19
|
-
ngOnDestroy(): void;
|
|
20
|
-
/**
|
|
21
|
-
* Set inputs and outputs
|
|
22
|
-
*/
|
|
23
|
-
private setProps;
|
|
24
|
-
/**
|
|
25
|
-
* Manually call 'ngOnChanges' hook because angular doesn't do that for dynamic components
|
|
26
|
-
* Issue: [https://github.com/angular/angular/issues/8903]
|
|
27
|
-
*/
|
|
28
|
-
private callNgOnChangesHook;
|
|
29
|
-
/**
|
|
30
|
-
* If component implements ControlValueAccessor interface try to set ngModel
|
|
31
|
-
*/
|
|
32
|
-
private setNgModel;
|
|
33
|
-
/**
|
|
34
|
-
* Store ref to subscription for cleanup in 'ngOnDestroy' and check if
|
|
35
|
-
* observable needs to be resubscribed to, before creating a new subscription.
|
|
36
|
-
*/
|
|
37
|
-
private setPropSubscription;
|
|
38
|
-
}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
-
};
|
|
8
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
-
};
|
|
11
|
-
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
-
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.AppComponent = void 0;
|
|
16
|
-
// We could use NgComponentOutlet here but there's currently no easy way
|
|
17
|
-
// to provide @Inputs and subscribe to @Outputs, see
|
|
18
|
-
// https://github.com/angular/angular/issues/15360
|
|
19
|
-
// For the time being, the ViewContainerRef approach works pretty well.
|
|
20
|
-
const core_1 = require("@angular/core");
|
|
21
|
-
const rxjs_1 = require("rxjs");
|
|
22
|
-
const operators_1 = require("rxjs/operators");
|
|
23
|
-
const app_token_1 = require("./app.token");
|
|
24
|
-
let AppComponent = class AppComponent {
|
|
25
|
-
constructor(cfr, changeDetectorRef, data) {
|
|
26
|
-
this.cfr = cfr;
|
|
27
|
-
this.changeDetectorRef = changeDetectorRef;
|
|
28
|
-
this.data = data;
|
|
29
|
-
this.previousValues = {};
|
|
30
|
-
this.propSubscriptions = new Map();
|
|
31
|
-
}
|
|
32
|
-
ngOnInit() {
|
|
33
|
-
this.data.pipe((0, operators_1.first)()).subscribe((data) => {
|
|
34
|
-
this.target.clear();
|
|
35
|
-
const compFactory = this.cfr.resolveComponentFactory(data.component);
|
|
36
|
-
const componentRef = this.target.createComponent(compFactory);
|
|
37
|
-
const { instance } = componentRef;
|
|
38
|
-
// For some reason, manual change detection ref is only working when getting the ref from the injector (rather than componentRef.changeDetectorRef)
|
|
39
|
-
const childChangeDetectorRef = componentRef.injector.get(core_1.ChangeDetectorRef);
|
|
40
|
-
this.subscription = this.data.subscribe((newData) => {
|
|
41
|
-
this.setProps(instance, newData);
|
|
42
|
-
childChangeDetectorRef.markForCheck();
|
|
43
|
-
// Must detect changes on the current component in order to update any changes in child component's @HostBinding properties (angular/angular#22560)
|
|
44
|
-
this.changeDetectorRef.detectChanges();
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
ngOnDestroy() {
|
|
49
|
-
this.target.clear();
|
|
50
|
-
if (this.subscription) {
|
|
51
|
-
this.subscription.unsubscribe();
|
|
52
|
-
}
|
|
53
|
-
this.propSubscriptions.forEach((v) => {
|
|
54
|
-
if (!v.sub.closed) {
|
|
55
|
-
v.sub.unsubscribe();
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
this.propSubscriptions.clear();
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Set inputs and outputs
|
|
62
|
-
*/
|
|
63
|
-
setProps(instance, { props = {} }) {
|
|
64
|
-
const changes = {};
|
|
65
|
-
const hasNgOnChangesHook = !!instance.ngOnChanges;
|
|
66
|
-
Object.keys(props).forEach((key) => {
|
|
67
|
-
const value = props[key];
|
|
68
|
-
const instanceProperty = instance[key];
|
|
69
|
-
if (!(instanceProperty instanceof core_1.EventEmitter) && value !== undefined && value !== null) {
|
|
70
|
-
// eslint-disable-next-line no-param-reassign
|
|
71
|
-
instance[key] = value;
|
|
72
|
-
if (hasNgOnChangesHook) {
|
|
73
|
-
const previousValue = this.previousValues[key];
|
|
74
|
-
if (previousValue !== value) {
|
|
75
|
-
changes[key] = new core_1.SimpleChange(previousValue, value, !Object.prototype.hasOwnProperty.call(this.previousValues, key));
|
|
76
|
-
this.previousValues[key] = value;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
else if (typeof value === 'function' && key !== 'ngModelChange') {
|
|
81
|
-
this.setPropSubscription(key, instanceProperty, value);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
this.callNgOnChangesHook(instance, changes);
|
|
85
|
-
this.setNgModel(instance, props);
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Manually call 'ngOnChanges' hook because angular doesn't do that for dynamic components
|
|
89
|
-
* Issue: [https://github.com/angular/angular/issues/8903]
|
|
90
|
-
*/
|
|
91
|
-
callNgOnChangesHook(instance, changes) {
|
|
92
|
-
if (Object.keys(changes).length) {
|
|
93
|
-
instance.ngOnChanges(changes);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* If component implements ControlValueAccessor interface try to set ngModel
|
|
98
|
-
*/
|
|
99
|
-
setNgModel(instance, props) {
|
|
100
|
-
if (props.ngModel) {
|
|
101
|
-
instance.writeValue(props.ngModel);
|
|
102
|
-
}
|
|
103
|
-
if (typeof props.ngModelChange === 'function') {
|
|
104
|
-
instance.registerOnChange(props.ngModelChange);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Store ref to subscription for cleanup in 'ngOnDestroy' and check if
|
|
109
|
-
* observable needs to be resubscribed to, before creating a new subscription.
|
|
110
|
-
*/
|
|
111
|
-
setPropSubscription(key, instanceProperty, value) {
|
|
112
|
-
if (this.propSubscriptions.has(key)) {
|
|
113
|
-
const v = this.propSubscriptions.get(key);
|
|
114
|
-
if (v.prop === value) {
|
|
115
|
-
// Prop hasn't changed, so the existing subscription can stay.
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
// Now that the value has changed, unsubscribe from the previous value's subscription.
|
|
119
|
-
if (!v.sub.closed) {
|
|
120
|
-
v.sub.unsubscribe();
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
const sub = instanceProperty.subscribe(value);
|
|
124
|
-
this.propSubscriptions.set(key, { prop: value, sub });
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
__decorate([
|
|
128
|
-
(0, core_1.ViewChild)('target', { read: core_1.ViewContainerRef, static: true }),
|
|
129
|
-
__metadata("design:type", core_1.ViewContainerRef)
|
|
130
|
-
], AppComponent.prototype, "target", void 0);
|
|
131
|
-
AppComponent = __decorate([
|
|
132
|
-
(0, core_1.Component)({
|
|
133
|
-
selector: 'storybook-dynamic-app-root',
|
|
134
|
-
template: '<ng-template #target></ng-template>',
|
|
135
|
-
}),
|
|
136
|
-
__param(2, (0, core_1.Inject)(app_token_1.STORY)),
|
|
137
|
-
__metadata("design:paramtypes", [core_1.ComponentFactoryResolver,
|
|
138
|
-
core_1.ChangeDetectorRef,
|
|
139
|
-
rxjs_1.Observable])
|
|
140
|
-
], AppComponent);
|
|
141
|
-
exports.AppComponent = AppComponent;
|
|
@@ -1,30 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { Meta, StoryFn } from '@storybook/angular';
|
|
2
|
-
import { NoopAnimationsModule } 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
|
-
} as Meta;
|
|
10
|
-
|
|
11
|
-
export const WithNoopBrowserAnimations: StoryFn = () => ({
|
|
12
|
-
template: `<app-open-close></app-open-close>`,
|
|
13
|
-
moduleMetadata: {
|
|
14
|
-
declarations: [OpenCloseComponent],
|
|
15
|
-
imports: [NoopAnimationsModule],
|
|
16
|
-
},
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
WithNoopBrowserAnimations.play = async ({ canvasElement }) => {
|
|
20
|
-
const canvas = within(canvasElement);
|
|
21
|
-
const opened = canvas.getByText('The box is now Open!');
|
|
22
|
-
expect(opened).toBeDefined();
|
|
23
|
-
const submitButton = canvas.getByRole('button');
|
|
24
|
-
await userEvent.click(submitButton);
|
|
25
|
-
const closed = canvas.getByText('The box is now Closed!');
|
|
26
|
-
expect(closed).toBeDefined();
|
|
27
|
-
};
|