diff --git a/code/frameworks/angular/src/client/public-api.ts b/code/frameworks/angular/src/client/public-api.ts index 3f91276a044b..553c4c85907e 100644 --- a/code/frameworks/angular/src/client/public-api.ts +++ b/code/frameworks/angular/src/client/public-api.ts @@ -1,29 +1 @@ -/* eslint-disable prefer-destructuring */ -import { Addon_ClientStoryApi, Addon_Loadable } from '@storybook/types'; -import { start } from '@storybook/preview-api'; -import { renderToCanvas, render } from './render'; -import decorateStory from './decorateStory'; -import { AngularRenderer } from './types'; - export * from './public-types'; - -const RENDERER = 'angular'; - -interface ClientApi extends Addon_ClientStoryApi { - configure(loader: Addon_Loadable, module: NodeModule): void; - forceReRender(): void; - raw: () => any; // todo add type - load: (...args: any[]) => void; -} - -const api = start(renderToCanvas, { decorateStory, render }); - -export const storiesOf: ClientApi['storiesOf'] = (kind, m) => { - return (api.clientApi.storiesOf(kind, m) as ReturnType).addParameters({ - renderer: RENDERER, - }); -}; - -export const configure: ClientApi['configure'] = (...args) => api.configure(RENDERER, ...args); -export const forceReRender: ClientApi['forceReRender'] = api.forceReRender; -export const raw: ClientApi['raw'] = api.clientApi.raw; diff --git a/code/frameworks/ember/src/client/preview/index.ts b/code/frameworks/ember/src/client/preview/index.ts index 7b77a8755219..53521e8aa728 100644 --- a/code/frameworks/ember/src/client/preview/index.ts +++ b/code/frameworks/ember/src/client/preview/index.ts @@ -1,16 +1 @@ -import { start } from '@storybook/preview-api'; - import './globals'; -import type { EmberRenderer } from './types'; -import { renderToCanvas } from './render'; - -const { configure: coreConfigure, clientApi, forceReRender } = start(renderToCanvas); - -export const { raw } = clientApi; - -const RENDERER = 'ember'; -export const storiesOf = (kind: string, m: any) => - clientApi.storiesOf(kind, m).addParameters({ renderer: RENDERER }); -export const configure = (...args: any[]) => coreConfigure(RENDERER, ...args); - -export { forceReRender }; diff --git a/code/frameworks/ember/src/index.ts b/code/frameworks/ember/src/index.ts index 3d30d71982e6..fc8faa13668a 100644 --- a/code/frameworks/ember/src/index.ts +++ b/code/frameworks/ember/src/index.ts @@ -1,6 +1,6 @@ /// -export { storiesOf, configure, forceReRender, raw } from './client/preview'; +import './client/preview'; // optimization: stop HMR propagation in webpack if (typeof module !== 'undefined') module?.hot?.decline(); diff --git a/code/lib/preview-api/src/modules/client-api/ClientApi.test.ts b/code/lib/preview-api/src/modules/client-api/ClientApi.test.ts deleted file mode 100644 index 65f4d718a9ed..000000000000 --- a/code/lib/preview-api/src/modules/client-api/ClientApi.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { addons, mockChannel } from '../addons'; -import { ClientApi } from './ClientApi'; - -beforeEach(() => { - addons.setChannel(mockChannel()); -}); - -describe('ClientApi', () => { - describe('getStoryIndex', () => { - it('should remember the order that files were added in', async () => { - const clientApi = new ClientApi(); - const store = { - processCSFFileWithCache: jest.fn(() => ({ meta: { title: 'title' } })), - storyFromCSFFile: jest.fn(({ storyId }) => ({ - id: storyId, - parameters: { fileName: storyId.split('-')[0].replace('kind', 'file') }, - })), - }; - clientApi.storyStore = store as any; - - let disposeCallback: () => void = () => {}; - const module1 = { - id: 'file1', - hot: { - data: {}, - accept: jest.fn(), - dispose(cb: () => void) { - disposeCallback = cb; - }, - }, - }; - const module2 = { - id: 'file2', - }; - clientApi.storiesOf('kind1', module1 as unknown as NodeModule).add('story1', jest.fn()); - clientApi.storiesOf('kind2', module2 as unknown as NodeModule).add('story2', jest.fn()); - // This gets called by configure - // eslint-disable-next-line no-underscore-dangle - clientApi._loadAddedExports(); - - expect(Object.keys(clientApi.getStoryIndex().entries)).toEqual([ - 'kind1--story1', - 'kind2--story2', - ]); - - disposeCallback(); - clientApi.storiesOf('kind1', module1 as unknown as NodeModule).add('story1', jest.fn()); - await new Promise((r) => setTimeout(r, 0)); - expect(Object.keys(clientApi.getStoryIndex().entries)).toEqual([ - 'kind1--story1', - 'kind2--story2', - ]); - }); - }); -}); diff --git a/code/lib/preview-api/src/modules/client-api/ClientApi.ts b/code/lib/preview-api/src/modules/client-api/ClientApi.ts index 83a2ba0cd6b0..d9bc31ec07ae 100644 --- a/code/lib/preview-api/src/modules/client-api/ClientApi.ts +++ b/code/lib/preview-api/src/modules/client-api/ClientApi.ts @@ -212,157 +212,6 @@ export class ClientApi { ); } - // what are the occasions that "m" is a boolean vs an obj - storiesOf = (kind: string, m?: NodeModule): Addon_StoryApi => { - if (!kind && typeof kind !== 'string') { - throw new Error('Invalid or missing kind provided for stories, should be a string'); - } - - if (!m) { - logger.warn( - `Missing 'module' parameter for story with a kind of '${kind}'. It will break your HMR` - ); - } - - if (m) { - const proto = Object.getPrototypeOf(m); - if (proto.exports && proto.exports.default) { - // FIXME: throw an error in SB6.0 - logger.error( - `Illegal mix of CSF default export and storiesOf calls in a single file: ${proto.i}` - ); - } - } - - // eslint-disable-next-line no-plusplus - const baseFilename = m && m.id ? `${m.id}` : (this.lastFileName++).toString(); - let fileName = baseFilename; - let i = 1; - // Deal with `storiesOf()` being called twice in the same file. - // On HMR, we clear _addedExports[fileName] below. - - while (this._addedExports[fileName]) { - i += 1; - fileName = `${baseFilename}-${i}`; - } - - if (m && m.hot && m.hot.accept) { - // This module used storiesOf(), so when it re-runs on HMR, it will reload - // itself automatically without us needing to look at our imports - m.hot.accept(); - m.hot.dispose(() => { - this.facade.clearFilenameExports(fileName); - - delete this._addedExports[fileName]; - - // We need to update the importFn as soon as the module re-evaluates - // (and calls storiesOf() again, etc). We could call `onImportFnChanged()` - // at the end of every setStories call (somehow), but then we'd need to - // debounce it somehow for initial startup. Instead, we'll take advantage of - // the fact that the evaluation of the module happens immediately in the same tick - setTimeout(() => { - this._loadAddedExports(); - this.onImportFnChanged?.({ importFn: this.importFn.bind(this) }); - }, 0); - }); - } - - let hasAdded = false; - const api: Addon_StoryApi = { - kind: kind.toString(), - add: () => api, - addDecorator: () => api, - addLoader: () => api, - addParameters: () => api, - }; - - // apply addons - Object.keys(this.addons).forEach((name) => { - const addon = this.addons[name]; - api[name] = (...args: any[]) => { - addon.apply(api, args); - return api; - }; - }); - - const meta: NormalizedComponentAnnotations = { - id: sanitize(kind), - title: kind, - decorators: [], - loaders: [], - parameters: {}, - }; - // We map these back to a simple default export, even though we have type guarantees at this point - - this._addedExports[fileName] = { default: meta }; - - let counter = 0; - api.add = (storyName: string, storyFn: StoryFn, parameters: Parameters = {}) => { - hasAdded = true; - - if (typeof storyName !== 'string') { - throw new Error(`Invalid or missing storyName provided for a "${kind}" story.`); - } - - if (!storyFn || Array.isArray(storyFn) || invalidStoryTypes.has(typeof storyFn)) { - throw new Error( - `Cannot load story "${storyName}" in "${kind}" due to invalid format. Storybook expected a function/object but received ${typeof storyFn} instead.` - ); - } - - const { decorators, loaders, component, args, argTypes, ...storyParameters } = parameters; - - const storyId = parameters.__id || toId(kind, storyName); - - const csfExports = this._addedExports[fileName]; - // Whack a _ on the front incase it is "default" - csfExports[`story${counter}`] = { - name: storyName, - parameters: { fileName, __id: storyId, ...storyParameters }, - decorators, - loaders, - args, - argTypes, - component, - render: storyFn, - }; - counter += 1; - - return api; - }; - - api.addDecorator = (decorator: DecoratorFunction) => { - if (hasAdded) - throw new Error(`You cannot add a decorator after the first story for a kind. -Read more here: https://github.com/storybookjs/storybook/blob/master/MIGRATION.md#can-no-longer-add-decoratorsparameters-after-stories`); - - meta.decorators?.push(decorator); - return api; - }; - - api.addLoader = (loader: LoaderFunction) => { - if (hasAdded) throw new Error(`You cannot add a loader after the first story for a kind.`); - - meta.loaders?.push(loader); - return api; - }; - - api.addParameters = ({ component, args, argTypes, tags, ...parameters }: Parameters) => { - if (hasAdded) - throw new Error(`You cannot add parameters after the first story for a kind. -Read more here: https://github.com/storybookjs/storybook/blob/master/MIGRATION.md#can-no-longer-add-decoratorsparameters-after-stories`); - - meta.parameters = combineParameters(meta.parameters, parameters); - if (component) meta.component = component; - if (args) meta.args = { ...meta.args, ...args }; - if (argTypes) meta.argTypes = { ...meta.argTypes, ...argTypes }; - if (tags) meta.tags = tags; - return api; - }; - - return api; - }; - // @deprecated raw = () => { return this.storyStore?.raw(); diff --git a/code/lib/preview-api/src/modules/core-client/start.test.ts b/code/lib/preview-api/src/modules/core-client/start.test.ts index b114e640f50a..aa304d2ba883 100644 --- a/code/lib/preview-api/src/modules/core-client/start.test.ts +++ b/code/lib/preview-api/src/modules/core-client/start.test.ts @@ -117,464 +117,6 @@ describe('start', () => { // @ts-expect-error (setting this to undefined is indeed what we want to do) global.IS_STORYBOOK = undefined; }); - describe('when configure is called with storiesOf only', () => { - it('loads and renders the first story correctly', async () => { - const renderToCanvas = jest.fn(); - - const { configure, clientApi } = start(renderToCanvas); - - configure('test', () => { - clientApi - .storiesOf('Component A', { id: 'file1' } as NodeModule) - .add('Story One', jest.fn()) - .add('Story Two', jest.fn()); - - clientApi - .storiesOf('Component B', { id: 'file2' } as NodeModule) - .add('Story Three', jest.fn()); - }); - - await waitForRender(); - - expect(mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1]) - .toMatchInlineSnapshot(` - Object { - "entries": Object { - "component-a--story-one": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-a", - "id": "component-a--story-one", - "importPath": "file1", - "initialArgs": Object {}, - "name": "Story One", - "parameters": Object { - "__id": "component-a--story-one", - "__isArgsStory": false, - "fileName": "file1", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component A", - "type": "story", - }, - "component-a--story-two": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-a", - "id": "component-a--story-two", - "importPath": "file1", - "initialArgs": Object {}, - "name": "Story Two", - "parameters": Object { - "__id": "component-a--story-two", - "__isArgsStory": false, - "fileName": "file1", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component A", - "type": "story", - }, - "component-b--story-three": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-b", - "id": "component-b--story-three", - "importPath": "file2", - "initialArgs": Object {}, - "name": "Story Three", - "parameters": Object { - "__id": "component-b--story-three", - "__isArgsStory": false, - "fileName": "file2", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component B", - "type": "story", - }, - }, - "v": 4, - } - `); - - await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-a--story-one'); - - expect(renderToCanvas).toHaveBeenCalledWith( - expect.objectContaining({ - id: 'component-a--story-one', - }), - 'story-root' - ); - }); - - it('deals with stories with "default" name', async () => { - const renderToCanvas = jest.fn(); - - const { configure, clientApi } = start(renderToCanvas); - - configure('test', () => { - clientApi.storiesOf('Component A', { id: 'file1' } as NodeModule).add('default', jest.fn()); - }); - - await waitForRender(); - - expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-a--default'); - }); - - it('deals with stories with camel-cased names', async () => { - const renderToCanvas = jest.fn(); - - const { configure, clientApi } = start(renderToCanvas); - - configure('test', () => { - clientApi - .storiesOf('Component A', { id: 'file1' } as NodeModule) - .add('storyOne', jest.fn()); - }); - - await waitForRender(); - - expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-a--storyone'); - }); - - it('deals with stories with spaces in the name', async () => { - const renderToCanvas = jest.fn(); - - const { configure, clientApi } = start(renderToCanvas); - - configure('test', () => { - clientApi - .storiesOf('Component A', { id: 'file1' } as NodeModule) - .add('Story One', jest.fn()); - }); - - await waitForRender(); - - expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-a--story-one'); - }); - - // https://github.com/storybookjs/storybook/issues/16303 - it('deals with stories with numeric names', async () => { - const renderToCanvas = jest.fn(); - - const { configure, clientApi } = start(renderToCanvas); - - configure('test', () => { - clientApi.storiesOf('Component A', { id: 'file1' } as NodeModule).add('story0', jest.fn()); - }); - - await waitForRender(); - - expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-a--story0'); - }); - - it('deals with storiesOf from the same file twice', async () => { - const renderToCanvas = jest.fn(); - - const { configure, clientApi } = start(renderToCanvas); - - configure('test', () => { - clientApi.storiesOf('Component A', { id: 'file1' } as NodeModule).add('default', jest.fn()); - clientApi.storiesOf('Component B', { id: 'file1' } as NodeModule).add('default', jest.fn()); - clientApi.storiesOf('Component C', { id: 'file1' } as NodeModule).add('default', jest.fn()); - }); - - await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-a--default'); - - const storiesOfData = mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1]; - expect(Object.values(storiesOfData.entries).map((s: any) => s.parameters.fileName)).toEqual([ - 'file1', - 'file1-2', - 'file1-3', - ]); - }); - - it('allows setting compomnent/args/argTypes via a parameter', async () => { - const renderToCanvas = jest.fn(({ storyFn }) => storyFn()); - - const { configure, clientApi } = start(renderToCanvas); - - const component = {}; - configure('test', () => { - clientApi - .storiesOf('Component A', { id: 'file1' } as NodeModule) - .addParameters({ - component, - args: { a: 'a' }, - argTypes: { a: { type: 'string' } }, - }) - .add('default', jest.fn(), { - args: { b: 'b' }, - argTypes: { b: { type: 'string' } }, - }); - }); - - await waitForRender(); - - expect(renderToCanvas).toHaveBeenCalledWith( - expect.objectContaining({ - storyContext: expect.objectContaining({ - component, - args: { a: 'a', b: 'b' }, - argTypes: { - a: { name: 'a', type: { name: 'string' } }, - b: { name: 'b', type: { name: 'string' } }, - }, - }), - }), - 'story-root' - ); - - expect(global.IS_STORYBOOK).toBe(true); - }); - - it('supports forceRerender()', async () => { - const renderToCanvas = jest.fn(({ storyFn }) => storyFn()); - - const { configure, clientApi, forceReRender } = start(renderToCanvas); - - configure('test', () => { - clientApi.storiesOf('Component A', { id: 'file1' } as NodeModule).add('default', jest.fn()); - }); - - await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-a--default'); - - mockChannel.emit.mockClear(); - forceReRender(); - - await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-a--default'); - }); - - it('supports HMR when a story file changes', async () => { - const renderToCanvas = jest.fn(({ storyFn }) => storyFn()); - - const { configure, clientApi } = start(renderToCanvas); - - let disposeCallback: () => void = () => {}; - const module = { - id: 'file1', - hot: { - accept: jest.fn(), - dispose(cb: () => void) { - disposeCallback = cb; - }, - }, - }; - const firstImplementation = jest.fn(); - configure('test', () => { - clientApi.storiesOf('Component A', module as any).add('default', firstImplementation); - }); - - await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-a--default'); - expect(firstImplementation).toHaveBeenCalled(); - expect(module.hot.accept).toHaveBeenCalled(); - expect(disposeCallback).toBeDefined(); - - mockChannel.emit.mockClear(); - disposeCallback(); - const secondImplementation = jest.fn(); - clientApi.storiesOf('Component A', module as any).add('default', secondImplementation); - - await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-a--default'); - expect(secondImplementation).toHaveBeenCalled(); - }); - - it('re-emits SET_INDEX when a story is added', async () => { - const renderToCanvas = jest.fn(({ storyFn }) => storyFn()); - - const { configure, clientApi } = start(renderToCanvas); - - let disposeCallback: () => void = () => {}; - const module = { - id: 'file1', - hot: { - accept: jest.fn(), - dispose(cb: () => void) { - disposeCallback = cb; - }, - }, - }; - configure('test', () => { - clientApi.storiesOf('Component A', module as any).add('default', jest.fn()); - }); - - await waitForRender(); - - mockChannel.emit.mockClear(); - disposeCallback(); - clientApi - .storiesOf('Component A', module as any) - .add('default', jest.fn()) - .add('new', jest.fn()); - - await waitForEvents([SET_INDEX]); - expect(mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1]) - .toMatchInlineSnapshot(` - Object { - "entries": Object { - "component-a--default": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-a", - "id": "component-a--default", - "importPath": "file1", - "initialArgs": Object {}, - "name": "default", - "parameters": Object { - "__id": "component-a--default", - "__isArgsStory": false, - "fileName": "file1", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component A", - "type": "story", - }, - "component-a--new": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-a", - "id": "component-a--new", - "importPath": "file1", - "initialArgs": Object {}, - "name": "new", - "parameters": Object { - "__id": "component-a--new", - "__isArgsStory": false, - "fileName": "file1", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component A", - "type": "story", - }, - }, - "v": 4, - } - `); - }); - - it('re-emits SET_INDEX when a story file is removed', async () => { - const renderToCanvas = jest.fn(({ storyFn }) => storyFn()); - - const { configure, clientApi } = start(renderToCanvas); - - let disposeCallback: () => void = () => {}; - const moduleB = { - id: 'file2', - hot: { - accept: jest.fn(), - dispose(cb: () => void) { - disposeCallback = cb; - }, - }, - }; - configure('test', () => { - clientApi.storiesOf('Component A', { id: 'file1' } as any).add('default', jest.fn()); - clientApi.storiesOf('Component B', moduleB as any).add('default', jest.fn()); - }); - - await waitForEvents([SET_INDEX]); - expect(mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1]) - .toMatchInlineSnapshot(` - Object { - "entries": Object { - "component-a--default": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-a", - "id": "component-a--default", - "importPath": "file1", - "initialArgs": Object {}, - "name": "default", - "parameters": Object { - "__id": "component-a--default", - "__isArgsStory": false, - "fileName": "file1", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component A", - "type": "story", - }, - "component-b--default": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-b", - "id": "component-b--default", - "importPath": "file2", - "initialArgs": Object {}, - "name": "default", - "parameters": Object { - "__id": "component-b--default", - "__isArgsStory": false, - "fileName": "file2", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component B", - "type": "story", - }, - }, - "v": 4, - } - `); - mockChannel.emit.mockClear(); - disposeCallback(); - - await waitForEvents([SET_INDEX]); - expect(mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1]) - .toMatchInlineSnapshot(` - Object { - "entries": Object { - "component-a--default": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-a", - "id": "component-a--default", - "importPath": "file1", - "initialArgs": Object {}, - "name": "default", - "parameters": Object { - "__id": "component-a--default", - "__isArgsStory": false, - "fileName": "file1", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component A", - "type": "story", - }, - }, - "v": 4, - } - `); - }); - }); const componentCExports = { default: { @@ -1039,356 +581,6 @@ describe('start', () => { }); }); - describe('when configure is called with a combination', () => { - it('loads and renders the first story correctly', async () => { - const renderToCanvas = jest.fn(); - - const { configure, clientApi } = start(renderToCanvas); - configure('test', () => { - clientApi - .storiesOf('Component A', { id: 'file1' } as NodeModule) - .add('Story One', jest.fn()) - .add('Story Two', jest.fn()); - - clientApi - .storiesOf('Component B', { id: 'file2' } as NodeModule) - .add('Story Three', jest.fn()); - - return [componentCExports]; - }); - - await waitForRender(); - expect(mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1]) - .toMatchInlineSnapshot(` - Object { - "entries": Object { - "component-a--story-one": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-a", - "id": "component-a--story-one", - "importPath": "file1", - "initialArgs": Object {}, - "name": "Story One", - "parameters": Object { - "__id": "component-a--story-one", - "__isArgsStory": false, - "fileName": "file1", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component A", - "type": "story", - }, - "component-a--story-two": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-a", - "id": "component-a--story-two", - "importPath": "file1", - "initialArgs": Object {}, - "name": "Story Two", - "parameters": Object { - "__id": "component-a--story-two", - "__isArgsStory": false, - "fileName": "file1", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component A", - "type": "story", - }, - "component-b--story-three": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-b", - "id": "component-b--story-three", - "importPath": "file2", - "initialArgs": Object {}, - "name": "Story Three", - "parameters": Object { - "__id": "component-b--story-three", - "__isArgsStory": false, - "fileName": "file2", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component B", - "type": "story", - }, - "component-c--story-one": Object { - "argTypes": Object {}, - "args": Object {}, - "id": "component-c--story-one", - "importPath": "exports-map-0", - "initialArgs": Object {}, - "name": "Story One", - "parameters": Object { - "__isArgsStory": false, - "fileName": "exports-map-0", - "renderer": "test", - }, - "tags": Array [ - "story-tag", - "story", - ], - "title": "Component C", - "type": "story", - }, - "component-c--story-two": Object { - "argTypes": Object {}, - "args": Object {}, - "id": "component-c--story-two", - "importPath": "exports-map-0", - "initialArgs": Object {}, - "name": "Story Two", - "parameters": Object { - "__isArgsStory": false, - "fileName": "exports-map-0", - "renderer": "test", - }, - "tags": Array [ - "component-tag", - "autodocs", - "story", - ], - "title": "Component C", - "type": "story", - }, - }, - "v": 4, - } - `); - - await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-a--story-one'); - - expect(renderToCanvas).toHaveBeenCalledWith( - expect.objectContaining({ - id: 'component-a--story-one', - }), - 'story-root' - ); - }); - - describe('autodocs', () => { - beforeEach(() => { - global.DOCS_OPTIONS = { autodocs: 'tag', defaultName: 'Docs' }; - }); - - it('adds stories for each component with autodocs tag', async () => { - const renderToCanvas = jest.fn(); - - const { configure, clientApi } = start(renderToCanvas); - configure('test', () => { - clientApi - .storiesOf('Component A', { id: 'file1' } as NodeModule) - .add('Story One', jest.fn()) - .add('Story Two', jest.fn()); - - clientApi - .storiesOf('Component B', { id: 'file2' } as NodeModule) - .addParameters({ tags: ['autodocs'] }) - .add('Story Three', jest.fn()); - - return [componentCExports]; - }); - - await waitForRender(); - expect(mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1]) - .toMatchInlineSnapshot(` - Object { - "entries": Object { - "component-a--story-one": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-a", - "id": "component-a--story-one", - "importPath": "file1", - "initialArgs": Object {}, - "name": "Story One", - "parameters": Object { - "__id": "component-a--story-one", - "__isArgsStory": false, - "fileName": "file1", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component A", - "type": "story", - }, - "component-a--story-two": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-a", - "id": "component-a--story-two", - "importPath": "file1", - "initialArgs": Object {}, - "name": "Story Two", - "parameters": Object { - "__id": "component-a--story-two", - "__isArgsStory": false, - "fileName": "file1", - "renderer": "test", - }, - "tags": Array [ - "story", - ], - "title": "Component A", - "type": "story", - }, - "component-b--docs": Object { - "componentId": "component-b", - "id": "component-b--docs", - "importPath": "file2", - "name": "Docs", - "parameters": Object { - "fileName": "file2", - "renderer": "test", - }, - "storiesImports": Array [], - "tags": Array [ - "autodocs", - "docs", - ], - "title": "Component B", - "type": "docs", - }, - "component-b--story-three": Object { - "argTypes": Object {}, - "args": Object {}, - "componentId": "component-b", - "id": "component-b--story-three", - "importPath": "file2", - "initialArgs": Object {}, - "name": "Story Three", - "parameters": Object { - "__id": "component-b--story-three", - "__isArgsStory": false, - "fileName": "file2", - "renderer": "test", - }, - "tags": Array [ - "autodocs", - "story", - ], - "title": "Component B", - "type": "story", - }, - "component-c--docs": Object { - "id": "component-c--docs", - "importPath": "exports-map-0", - "name": "Docs", - "parameters": Object { - "fileName": "exports-map-0", - "renderer": "test", - }, - "storiesImports": Array [], - "tags": Array [ - "component-tag", - "autodocs", - "docs", - ], - "title": "Component C", - "type": "docs", - }, - "component-c--story-one": Object { - "argTypes": Object {}, - "args": Object {}, - "id": "component-c--story-one", - "importPath": "exports-map-0", - "initialArgs": Object {}, - "name": "Story One", - "parameters": Object { - "__isArgsStory": false, - "fileName": "exports-map-0", - "renderer": "test", - }, - "tags": Array [ - "story-tag", - "story", - ], - "title": "Component C", - "type": "story", - }, - "component-c--story-two": Object { - "argTypes": Object {}, - "args": Object {}, - "id": "component-c--story-two", - "importPath": "exports-map-0", - "initialArgs": Object {}, - "name": "Story Two", - "parameters": Object { - "__isArgsStory": false, - "fileName": "exports-map-0", - "renderer": "test", - }, - "tags": Array [ - "component-tag", - "autodocs", - "story", - ], - "title": "Component C", - "type": "story", - }, - }, - "v": 4, - } - `); - }); - }); - describe('when docsOptions.autodocs = true', () => { - beforeEach(() => { - global.DOCS_OPTIONS = { autodocs: true, defaultName: 'Docs' }; - }); - - it('adds stories for each component with autodocs tag', async () => { - const renderToDOM = jest.fn(); - - const { configure, clientApi } = start(renderToDOM); - configure('test', () => { - (clientApi as any).addParameters({ - docs: { renderer: () => ({ render: jest.fn((_, _2, _3, d) => d()) }) }, - }); - clientApi - .storiesOf('Component A', { id: 'file1' } as NodeModule) - .add('Story One', jest.fn()) - .add('Story Two', jest.fn()); - - clientApi - .storiesOf('Component B', { id: 'file2' } as NodeModule) - .addParameters({ tags: ['autodocs'] }) - .add('Story Three', jest.fn()); - - return [componentCExports]; - }); - - await waitForRender(); - const setIndexData = mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1]; - expect(Object.keys(setIndexData.entries)).toMatchInlineSnapshot(` - Array [ - "component-a--docs", - "component-a--story-one", - "component-a--story-two", - "component-b--docs", - "component-b--story-three", - "component-c--docs", - "component-c--story-one", - "component-c--story-two", - ] - `); - }); - }); - }); - describe('auto-title', () => { const componentDExports = { default: { diff --git a/code/lib/preview-api/src/modules/core-client/start.ts b/code/lib/preview-api/src/modules/core-client/start.ts index f9c389f71e8f..3b527da4cd1a 100644 --- a/code/lib/preview-api/src/modules/core-client/start.ts +++ b/code/lib/preview-api/src/modules/core-client/start.ts @@ -32,11 +32,6 @@ interface CoreClient_RendererImplementation { } interface CoreClient_ClientAPIFacade { - /** - * The old way of adding stories at runtime. - * @deprecated This method is deprecated and will be removed in a future version. - */ - storiesOf: (...args: any[]) => never; /** * The old way of retrieving the list of stories at runtime. * @deprecated This method is deprecated and will be removed in a future version. @@ -88,7 +83,6 @@ export function start( forceReRender: removedApi('forceReRender'), configure: removedApi('configure'), clientApi: { - storiesOf: removedApi('clientApi.storiesOf'), raw: removedApi('raw'), }, }; diff --git a/code/lib/types/src/modules/addons.ts b/code/lib/types/src/modules/addons.ts index ff015d7071b9..337b84ba4f86 100644 --- a/code/lib/types/src/modules/addons.ts +++ b/code/lib/types/src/modules/addons.ts @@ -156,9 +156,8 @@ export interface Addon_StoryApi { [k: string]: string | Addon_ClientApiReturnFn; } -export interface Addon_ClientStoryApi { - storiesOf(kind: StoryKind, module: any): Addon_StoryApi; -} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface Addon_ClientStoryApi {} export type Addon_LoadFn = () => any; export type Addon_RequireContext = any; // FIXME diff --git a/code/renderers/html/src/public-api.ts b/code/renderers/html/src/public-api.ts index 542eb1ca7b65..e69de29bb2d1 100644 --- a/code/renderers/html/src/public-api.ts +++ b/code/renderers/html/src/public-api.ts @@ -1,26 +0,0 @@ -/* eslint-disable prefer-destructuring */ -import type { Addon_ClientStoryApi, Addon_Loadable } from '@storybook/types'; -import { start } from '@storybook/preview-api'; -import type { HtmlRenderer } from './types'; - -import { renderToCanvas, render } from './render'; - -const RENDERER = 'html'; - -interface ClientApi extends Addon_ClientStoryApi { - configure(loader: Addon_Loadable, module: NodeModule): void; - forceReRender(): void; - raw: () => any; // todo add type -} - -const api = start(renderToCanvas, { render }); - -export const storiesOf: ClientApi['storiesOf'] = (kind, m) => { - return (api.clientApi.storiesOf(kind, m) as ReturnType).addParameters({ - renderer: RENDERER, - }); -}; - -export const configure: ClientApi['configure'] = (...args) => api.configure(RENDERER, ...args); -export const forceReRender: ClientApi['forceReRender'] = api.forceReRender; -export const raw: ClientApi['raw'] = api.clientApi.raw; diff --git a/code/renderers/preact/src/public-api.ts b/code/renderers/preact/src/public-api.ts index 7a5451bb9ae8..e69de29bb2d1 100644 --- a/code/renderers/preact/src/public-api.ts +++ b/code/renderers/preact/src/public-api.ts @@ -1,26 +0,0 @@ -/* eslint-disable prefer-destructuring */ -import type { Addon_ClientStoryApi, Addon_Loadable } from '@storybook/types'; -import { start } from '@storybook/preview-api'; - -import { renderToCanvas } from './render'; -import type { PreactRenderer } from './types'; - -export interface ClientApi extends Addon_ClientStoryApi { - configure(loader: Addon_Loadable, module: NodeModule): void; - forceReRender(): void; - raw: () => any; // todo add type - load: (...args: any[]) => void; -} - -const RENDERER = 'preact'; -const api = start(renderToCanvas); - -export const storiesOf: ClientApi['storiesOf'] = (kind, m) => { - return (api.clientApi.storiesOf(kind, m) as ReturnType).addParameters({ - renderer: RENDERER, - }); -}; - -export const configure: ClientApi['configure'] = (...args) => api.configure(RENDERER, ...args); -export const forceReRender: ClientApi['forceReRender'] = api.forceReRender; -export const raw: ClientApi['raw'] = api.clientApi.raw; diff --git a/code/renderers/react/src/public-api.tsx b/code/renderers/react/src/public-api.tsx index aaef6d65ddd2..e69de29bb2d1 100644 --- a/code/renderers/react/src/public-api.tsx +++ b/code/renderers/react/src/public-api.tsx @@ -1,25 +0,0 @@ -/* eslint-disable prefer-destructuring */ -import { start } from '@storybook/preview-api'; -import type { Addon_ClientStoryApi, Addon_Loadable } from '@storybook/types'; - -import { render, renderToCanvas } from './render'; -import type { ReactRenderer } from './types'; - -interface ClientApi extends Addon_ClientStoryApi { - configure(loader: Addon_Loadable, module: NodeModule): void; - forceReRender(): void; - raw: () => any; // todo add type -} -const RENDERER = 'react'; - -const api = start(renderToCanvas, { render }); - -export const storiesOf: ClientApi['storiesOf'] = (kind, m) => { - return (api.clientApi.storiesOf(kind, m) as ReturnType).addParameters({ - renderer: RENDERER, - }); -}; - -export const configure: ClientApi['configure'] = (...args) => api.configure(RENDERER, ...args); -export const forceReRender: ClientApi['forceReRender'] = api.forceReRender; -export const raw: ClientApi['raw'] = api.clientApi.raw; diff --git a/code/renderers/server/src/public-api.ts b/code/renderers/server/src/public-api.ts index e830f96a8918..e69de29bb2d1 100644 --- a/code/renderers/server/src/public-api.ts +++ b/code/renderers/server/src/public-api.ts @@ -1,26 +0,0 @@ -import type { Addon_ClientStoryApi, Addon_Loadable } from '@storybook/types'; -import { start } from '@storybook/preview-api'; - -import { renderToCanvas, render } from './render'; -import type { ServerRenderer } from './types'; - -const RENDERER = 'server'; - -interface ClientApi extends Addon_ClientStoryApi { - configure(loader: Addon_Loadable, module: NodeModule): void; - forceReRender(): void; - raw: () => any; // todo add type -} - -const api = start(renderToCanvas, { render }); - -export const storiesOf: ClientApi['storiesOf'] = (kind, m) => { - return (api.clientApi.storiesOf(kind, m) as ReturnType).addParameters({ - renderer: RENDERER, - }); -}; - -export const configure: ClientApi['configure'] = (...args) => api.configure(RENDERER, ...args); -export const { raw } = api.clientApi; - -export const { forceReRender } = api; diff --git a/code/renderers/svelte/src/public-api.ts b/code/renderers/svelte/src/public-api.ts index fde627e6a20e..e69de29bb2d1 100644 --- a/code/renderers/svelte/src/public-api.ts +++ b/code/renderers/svelte/src/public-api.ts @@ -1,30 +0,0 @@ -/* eslint-disable prefer-destructuring */ -import { start } from '@storybook/preview-api'; -import type { Addon_ClientStoryApi, Addon_Loadable } from '@storybook/types'; -import { decorateStory } from './decorators'; - -import type { SvelteRenderer } from './types'; -import { render, renderToCanvas } from './render'; - -const RENDERER = 'svelte'; - -interface ClientApi extends Addon_ClientStoryApi { - configure(loader: Addon_Loadable, module: NodeModule): void; - forceReRender(): void; - raw: () => any; // todo add type -} - -const api = start(renderToCanvas, { - decorateStory, - render, -}); - -export const storiesOf: ClientApi['storiesOf'] = (kind, m) => { - return (api.clientApi.storiesOf(kind, m) as ReturnType).addParameters({ - renderer: RENDERER, - }); -}; - -export const configure: ClientApi['configure'] = (...args) => api.configure(RENDERER, ...args); -export const forceReRender: ClientApi['forceReRender'] = api.forceReRender; -export const raw: ClientApi['raw'] = api.clientApi.raw; diff --git a/code/renderers/vue/src/public-api.ts b/code/renderers/vue/src/public-api.ts index 708e4e2b4014..e69de29bb2d1 100644 --- a/code/renderers/vue/src/public-api.ts +++ b/code/renderers/vue/src/public-api.ts @@ -1,28 +0,0 @@ -/* eslint-disable prefer-destructuring */ -import type { Addon_ClientStoryApi, Addon_Loadable } from '@storybook/types'; -import { start } from '@storybook/preview-api'; - -import type { VueRenderer } from './types'; -import { renderToCanvas, render } from './render'; -import { decorateStory } from './decorateStory'; - -const RENDERER = 'vue'; - -interface ClientApi extends Addon_ClientStoryApi { - configure(loader: Addon_Loadable, module: NodeModule): void; - forceReRender(): void; - raw: () => any; // todo add type - load: (...args: any[]) => void; -} - -const api = start(renderToCanvas, { decorateStory, render }); - -export const storiesOf: ClientApi['storiesOf'] = (kind, m) => { - return (api.clientApi.storiesOf(kind, m) as ReturnType).addParameters({ - renderer: RENDERER, - }); -}; - -export const configure: ClientApi['configure'] = (...args) => api.configure(RENDERER, ...args); -export const forceReRender: ClientApi['forceReRender'] = api.forceReRender; -export const raw: ClientApi['raw'] = api.clientApi.raw; diff --git a/code/renderers/vue3/src/public-api.ts b/code/renderers/vue3/src/public-api.ts index a6daddc418ac..a2d5f8e5bc4a 100644 --- a/code/renderers/vue3/src/public-api.ts +++ b/code/renderers/vue3/src/public-api.ts @@ -1,31 +1 @@ -import type { Addon_ClientStoryApi, Addon_Loadable } from '@storybook/types'; -import type { App } from 'vue'; -import { start } from '@storybook/preview-api'; - -import type { VueRenderer } from './types'; -import { decorateStory } from './decorateStory'; - -import { render, renderToCanvas } from './render'; - -const RENDERER = 'vue3'; - -interface ClientApi extends Addon_ClientStoryApi { - configure(loader: Addon_Loadable, module: NodeModule): void; - forceReRender(): void; - raw: () => any; // todo add type - load: (...args: any[]) => void; - app: App; -} - -const api = start(renderToCanvas, { decorateStory, render }); - -export const storiesOf: ClientApi['storiesOf'] = (kind, m) => { - return (api.clientApi.storiesOf(kind, m) as ReturnType).addParameters({ - renderer: RENDERER, - }); -}; - -export const configure: ClientApi['configure'] = (...args) => api.configure(RENDERER, ...args); -export const { forceReRender } = api; -export const { raw } = api.clientApi; export { setup } from './render'; diff --git a/code/renderers/web-components/src/public-api.ts b/code/renderers/web-components/src/public-api.ts index b8e1b24bb107..e69de29bb2d1 100644 --- a/code/renderers/web-components/src/public-api.ts +++ b/code/renderers/web-components/src/public-api.ts @@ -1,26 +0,0 @@ -/* eslint-disable prefer-destructuring */ -import type { Addon_ClientStoryApi, Addon_Loadable } from '@storybook/types'; -import { start } from '@storybook/preview-api'; - -import { renderToCanvas } from './render'; -import type { WebComponentsRenderer } from './types'; - -const RENDERER = 'web-components'; - -interface ClientApi extends Addon_ClientStoryApi { - configure(loader: Addon_Loadable, module: NodeModule): void; - forceReRender(): void; - raw: () => any; // todo add type -} - -const api = start(renderToCanvas); - -export const storiesOf: ClientApi['storiesOf'] = (kind, m) => { - return (api.clientApi.storiesOf(kind, m) as ReturnType).addParameters({ - renderer: RENDERER, - }); -}; - -export const configure: ClientApi['configure'] = (...args) => api.configure(RENDERER, ...args); -export const forceReRender: ClientApi['forceReRender'] = api.forceReRender; -export const raw: ClientApi['raw'] = api.clientApi.raw; diff --git a/code/ui/components/src/components/syntaxhighlighter/syntaxhighlighter.stories.tsx b/code/ui/components/src/components/syntaxhighlighter/syntaxhighlighter.stories.tsx index 12d76391f6cf..06f2a3a2cb43 100644 --- a/code/ui/components/src/components/syntaxhighlighter/syntaxhighlighter.stories.tsx +++ b/code/ui/components/src/components/syntaxhighlighter/syntaxhighlighter.stories.tsx @@ -179,36 +179,34 @@ export const UnsupportedDark = { export const Story = { args: { language: 'jsx', - children: `import React from 'react'; - import { storiesOf } from '@storybook/react'; - import { styled } from '@storybook/theming'; - - import Heading from './heading'; - - const Holder = styled.div({ - margin: 10, - border: '1px dashed deepskyblue', - // overflow: 'hidden', - }); - - storiesOf('Basics|Heading', module).add('types', () => ( -
- - DEFAULT WITH ALL CAPS - - - THIS LONG DEFAULT WITH ALL CAPS & SUB - - - page type - - - - page type - - -
- ));`, + children: `import type { Meta, StoryObj } from '@storybook/react'; + + import { Header } from './Header'; + + const meta = { + title: 'Example/Header', + component: Header, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs + tags: ['autodocs'], + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout + layout: 'fullscreen', + }, + } satisfies Meta; + + export default meta; + type Story = StoryObj; + + export const LoggedIn: Story = { + args: { + user: { + name: 'Jane Doe', + }, + }, + }; + + export const LoggedOut: Story = {}; + `, }, };