mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-04 13:51:28 +08:00
136 lines
3.9 KiB
JavaScript
136 lines
3.9 KiB
JavaScript
/* eslint no-underscore-dangle: 0 */
|
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
import { Component, SimpleChange, ChangeDetectorRef } from '@angular/core';
|
|
import { getParameters, getAnnotations } from './utils';
|
|
|
|
const getComponentMetadata = ({ component, props = {}, moduleMetadata = {} }) => {
|
|
if (!component || typeof component !== 'function') throw new Error('No valid component provided');
|
|
|
|
const componentMeta = getAnnotations(component)[0] || {};
|
|
const paramsMetadata = getParameters(component);
|
|
|
|
return {
|
|
component,
|
|
props,
|
|
componentMeta,
|
|
moduleMetadata,
|
|
params: paramsMetadata,
|
|
};
|
|
};
|
|
|
|
const getAnnotatedComponent = ({ componentMeta, component, params, knobStore, channel }) => {
|
|
const KnobWrapperComponent = function KnobWrapperComponent(cd, ...args) {
|
|
component.call(this, ...args);
|
|
this.cd = cd;
|
|
this.knobChanged = this.knobChanged.bind(this);
|
|
this.setPaneKnobs = this.setPaneKnobs.bind(this);
|
|
};
|
|
|
|
KnobWrapperComponent.prototype = Object.create(component.prototype);
|
|
KnobWrapperComponent.annotations = [new Component(componentMeta)];
|
|
KnobWrapperComponent.parameters = [[ChangeDetectorRef], ...params];
|
|
|
|
KnobWrapperComponent.prototype.constructor = KnobWrapperComponent;
|
|
KnobWrapperComponent.prototype.ngOnInit = function onInit() {
|
|
if (component.prototype.ngOnInit) {
|
|
component.prototype.ngOnInit.call(this);
|
|
}
|
|
|
|
channel.on('addon:knobs:knobChange', this.knobChanged);
|
|
channel.on('addon:knobs:knobClick', this.knobClicked);
|
|
knobStore.subscribe(this.setPaneKnobs);
|
|
this.setPaneKnobs();
|
|
};
|
|
|
|
KnobWrapperComponent.prototype.ngOnDestroy = function onDestroy() {
|
|
if (component.prototype.ngOnDestroy) {
|
|
component.prototype.ngOnDestroy.call(this);
|
|
}
|
|
|
|
channel.removeListener('addon:knobs:knobChange', this.knobChanged);
|
|
channel.removeListener('addon:knobs:knobClick', this.knobClicked);
|
|
knobStore.unsubscribe(this.setPaneKnobs);
|
|
};
|
|
|
|
KnobWrapperComponent.prototype.ngOnChanges = function onChanges(changes) {
|
|
if (component.prototype.ngOnChanges) {
|
|
component.prototype.ngOnChanges.call(this, changes);
|
|
}
|
|
};
|
|
|
|
KnobWrapperComponent.prototype.setPaneKnobs = function setPaneKnobs(timestamp = +new Date()) {
|
|
channel.emit('addon:knobs:setKnobs', {
|
|
knobs: knobStore.getAll(),
|
|
timestamp,
|
|
});
|
|
};
|
|
|
|
KnobWrapperComponent.prototype.knobChanged = function knobChanged(change) {
|
|
const { name, value } = change;
|
|
const knobOptions = knobStore.get(name);
|
|
const oldValue = knobOptions.value;
|
|
knobOptions.value = value;
|
|
knobStore.markAllUnused();
|
|
this[name] = value;
|
|
this.cd.detectChanges();
|
|
this.ngOnChanges({
|
|
[name]: new SimpleChange(oldValue, value, false),
|
|
});
|
|
};
|
|
|
|
KnobWrapperComponent.prototype.knobClicked = function knobClicked(clicked) {
|
|
const knobOptions = knobStore.get(clicked.name);
|
|
knobOptions.callback();
|
|
};
|
|
|
|
return KnobWrapperComponent;
|
|
};
|
|
|
|
const createComponentFromTemplate = template => {
|
|
const componentClass = class DynamicComponent {};
|
|
|
|
return Component({
|
|
template,
|
|
})(componentClass);
|
|
};
|
|
|
|
const resetKnobs = (knobStore, channel) => {
|
|
knobStore.reset();
|
|
channel.emit('addon:knobs:setKnobs', {
|
|
knobs: knobStore.getAll(),
|
|
timestamp: false,
|
|
});
|
|
};
|
|
|
|
export function prepareComponent({ getStory, context, channel, knobStore }) {
|
|
resetKnobs(knobStore, channel);
|
|
const story = getStory(context);
|
|
let { component } = story;
|
|
const { template } = story;
|
|
|
|
if (!component) {
|
|
component = createComponentFromTemplate(template);
|
|
}
|
|
|
|
const { componentMeta, props, params, moduleMetadata } = getComponentMetadata({
|
|
...story,
|
|
component,
|
|
});
|
|
|
|
if (!componentMeta && component) throw new Error('No component metadata available');
|
|
|
|
const AnnotatedComponent = getAnnotatedComponent({
|
|
componentMeta,
|
|
component,
|
|
params,
|
|
knobStore,
|
|
channel,
|
|
});
|
|
|
|
return {
|
|
component: AnnotatedComponent,
|
|
props,
|
|
moduleMetadata,
|
|
};
|
|
}
|