-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
193 additions
and
273 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,158 +1,14 @@ | ||
import global from 'global'; | ||
import type { ReactElement } from 'react'; | ||
import { Channel } from '@storybook/channels'; | ||
import type { API } from '@storybook/api'; | ||
import type { RenderData as RouterData } from '@storybook/router'; | ||
import { logger } from '@storybook/client-logger'; | ||
import type { ThemeVars } from '@storybook/theming'; | ||
import { mockChannel } from './storybook-channel-mock'; | ||
import { types, Types } from './types'; | ||
|
||
export { Channel }; | ||
|
||
export interface RenderOptions { | ||
active?: boolean; | ||
key?: string; | ||
} | ||
|
||
export interface Addon { | ||
title: (() => string) | string; | ||
type?: Types; | ||
id?: string; | ||
route?: (routeOptions: RouterData) => string; | ||
match?: (matchOptions: RouterData) => boolean; | ||
render: (renderOptions: RenderOptions) => ReactElement<any>; | ||
paramKey?: string; | ||
disabled?: boolean; | ||
hidden?: boolean; | ||
} | ||
|
||
export type Loader = (api: API) => void; | ||
|
||
interface Loaders { | ||
[key: string]: Loader; | ||
} | ||
export interface Collection { | ||
[key: string]: Addon; | ||
} | ||
interface Elements { | ||
[key: string]: Collection; | ||
} | ||
interface ToolbarConfig { | ||
hidden?: boolean; | ||
} | ||
export interface Config { | ||
theme?: ThemeVars; | ||
toolbar?: { | ||
[id: string]: ToolbarConfig; | ||
}; | ||
[key: string]: any; | ||
} | ||
|
||
export class AddonStore { | ||
constructor() { | ||
this.promise = new Promise((res) => { | ||
this.resolve = () => res(this.getChannel()); | ||
}) as Promise<Channel>; | ||
} | ||
|
||
private loaders: Loaders = {}; | ||
|
||
private elements: Elements = {}; | ||
|
||
private config: Config = {}; | ||
|
||
private channel: Channel | undefined; | ||
|
||
private serverChannel: Channel | undefined; | ||
|
||
private promise: any; | ||
|
||
private resolve: any; | ||
|
||
getChannel = (): Channel => { | ||
// this.channel should get overwritten by setChannel. If it wasn't called (e.g. in non-browser environment), set a mock instead. | ||
if (!this.channel) { | ||
this.setChannel(mockChannel()); | ||
} | ||
|
||
return this.channel; | ||
}; | ||
|
||
getServerChannel = (): Channel => { | ||
if (!this.serverChannel) { | ||
throw new Error('Accessing non-existent serverChannel'); | ||
} | ||
|
||
return this.serverChannel; | ||
}; | ||
|
||
ready = (): Promise<Channel> => this.promise; | ||
|
||
hasChannel = (): boolean => !!this.channel; | ||
|
||
hasServerChannel = (): boolean => !!this.serverChannel; | ||
|
||
setChannel = (channel: Channel): void => { | ||
this.channel = channel; | ||
this.resolve(); | ||
}; | ||
|
||
setServerChannel = (channel: Channel): void => { | ||
this.serverChannel = channel; | ||
}; | ||
|
||
getElements = (type: Types): Collection => { | ||
if (!this.elements[type]) { | ||
this.elements[type] = {}; | ||
} | ||
return this.elements[type]; | ||
}; | ||
|
||
addPanel = (name: string, options: Addon): void => { | ||
this.add(name, { | ||
type: types.PANEL, | ||
...options, | ||
}); | ||
}; | ||
|
||
add = (name: string, addon: Addon) => { | ||
const { type } = addon; | ||
const collection = this.getElements(type); | ||
collection[name] = { id: name, ...addon }; | ||
}; | ||
|
||
setConfig = (value: Config) => { | ||
Object.assign(this.config, value); | ||
}; | ||
|
||
getConfig = () => this.config; | ||
|
||
register = (name: string, registerCallback: (api: API) => void): void => { | ||
if (this.loaders[name]) { | ||
logger.warn(`${name} was loaded twice, this could have bad side-effects`); | ||
} | ||
this.loaders[name] = registerCallback; | ||
}; | ||
|
||
loadAddons = (api: any) => { | ||
Object.values(this.loaders).forEach((value) => value(api)); | ||
}; | ||
} | ||
|
||
// Enforce addons store to be a singleton | ||
const KEY = '__STORYBOOK_ADDONS'; | ||
|
||
function getAddonsStore(): AddonStore { | ||
if (!global[KEY]) { | ||
global[KEY] = new AddonStore(); | ||
} | ||
return global[KEY]; | ||
} | ||
|
||
// There can only be 1 default export per entry point and it has to be directly from index | ||
// Exporting this twice in order to to be able to import it like { addons } instead of 'addons' | ||
// prefer import { addons } from '@storybook/addons' over import addons from '@storybook/addons' | ||
// | ||
// See public_api.ts | ||
// See main.ts | ||
import { addons } from './main'; | ||
|
||
export * from './make-decorator'; | ||
export * from './main'; | ||
export * from './types'; | ||
export * from './storybook-channel-mock'; | ||
export * from './hooks'; | ||
|
||
export const addons = getAddonsStore(); | ||
export default addons; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
import global from 'global'; | ||
import type { ReactElement } from 'react'; | ||
import { Channel } from '@storybook/channels'; | ||
import type { API } from '@storybook/api'; | ||
import type { RenderData as RouterData } from '@storybook/router'; | ||
import { logger } from '@storybook/client-logger'; | ||
import type { ThemeVars } from '@storybook/theming'; | ||
import { mockChannel } from './storybook-channel-mock'; | ||
import { types, Types } from './types'; | ||
|
||
export { Channel }; | ||
|
||
export interface RenderOptions { | ||
active?: boolean; | ||
key?: string; | ||
} | ||
|
||
export interface Addon { | ||
title: (() => string) | string; | ||
type?: Types; | ||
id?: string; | ||
route?: (routeOptions: RouterData) => string; | ||
match?: (matchOptions: RouterData) => boolean; | ||
render: (renderOptions: RenderOptions) => ReactElement<any>; | ||
paramKey?: string; | ||
disabled?: boolean; | ||
hidden?: boolean; | ||
} | ||
|
||
export type Loader = (api: API) => void; | ||
|
||
interface Loaders { | ||
[key: string]: Loader; | ||
} | ||
export interface Collection { | ||
[key: string]: Addon; | ||
} | ||
interface Elements { | ||
[key: string]: Collection; | ||
} | ||
interface ToolbarConfig { | ||
hidden?: boolean; | ||
} | ||
export interface Config { | ||
theme?: ThemeVars; | ||
toolbar?: { | ||
[id: string]: ToolbarConfig; | ||
}; | ||
[key: string]: any; | ||
} | ||
|
||
export class AddonStore { | ||
constructor() { | ||
this.promise = new Promise((res) => { | ||
this.resolve = () => res(this.getChannel()); | ||
}) as Promise<Channel>; | ||
} | ||
|
||
private loaders: Loaders = {}; | ||
|
||
private elements: Elements = {}; | ||
|
||
private config: Config = {}; | ||
|
||
private channel: Channel | undefined; | ||
|
||
private serverChannel: Channel | undefined; | ||
|
||
private promise: any; | ||
|
||
private resolve: any; | ||
|
||
getChannel = (): Channel => { | ||
// this.channel should get overwritten by setChannel. If it wasn't called (e.g. in non-browser environment), set a mock instead. | ||
if (!this.channel) { | ||
this.setChannel(mockChannel()); | ||
} | ||
|
||
return this.channel; | ||
}; | ||
|
||
getServerChannel = (): Channel => { | ||
if (!this.serverChannel) { | ||
throw new Error('Accessing non-existent serverChannel'); | ||
} | ||
|
||
return this.serverChannel; | ||
}; | ||
|
||
ready = (): Promise<Channel> => this.promise; | ||
|
||
hasChannel = (): boolean => !!this.channel; | ||
|
||
hasServerChannel = (): boolean => !!this.serverChannel; | ||
|
||
setChannel = (channel: Channel): void => { | ||
this.channel = channel; | ||
this.resolve(); | ||
}; | ||
|
||
setServerChannel = (channel: Channel): void => { | ||
this.serverChannel = channel; | ||
}; | ||
|
||
getElements = (type: Types): Collection => { | ||
if (!this.elements[type]) { | ||
this.elements[type] = {}; | ||
} | ||
return this.elements[type]; | ||
}; | ||
|
||
addPanel = (name: string, options: Addon): void => { | ||
this.add(name, { | ||
type: types.PANEL, | ||
...options, | ||
}); | ||
}; | ||
|
||
add = (name: string, addon: Addon) => { | ||
const { type } = addon; | ||
const collection = this.getElements(type); | ||
collection[name] = { id: name, ...addon }; | ||
}; | ||
|
||
setConfig = (value: Config) => { | ||
Object.assign(this.config, value); | ||
}; | ||
|
||
getConfig = () => this.config; | ||
|
||
register = (name: string, registerCallback: (api: API) => void): void => { | ||
if (this.loaders[name]) { | ||
logger.warn(`${name} was loaded twice, this could have bad side-effects`); | ||
} | ||
this.loaders[name] = registerCallback; | ||
}; | ||
|
||
loadAddons = (api: any) => { | ||
Object.values(this.loaders).forEach((value) => value(api)); | ||
}; | ||
} | ||
|
||
// Enforce addons store to be a singleton | ||
const KEY = '__STORYBOOK_ADDONS'; | ||
|
||
function getAddonsStore(): AddonStore { | ||
if (!global[KEY]) { | ||
global[KEY] = new AddonStore(); | ||
} | ||
return global[KEY]; | ||
} | ||
|
||
// Exporting this twice in order to to be able to import it like { addons } instead of 'addons' | ||
// prefer import { addons } from '@storybook/addons' over import addons from '@storybook/addons' | ||
// | ||
// See public_api.ts | ||
|
||
export const addons = getAddonsStore(); |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
export * from './dist/types/lib/shortcut.d'; | ||
export type KeyCollection = string[]; | ||
|
||
export function shortcutToHumanString(shortcut: KeyCollection): string |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.