diff --git a/lib/addons/package.json b/lib/addons/package.json index a12704d8642a..ab75d72f5884 100644 --- a/lib/addons/package.json +++ b/lib/addons/package.json @@ -20,9 +20,9 @@ }, "license": "MIT", "sideEffects": false, - "main": "dist/cjs/public_api.js", - "module": "dist/esm/public_api.js", - "types": "dist/types/public_api.d.ts", + "main": "dist/cjs/index.js", + "module": "dist/esm/index.js", + "types": "dist/types/index.d.ts", "files": [ "dist/**/*", "README.md", diff --git a/lib/addons/src/index.ts b/lib/addons/src/index.ts index ff0923848613..7c0cb072e5a3 100644 --- a/lib/addons/src/index.ts +++ b/lib/addons/src/index.ts @@ -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; - 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; - } - - 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 => 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; diff --git a/lib/addons/src/main.ts b/lib/addons/src/main.ts new file mode 100644 index 000000000000..ff0923848613 --- /dev/null +++ b/lib/addons/src/main.ts @@ -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; + 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; + } + + 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 => 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(); diff --git a/lib/addons/src/public_api.ts b/lib/addons/src/public_api.ts deleted file mode 100644 index 7639be2ff7b8..000000000000 --- a/lib/addons/src/public_api.ts +++ /dev/null @@ -1,14 +0,0 @@ -// There can only be 1 default export per entry point and it has to be directly from public_api -// 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 index.ts -import { addons } from './index'; - -export * from './make-decorator'; -export * from './index'; -export * from './types'; -export * from './storybook-channel-mock'; -export * from './hooks'; - -export default addons; diff --git a/lib/api/shortcut.d.ts b/lib/api/shortcut.d.ts index 2b4b12c4185a..3e41cf9d06c5 100644 --- a/lib/api/shortcut.d.ts +++ b/lib/api/shortcut.d.ts @@ -1 +1,3 @@ -export * from './dist/types/lib/shortcut.d'; +export type KeyCollection = string[]; + +export function shortcutToHumanString(shortcut: KeyCollection): string \ No newline at end of file diff --git a/lib/ui/tsconfig.json b/lib/ui/tsconfig.json index 30bfb0d9d8f9..4bc732d30655 100644 --- a/lib/ui/tsconfig.json +++ b/lib/ui/tsconfig.json @@ -1,6 +1,5 @@ { "extends": "../../tsconfig.json", - "baseUrl": ".", "compilerOptions": { "lib": ["ESNext", "DOM", "DOM.Iterable"] }, diff --git a/scripts/bundle-package.ts b/scripts/bundle-package.ts index 548895ed2a82..981ceecf5b04 100644 --- a/scripts/bundle-package.ts +++ b/scripts/bundle-package.ts @@ -63,6 +63,14 @@ async function removeDist() { await fs.remove('dist'); } +async function mapper() { + await fs.emptyDir(path.join(process.cwd(), 'dist', 'types')); + await fs.writeFile( + path.join(process.cwd(), 'dist', 'types', 'index.d.ts'), + `export * from '../../src/index';` + ); +} + async function build(options: Options) { const { input, externals, cwd, optimized } = options; const setting: RollupOptions = { @@ -174,7 +182,7 @@ export async function run({ cwd, flags }: { cwd: string; flags: string[] }) { await Promise.all([ // build(options), - ...(options.optimized ? [dts(options)] : []), + ...(options.optimized ? [dts(options)] : [mapper()]), ]); console.timeEnd(message); diff --git a/scripts/prepare/bundle.ts b/scripts/prepare/bundle.ts index 3b25d394c67c..f28ae6f869d2 100644 --- a/scripts/prepare/bundle.ts +++ b/scripts/prepare/bundle.ts @@ -5,7 +5,11 @@ import { build } from 'tsup'; const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => { const packageJson = await fs.readJson(join(cwd, 'package.json')); - console.log(`skipping generating types for ${process.cwd()}`); + if (!flags.includes('--optimized')) { + console.log(`skipping generating types for ${process.cwd()}`); + await fs.emptyDir(join(process.cwd(), 'dist', 'types')); + await fs.writeFile(join(process.cwd(), 'dist', 'index.d.ts'), `export * from '../src/index';`); + } await build({ entry: packageJson.bundlerEntrypoint, diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json index 6cd354e5bfea..4be353cd89f2 100644 --- a/scripts/tsconfig.json +++ b/scripts/tsconfig.json @@ -1,7 +1,6 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "baseUrl": ".", "types": [ "node", "jest" diff --git a/scripts/utils/compile-tsc.js b/scripts/utils/compile-tsc.js index 11e5eee52ea4..90e9ca49a56b 100644 --- a/scripts/utils/compile-tsc.js +++ b/scripts/utils/compile-tsc.js @@ -68,7 +68,11 @@ async function run({ optimized, watch, silent, errorCallback }) { }); } else { console.log(`skipping generating types for ${process.cwd()}`); - resolve(); + const loc = path.join(process.cwd(), 'dist', 'types'); + Promise.resolve() + .then(() => fs.emptyDir(loc)) + .then(() => fs.writeFile(path.join(loc, 'index.d.ts'), `export * from '../../src/index';`)) + .then(resolve); } }); } diff --git a/tsconfig.json b/tsconfig.json index d00d62432fda..965c65d3bde1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,102 +2,6 @@ "compileOnSave": false, "compilerOptions": { "baseUrl": ".", - "paths": { - "@storybook/addon-a11y": ["addons/a11y/src/index.ts"], - "@storybook/addon-actions": ["addons/actions/src/index.ts"], - "@storybook/addon-backgrounds": ["addons/backgrounds/src/index.ts"], - "@storybook/addon-controls": ["addons/controls/src/index.ts"], - "@storybook/addon-docs": ["addons/docs/src/index.ts"], - "@storybook/addon-essentials": ["addons/essentials/src/index.ts"], - "@storybook/addon-interactions": ["addons/interactions/src/index.ts"], - "@storybook/addon-jest": ["addons/jest/src/index.ts"], - "@storybook/addon-links": ["addons/links/src/index.ts"], - "@storybook/addon-measure": ["addons/measure/src/index.ts"], - "@storybook/addon-outline": ["addons/outline/src/index.ts"], - "@storybook/addon-storyshots": ["addons/storyshots/storyshots-core/src/index.ts"], - "@storybook/addon-storyshots-puppeteer": ["addons/storyshots/storyshots-puppeteer/src/index.ts"], - "@storybook/addon-storysource": ["addons/storysource/src/index.ts"], - "@storybook/addon-toolbars": ["addons/toolbars/src/index.ts"], - "@storybook/addon-viewport": ["addons/viewport/src/index.ts"], - - "angular-cli": ["examples/angular-cli/src/index.ts"], - "cra-kitchen-sink": ["examples/cra-kitchen-sink/src/index.ts"], - "cra-ts-essentials": ["examples/cra-ts-essentials/src/index.ts"], - "cra-ts-kitchen-sink": ["examples/cra-ts-kitchen-sink/src/index.ts"], - "ember-example": ["examples/ember-cli/src/index.ts"], - "@storybook/external-docs": ["examples/external-docs/src/index.ts"], - "html-kitchen-sink": ["examples/html-kitchen-sink/src/index.ts"], - "official-storybook": ["examples/official-storybook/src/index.ts"], - "preact-example": ["examples/preact-kitchen-sink/src/index.ts"], - "@storybook/example-react-ts": ["examples/react-ts/src/index.ts"], - "server-kitchen-sink": ["examples/server-kitchen-sink/src/index.ts"], - "standalone-preview": ["examples/standalone-preview/src/index.ts"], - "svelte-example": ["examples/svelte-kitchen-sink/src/index.ts"], - "vue-3-cli-example": ["examples/vue-3-cli/src/index.ts"], - "vue-cli-example": ["examples/vue-cli/src/index.ts"], - "vue-example": ["examples/vue-kitchen-sink/src/index.ts"], - - "@storybook/angular": ["frameworks/angular/src/index.ts"], - "@storybook/ember": ["frameworks/ember/src/index.ts"], - "@storybook/html-webpack5": ["frameworks/html-webpack5/src/index.ts"], - "@storybook/preact-webpack5": ["frameworks/preact-webpack5/src/index.ts"], - "@storybook/react-webpack5": ["frameworks/react-webpack5/src/index.ts"], - "@storybook/server-webpack5": ["frameworks/server-webpack5/src/index.ts"], - "@storybook/svelte-webpack5": ["frameworks/svelte-webpack5/src/index.ts"], - "@storybook/vue-webpack5": ["frameworks/vue-webpack5/src/index.ts"], - "@storybook/vue3-webpack5": ["frameworks/vue3-webpack5/src/index.ts"], - "@storybook/web-components-webpack5": ["frameworks/web-components-webpack5/src/index.ts"], - - "@storybook/addons": ["lib/addons/src/index.ts"], - "@storybook/api": ["lib/api/src/index.ts"], - "@storybook/builder-webpack5": ["lib/builder-webpack5/src/index.ts"], - "@storybook/channel-postmessage": ["lib/channel-postmessage/src/index.ts"], - "@storybook/channel-websocket": ["lib/channel-websocket/src/index.ts"], - "@storybook/channels": ["lib/channels/src/index.ts"], - "@storybook/cli": ["lib/cli/src/index.ts"], - "sb": ["lib/cli-sb/src/index.ts"], - "storybook": ["lib/cli-storybook/src/index.ts"], - "@storybook/client-api": ["lib/client-api/src/index.ts"], - "@storybook/client-logger": ["lib/client-logger/src/index.ts"], - "@storybook/codemod": ["lib/codemod/src/index.ts"], - "@storybook/components": ["lib/components/src/index.ts"], - "@storybook/core-client": ["lib/core-client/src/index.ts"], - "@storybook/core-common": ["lib/core-common/src/index.ts"], - "@storybook/core-events": ["lib/core-events/src/index.ts"], - "@storybook/core-server": ["lib/core-server/src/index.ts"], - "@storybook/core-webpack": ["lib/core-webpack/src/index.ts"], - "@storybook/csf-tools": ["lib/csf-tools/src/index.ts"], - "@storybook/docs-tools": ["lib/docs-tools/src/index.ts"], - "@storybook/instrumenter": ["lib/instrumenter/src/index.ts"], - "@storybook/manager-webpack5": ["lib/manager-webpack5/src/index.ts"], - "@storybook/node-logger": ["lib/node-logger/src/index.ts"], - "@storybook/postinstall": ["lib/postinstall/src/index.ts"], - "@storybook/preview-web": ["lib/preview-web/src/index.ts"], - "@storybook/router": ["lib/router/src/index.ts"], - "@storybook/source-loader": ["lib/source-loader/src/index.ts"], - "@storybook/store": ["lib/store/src/index.ts"], - "@storybook/telemetry": ["lib/telemetry/src/index.ts"], - "@storybook/theming": ["lib/theming/src/index.ts"], - "@storybook/ui": ["lib/ui/src/index.ts"], - - "@storybook/preset-html-webpack": ["presets/html-webpack/src/index.ts"], - "@storybook/preset-preact-webpack": ["presets/preact-webpack/src/index.ts"], - "@storybook/preset-react-webpack": ["presets/react-webpack/src/index.ts"], - "@storybook/preset-server-webpack": ["presets/server-webpack/src/index.ts"], - "@storybook/preset-svelte-webpack": ["presets/svelte-webpack/src/index.ts"], - "@storybook/preset-vue-webpack": ["presets/vue-webpack/src/index.ts"], - "@storybook/preset-vue3-webpack": ["presets/vue3-webpack/src/index.ts"], - "@storybook/preset-web-components-webpack": ["presets/web-components-webpack/src/index.ts"], - - "@storybook/html": ["renderers/html/src/index.ts"], - "@storybook/preact": ["renderers/preact/src/index.ts"], - "@storybook/react": ["renderers/react/src/index.ts"], - "@storybook/server": ["renderers/server/src/index.ts"], - "@storybook/svelte": ["renderers/svelte/src/index.ts"], - "@storybook/vue": ["renderers/vue/src/index.ts"], - "@storybook/vue3": ["renderers/vue3/src/index.ts"], - "@storybook/web-components": ["renderers/web-components/src/index.ts"] - }, "incremental": false, "noImplicitAny": true, "experimentalDecorators": true,