mirror of
https://github.com/storybookjs/storybook.git
synced 2025-03-17 05:02:23 +08:00
Adding extra metadata to module/components
This commit is contained in:
parent
9504ef8415
commit
82c1642923
23
addons/knobs/src/angular/helpers.js
vendored
23
addons/knobs/src/angular/helpers.js
vendored
@ -3,7 +3,7 @@
|
||||
import { Component, SimpleChange, ChangeDetectorRef } from '@angular/core';
|
||||
import { getParameters, getAnnotations, getPropMetadata } from './utils';
|
||||
|
||||
const getComponentMetadata = ({ component, props = {}, pipes = [] }) => {
|
||||
const getComponentMetadata = ({ component, props = {}, moduleMetadata }) => {
|
||||
if (!component || typeof component !== 'function') throw new Error('No valid component provided');
|
||||
|
||||
const componentMeta = getAnnotations(component)[0] || {};
|
||||
@ -13,9 +13,9 @@ const getComponentMetadata = ({ component, props = {}, pipes = [] }) => {
|
||||
return {
|
||||
component,
|
||||
props,
|
||||
pipes,
|
||||
componentMeta,
|
||||
propsMeta,
|
||||
moduleMetadata,
|
||||
params: paramsMetadata,
|
||||
};
|
||||
};
|
||||
@ -35,7 +35,7 @@ const getAnnotatedComponent = ({ componentMeta, component, params, knobStore, ch
|
||||
KnobWrapperComponent.prototype.constructor = KnobWrapperComponent;
|
||||
KnobWrapperComponent.prototype.ngOnInit = function onInit() {
|
||||
if (component.prototype.ngOnInit) {
|
||||
component.prototype.ngOnInit();
|
||||
component.prototype.ngOnInit.call(this);
|
||||
}
|
||||
|
||||
channel.on('addon:knobs:knobChange', this.knobChanged);
|
||||
@ -46,7 +46,7 @@ const getAnnotatedComponent = ({ componentMeta, component, params, knobStore, ch
|
||||
|
||||
KnobWrapperComponent.prototype.ngOnDestroy = function onDestroy() {
|
||||
if (component.prototype.ngOnDestroy) {
|
||||
component.prototype.ngOnDestroy();
|
||||
component.prototype.ngOnDestroy.call(this);
|
||||
}
|
||||
|
||||
channel.removeListener('addon:knobs:knobChange', this.knobChanged);
|
||||
@ -56,7 +56,7 @@ const getAnnotatedComponent = ({ componentMeta, component, params, knobStore, ch
|
||||
|
||||
KnobWrapperComponent.prototype.ngOnChanges = function onChanges(changes) {
|
||||
if (component.prototype.ngOnChanges) {
|
||||
component.prototype.ngOnChanges(changes);
|
||||
component.prototype.ngOnChanges.call(this, changes);
|
||||
}
|
||||
};
|
||||
|
||||
@ -99,9 +99,14 @@ const resetKnobs = (knobStore, channel) => {
|
||||
|
||||
export function prepareComponent({ getStory, context, channel, knobStore }) {
|
||||
resetKnobs(knobStore, channel);
|
||||
const { component, componentMeta, props, pipes, propsMeta, params } = getComponentMetadata(
|
||||
getStory(context)
|
||||
);
|
||||
const {
|
||||
component,
|
||||
componentMeta,
|
||||
props,
|
||||
propsMeta,
|
||||
params,
|
||||
moduleMetadata,
|
||||
} = getComponentMetadata(getStory(context));
|
||||
|
||||
if (!componentMeta) throw new Error('No component metadata available');
|
||||
|
||||
@ -116,7 +121,7 @@ export function prepareComponent({ getStory, context, channel, knobStore }) {
|
||||
return {
|
||||
component: AnnotatedComponent,
|
||||
props,
|
||||
pipes,
|
||||
propsMeta,
|
||||
moduleMetadata,
|
||||
};
|
||||
}
|
||||
|
@ -1,10 +1,4 @@
|
||||
import { InjectionToken, PipeTransform } from "@angular/core";
|
||||
import { InjectionToken } from "@angular/core";
|
||||
import { Data } from "./types";
|
||||
|
||||
export const STORY = new InjectionToken<Data>("story");
|
||||
|
||||
export type Data = {
|
||||
component: any;
|
||||
props: object;
|
||||
propsMeta: object;
|
||||
pipes: PipeTransform[];
|
||||
}
|
@ -13,7 +13,8 @@ import {
|
||||
OnDestroy,
|
||||
EventEmitter
|
||||
} from "@angular/core";
|
||||
import { STORY, Data } from "../app.token";
|
||||
import { STORY } from "../app.token";
|
||||
import { Data } from "../types";
|
||||
|
||||
@Component({
|
||||
selector: "my-app",
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { STORY, Data } from "../app.token";
|
||||
import { STORY } from "../app.token";
|
||||
import { Data } from "../types";
|
||||
|
||||
@Component({
|
||||
selector: "my-app",
|
||||
|
@ -2,7 +2,9 @@ import {
|
||||
enableProdMode,
|
||||
NgModule,
|
||||
Component,
|
||||
CUSTOM_ELEMENTS_SCHEMA
|
||||
CUSTOM_ELEMENTS_SCHEMA,
|
||||
NgModuleRef,
|
||||
ApplicationRef
|
||||
} from "@angular/core";
|
||||
|
||||
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
|
||||
@ -12,6 +14,7 @@ import { ErrorComponent } from "./components/error.component";
|
||||
import { NoPreviewComponent } from "./components/no-preview.component";
|
||||
import { STORY } from "./app.token";
|
||||
import { getAnnotations, getParameters, getPropMetadata } from './utils';
|
||||
import { NgModuleMetadata, NgStory } from "./types";
|
||||
|
||||
let platform = null;
|
||||
let promises = [];
|
||||
@ -34,7 +37,9 @@ const debounce = (func, wait = 100, immediate = false) => {
|
||||
};
|
||||
};
|
||||
|
||||
const getComponentMetadata = ({ component, props = {}, propsMeta = {}, pipes = [] }) => {
|
||||
const getComponentMetadata = (
|
||||
{ component, props = {}, propsMeta = {}, moduleMetadata }: NgStory
|
||||
) => {
|
||||
if (!component || typeof component !== "function")
|
||||
throw new Error("No valid component provided");
|
||||
|
||||
@ -46,13 +51,25 @@ const getComponentMetadata = ({ component, props = {}, propsMeta = {}, pipes = [
|
||||
propsMetadata[key] = propsMeta[key];
|
||||
});
|
||||
|
||||
const {
|
||||
imports = [],
|
||||
schemas = [],
|
||||
declarations = [],
|
||||
providers = []
|
||||
} = moduleMetadata || {};
|
||||
|
||||
return {
|
||||
component,
|
||||
props,
|
||||
pipes,
|
||||
componentMeta: componentMetadata,
|
||||
propsMeta: propsMetadata,
|
||||
params: paramsMetadata
|
||||
params: paramsMetadata,
|
||||
moduleMeta: {
|
||||
imports,
|
||||
schemas,
|
||||
declarations,
|
||||
providers
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@ -69,13 +86,18 @@ const getAnnotatedComponent = (meta, component, propsMeta, params) => {
|
||||
return NewComponent;
|
||||
};
|
||||
|
||||
const getModule = (declarations, entryComponents, bootstrap, data) => {
|
||||
const getModule = (declarations, entryComponents, bootstrap, data, moduleMetadata: NgModuleMetadata = {
|
||||
imports: [],
|
||||
schemas: [],
|
||||
declarations: [],
|
||||
providers: []
|
||||
}) => {
|
||||
const moduleMeta = new NgModule({
|
||||
declarations: [...declarations],
|
||||
imports: [BrowserModule],
|
||||
providers: [{ provide: STORY, useValue: Object.assign({}, data) }],
|
||||
declarations: [...declarations, ...moduleMetadata.declarations],
|
||||
imports: [BrowserModule, ...moduleMetadata.imports],
|
||||
providers: [{ provide: STORY, useValue: Object.assign({}, data) }, ...moduleMetadata.providers],
|
||||
entryComponents: [...entryComponents],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
schemas: [...moduleMetadata.schemas],
|
||||
bootstrap: [...bootstrap]
|
||||
});
|
||||
|
||||
@ -91,9 +113,9 @@ const initModule = (currentStory, context, reRender) => {
|
||||
component,
|
||||
componentMeta,
|
||||
props,
|
||||
pipes,
|
||||
propsMeta,
|
||||
params
|
||||
params,
|
||||
moduleMeta
|
||||
} = getComponentMetadata(currentStory(context));
|
||||
|
||||
if (!componentMeta) throw new Error("No component metadata available");
|
||||
@ -102,7 +124,7 @@ const initModule = (currentStory, context, reRender) => {
|
||||
componentMeta,
|
||||
component,
|
||||
propsMeta,
|
||||
params
|
||||
[...params, ...moduleMeta.providers.map(provider => [provider])]
|
||||
);
|
||||
|
||||
const story = {
|
||||
@ -110,12 +132,15 @@ const initModule = (currentStory, context, reRender) => {
|
||||
props,
|
||||
propsMeta
|
||||
};
|
||||
|
||||
const Module = getModule(
|
||||
[AppComponent, AnnotatedComponent, ...pipes],
|
||||
[AppComponent, AnnotatedComponent],
|
||||
[AnnotatedComponent],
|
||||
[AppComponent],
|
||||
story
|
||||
story,
|
||||
moduleMeta
|
||||
);
|
||||
|
||||
return Module;
|
||||
};
|
||||
|
||||
|
24
app/angular/src/client/preview/angular/types.ts
Normal file
24
app/angular/src/client/preview/angular/types.ts
Normal file
@ -0,0 +1,24 @@
|
||||
export type NgModuleMetadata = {
|
||||
declarations: Array<any>,
|
||||
imports: Array<any>,
|
||||
schemas: Array<any>,
|
||||
providers: Array<any>
|
||||
}
|
||||
|
||||
export type NgStory = {
|
||||
component: any;
|
||||
props: object;
|
||||
propsMeta: object;
|
||||
moduleMetadata: NgModuleMetadata
|
||||
}
|
||||
|
||||
export type Data = {
|
||||
component: any;
|
||||
props: ErrorProps | object;
|
||||
propsMeta: object;
|
||||
}
|
||||
|
||||
type ErrorProps = {
|
||||
message: string
|
||||
stack: string
|
||||
}
|
@ -20,28 +20,11 @@ import { Welcome, Button } from '@storybook/angular/demo';
|
||||
import { SimpleKnobsComponent } from './knobs.component';
|
||||
import { AllKnobsComponent } from './all-knobs.component';
|
||||
import { AppComponent } from '../app/app.component';
|
||||
import { DummyService } from './moduleMetadata/dummy.service';
|
||||
import { ServiceComponent } from './moduleMetadata/service.component'
|
||||
import { NameComponent } from './name.component';
|
||||
import { CustomPipePipe } from './custom.pipe';
|
||||
|
||||
storiesOf('Custom Pipe', module)
|
||||
.add('Default', () => ({
|
||||
component: NameComponent,
|
||||
props: {
|
||||
field: 'foobar',
|
||||
},
|
||||
pipes: [ CustomPipePipe ],
|
||||
}));
|
||||
|
||||
storiesOf('Custom Pipe/With Knobs', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add('NameComponent', () => ({
|
||||
component: NameComponent,
|
||||
props: {
|
||||
field: text('field', 'foobar'),
|
||||
},
|
||||
pipes: [ CustomPipePipe ],
|
||||
}));
|
||||
|
||||
storiesOf('Welcome', module)
|
||||
.add('to Storybook', () => ({
|
||||
component: Welcome,
|
||||
@ -135,7 +118,6 @@ storiesOf('Addon Knobs', module)
|
||||
.add('Simple', () => {
|
||||
const name = text('Name', 'John Doe');
|
||||
const age = number('Age', 44);
|
||||
const content = `I am ${name} and I'm ${age} years old.`;
|
||||
|
||||
return {
|
||||
component: SimpleKnobsComponent,
|
||||
@ -182,3 +164,63 @@ storiesOf('Addon Knobs', module)
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
storiesOf('Custom ngModule metadata', module)
|
||||
.add('simple', () => ({
|
||||
component: ServiceComponent,
|
||||
props: {
|
||||
name: 'Static name'
|
||||
},
|
||||
moduleMetadata: {
|
||||
imports: [],
|
||||
schemas: [],
|
||||
declarations: [],
|
||||
providers: [DummyService]
|
||||
}
|
||||
}))
|
||||
.addDecorator(withKnobs)
|
||||
.add('with knobs', () => {
|
||||
const name = text('Name', 'Dynamic knob');
|
||||
|
||||
return {
|
||||
component: ServiceComponent,
|
||||
props: {
|
||||
name
|
||||
},
|
||||
moduleMetadata: {
|
||||
imports: [],
|
||||
schemas: [],
|
||||
declarations: [],
|
||||
providers: [DummyService]
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
storiesOf('Custom Pipe', module)
|
||||
.add('Default', () => ({
|
||||
component: NameComponent,
|
||||
props: {
|
||||
field: 'foobar',
|
||||
},
|
||||
moduleMetadata: {
|
||||
imports: [],
|
||||
schemas: [],
|
||||
declarations: [CustomPipePipe],
|
||||
providers: []
|
||||
}
|
||||
}));
|
||||
|
||||
storiesOf('Custom Pipe/With Knobs', module)
|
||||
.addDecorator(withKnobs)
|
||||
.add('NameComponent', () => ({
|
||||
component: NameComponent,
|
||||
props: {
|
||||
field: text('field', 'foobar'),
|
||||
},
|
||||
moduleMetadata: {
|
||||
imports: [],
|
||||
schemas: [],
|
||||
declarations: [CustomPipePipe],
|
||||
providers: []
|
||||
}
|
||||
}));
|
||||
|
@ -0,0 +1,17 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class DummyService {
|
||||
constructor() { }
|
||||
|
||||
getItems() {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve([
|
||||
"Joe",
|
||||
"Jane"
|
||||
])
|
||||
}, 2000)
|
||||
})
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { DummyService } from './dummy.service';
|
||||
|
||||
@Component({
|
||||
selector: 'simple-knobs-component',
|
||||
template: `
|
||||
<p>{{ name }}:</p>
|
||||
<ul>
|
||||
<li *ngFor="let item of items">
|
||||
{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
`
|
||||
})
|
||||
export class ServiceComponent {
|
||||
items;
|
||||
@Input() name;
|
||||
|
||||
constructor(private dummy: DummyService) {
|
||||
console.log(DummyService);
|
||||
console.log(this.dummy);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.items = await this.dummy.getItems();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user