UNPKG

2.78 kBJavaScriptView Raw
1import global from 'global';
2import { Channel } from '@storybook/channels';
3import { logger } from '@storybook/client-logger';
4import { types } from './types';
5export { Channel };
6export class AddonStore {
7 constructor() {
8 this.loaders = {};
9 this.elements = {};
10 this.config = {};
11 this.channel = void 0;
12 this.serverChannel = void 0;
13 this.promise = void 0;
14 this.resolve = void 0;
15
16 this.getChannel = () => {
17 // this.channel should get overwritten by setChannel. If it wasn't called (e.g. in non-browser environment), throw.
18 if (!this.channel) {
19 throw new Error('Accessing non-existent addons channel, see https://storybook.js.org/basics/faq/#why-is-there-no-addons-channel');
20 }
21
22 return this.channel;
23 };
24
25 this.getServerChannel = () => {
26 if (!this.serverChannel) {
27 throw new Error('Accessing non-existent serverChannel');
28 }
29
30 return this.serverChannel;
31 };
32
33 this.ready = () => this.promise;
34
35 this.hasChannel = () => !!this.channel;
36
37 this.hasServerChannel = () => !!this.serverChannel;
38
39 this.setChannel = channel => {
40 this.channel = channel;
41 this.resolve();
42 };
43
44 this.setServerChannel = channel => {
45 this.serverChannel = channel;
46 };
47
48 this.getElements = type => {
49 if (!this.elements[type]) {
50 this.elements[type] = {};
51 }
52
53 return this.elements[type];
54 };
55
56 this.addPanel = (name, options) => {
57 this.add(name, Object.assign({
58 type: types.PANEL
59 }, options));
60 };
61
62 this.add = (name, addon) => {
63 const {
64 type
65 } = addon;
66 const collection = this.getElements(type);
67 collection[name] = Object.assign({
68 id: name
69 }, addon);
70 };
71
72 this.setConfig = value => {
73 Object.assign(this.config, value);
74 };
75
76 this.getConfig = () => this.config;
77
78 this.register = (name, registerCallback) => {
79 if (this.loaders[name]) {
80 logger.warn(`${name} was loaded twice, this could have bad side-effects`);
81 }
82
83 this.loaders[name] = registerCallback;
84 };
85
86 this.loadAddons = api => {
87 Object.values(this.loaders).forEach(value => value(api));
88 };
89
90 this.promise = new Promise(res => {
91 this.resolve = () => res(this.getChannel());
92 });
93 }
94
95} // Enforce addons store to be a singleton
96
97const KEY = '__STORYBOOK_ADDONS';
98
99function getAddonsStore() {
100 if (!global[KEY]) {
101 global[KEY] = new AddonStore();
102 }
103
104 return global[KEY];
105} // Exporting this twice in order to to be able to import it like { addons } instead of 'addons'
106// prefer import { addons } from '@storybook/addons' over import addons from '@storybook/addons'
107//
108// See public_api.ts
109
110
111export const addons = getAddonsStore();
\No newline at end of file