Skip to content

Commit

Permalink
Merge pull request #18099 from storybookjs/future/docs2/preview
Browse files Browse the repository at this point in the history
Docs2: Handle new docs entries in the preview
  • Loading branch information
shilman authored May 9, 2022
2 parents cf0529e + dffce1e commit 4c47903
Show file tree
Hide file tree
Showing 30 changed files with 862 additions and 484 deletions.
4 changes: 2 additions & 2 deletions addons/docs/src/blocks/DocsContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ export type { DocsContextProps };
// This was specifically a problem with the Vite builder.
/* eslint-disable no-underscore-dangle */
if (globalWindow && globalWindow.__DOCS_CONTEXT__ === undefined) {
globalWindow.__DOCS_CONTEXT__ = createContext({});
globalWindow.__DOCS_CONTEXT__ = createContext(null);
globalWindow.__DOCS_CONTEXT__.displayName = 'DocsContext';
}

export const DocsContext: Context<DocsContextProps<AnyFramework>> = globalWindow
? globalWindow.__DOCS_CONTEXT__
: createContext({});
: createContext(null);
58 changes: 58 additions & 0 deletions addons/docs/src/blocks/DocsRenderer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { ComponentType } from 'react';
import ReactDOM from 'react-dom';
import { AnyFramework, Parameters } from '@storybook/csf';
import { DocsRenderFunction } from '@storybook/preview-web';

import { DocsContainer } from './DocsContainer';
import { DocsPage } from './DocsPage';
import { DocsContext, DocsContextProps } from './DocsContext';

export class DocsRenderer<TFramework extends AnyFramework> {
public render: DocsRenderFunction<TFramework>;

public unmount: (element: HTMLElement) => void;

constructor() {
this.render = (
docsContext: DocsContextProps<TFramework>,
docsParameters: Parameters,
element: HTMLElement,
callback: () => void
): void => {
renderDocsAsync(docsContext, docsParameters, element).then(callback);
};

this.unmount = (element: HTMLElement) => {
ReactDOM.unmountComponentAtNode(element);
};
}
}

async function renderDocsAsync<TFramework extends AnyFramework>(
docsContext: DocsContextProps<TFramework>,
docsParameters: Parameters,
element: HTMLElement
) {
// FIXME -- use DocsContainer, make it work for modern
const SimpleContainer = ({ children }: any) => (
<DocsContext.Provider value={docsContext}>{children} </DocsContext.Provider>
);

const Container: ComponentType<{ context: DocsContextProps<TFramework> }> =
docsParameters.container ||
(await docsParameters.getContainer?.()) ||
(docsContext.legacy ? DocsContainer : SimpleContainer);

const Page: ComponentType = docsParameters.page || (await docsParameters.getPage?.()) || DocsPage;

// Use `title` as a key so that we force a re-render every time we switch components
const docsElement = (
<Container key={docsContext.title} context={docsContext}>
<Page />
</Container>
);

await new Promise<void>((resolve) => {
ReactDOM.render(docsElement, element, resolve);
});
}
3 changes: 3 additions & 0 deletions addons/docs/src/blocks/Meta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ function getFirstStoryId(docsContext: DocsContextProps): string {

function renderAnchor() {
const context = useContext(DocsContext);
if (!context.legacy) {
return null;
}
const anchorId = getFirstStoryId(context) || context.id;

return <Anchor storyId={anchorId} />;
Expand Down
8 changes: 7 additions & 1 deletion addons/docs/src/blocks/Story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type StoryDefProps = {

type StoryRefProps = {
id?: string;
of?: any;
};

type StoryImportProps = {
Expand All @@ -55,7 +56,12 @@ export const lookupStoryId = (
);

export const getStoryId = (props: StoryProps, context: DocsContextProps): StoryId => {
const { id } = props as StoryRefProps;
const { id, of } = props as StoryRefProps;

if (of) {
return context.storyIdByModuleExport(of);
}

const { name } = props as StoryDefProps;
const inputId = id === CURRENT_SELECTION ? context.id : id;
return inputId || lookupStoryId(name, context);
Expand Down
1 change: 1 addition & 0 deletions addons/docs/src/blocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * from './Description';
export * from './DocsContext';
export * from './DocsPage';
export * from './DocsContainer';
export * from './DocsRenderer'; // For testing
export * from './DocsStory';
export * from './Heading';
export * from './Meta';
Expand Down
20 changes: 13 additions & 7 deletions addons/docs/src/blocks/useStory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,9 @@ export function useStories<TFramework extends AnyFramework = AnyFramework>(
storyIds: StoryId[],
context: DocsContextProps<TFramework>
): (Story<TFramework> | void)[] {
const initialStoriesById = context.componentStories().reduce((acc, story) => {
acc[story.id] = story;
return acc;
}, {} as Record<StoryId, Story<TFramework>>);

const [storiesById, setStories] = useState(initialStoriesById as typeof initialStoriesById);
// Legacy docs pages can reference any story by id. Those stories will need to be
// asyncronously loaded; we use the state for this
const [storiesById, setStories] = useState<Record<StoryId, Story<TFramework>>>({});

useEffect(() => {
Promise.all(
Expand All @@ -40,5 +37,14 @@ export function useStories<TFramework extends AnyFramework = AnyFramework>(
);
});

return storyIds.map((storyId) => storiesById[storyId]);
return storyIds.map((storyId) => {
if (storiesById[storyId]) return storiesById[storyId];

try {
// If we are allowed to load this story id synchonously, this will work
return context.storyById(storyId);
} catch (err) {
return null;
}
});
}
6 changes: 4 additions & 2 deletions addons/docs/src/preview.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export const parameters = {
docs: {
getContainer: async () => (await import('./blocks')).DocsContainer,
getPage: async () => (await import('./blocks')).DocsPage,
renderer: async () => {
const { DocsRenderer } = await import('./blocks/DocsRenderer');
return new DocsRenderer();
},
},
};
5 changes: 4 additions & 1 deletion examples/react-ts/src/docs2/MetaOf.docs.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import meta from '../button.stories';
import { Meta, Story } from '@storybook/addon-docs';
import meta, { Basic } from '../button.stories';

<Meta of={meta} />

# Docs with of

hello docs

<Story of={Basic} />
3 changes: 3 additions & 0 deletions lib/core-client/src/preview/start.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,7 @@ describe('start', () => {
"v": 2,
}
`);
await waitForRender();

mockChannel.emit.mockClear();
disposeCallback(module.hot.data);
Expand Down Expand Up @@ -1340,6 +1341,8 @@ describe('start', () => {
"v": 2,
}
`);

await waitForRender();
});
});
});
4 changes: 0 additions & 4 deletions lib/preview-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,6 @@
"unfetch": "^4.2.0",
"util-deprecate": "^1.0.2"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"publishConfig": {
"access": "public"
},
Expand Down
Loading

0 comments on commit 4c47903

Please sign in to comment.