Skip to content

Commit

Permalink
feat: support storybook docs-only pages
Browse files Browse the repository at this point in the history
  • Loading branch information
atanasster committed Jul 31, 2020
1 parent d455445 commit 4014d65
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 30 deletions.
3 changes: 2 additions & 1 deletion core/instrument/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export const parseStories = async (
test,
renderer,
transformMDX,
storybookExports,
...otherMDXOptions
} = mergedOptions.mdx;
if (test && filePath.match(test)) {
Expand Down Expand Up @@ -165,7 +166,7 @@ export const parseStories = async (
};
}
const { stories, doc, components, exports, packages } = store || {};
const exportsSource = extractStoryExports(exports);
const exportsSource = extractStoryExports(storybookExports, exports);
let transformed = `
${content}
Expand Down
43 changes: 33 additions & 10 deletions core/instrument/src/misc/mdx-exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,39 @@ const mdxFunctionExport = (
: undefined;
};

export const extractStoryExports = (exports?: MDXExportTypes): string => {
export const extractStoryExports = (
storybookExports: boolean,
exports?: MDXExportTypes,
): string => {
if (exports) {
const exportNames = Object.keys(exports);
if (exportNames.length) {
let defaultExportCode = '';
if (exports.default) {
const expCode = mdxPropertiesExport(exports.default, {
MDXPage: new String('MDXContent'),
});
defaultExportCode = `export default ${expCode};`;
const defaults: any = { MDXPage: new String('MDXContent') };
if (storybookExports) {
//docs parameters
defaults.parameters = {
docs: {
page: new String('MDXContent'),
container: new String(
'({ children }) => <React.Fragment>{children}</React.Fragment>',
),
},
};
}
const expCode = mdxPropertiesExport(exports.default, defaults);
defaultExportCode = `
const mdxDefaultExport = MDXContent;
Object.assign(mdxDefaultExport, ${expCode});
export default mdxDefaultExport;
`;
}

let storiesExports: string[] = [];
const expStories = Object.keys(exports).filter(id => id !== 'default');

if (expStories.length) {
const storiesExports: string[] = [];
for (const exportStory of expStories) {
const expFn = mdxFunctionExport(exportStory, exports[exportStory]);
if (expFn) {
Expand All @@ -44,13 +62,18 @@ export const extractStoryExports = (exports?: MDXExportTypes): string => {
`);
}
}
return `${defaultExportCode}\n${storiesExports.join('\n')}`;
} else if (storybookExports) {
//fake page object to accoodate storybook
return `${defaultExportCode}
export const __page = () => { throw new Error("Docs-only story"); };
__page.story = { parameters: { docsOnly: true } };
`;
}
return `${defaultExportCode}\n${storiesExports.join('\n')}`;
return `${defaultExportCode}`;
}
}
return `
const dmsPageExport = MDXContent;
dmsPageExport.MDXPage = MDXContent;
export default dmsPageExport;
export default { MDXPage: MDXContent };
`;
};
5 changes: 5 additions & 0 deletions core/instrument/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ export interface MDXOptions {
* if true, will return the transformed MDX -< JSX, ready to be loaded by babel
*/
transformMDX?: boolean;

/**
* generate storybok required fake exports for MDX compatibility
*/
storybookExports?: boolean;
/**
* ability to configure the mdx files imports. Works with transformMDX: true
* by default this is the string
Expand Down
1 change: 1 addition & 0 deletions core/webpack-configs/src/instrument/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const instrument: Configuration = {
options: {
mdx: {
transformMDX: true,
storybookExports: true,
},
},
},
Expand Down
5 changes: 2 additions & 3 deletions integrations/storybook/src/context/BlockContext.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { BlockContextProvider as BlocksContextProvider } from '@component-controls/blocks';
import { store } from '@component-controls/store/live_store';
import { useStoryId } from '@component-controls/storybook-custom-docs';
import { useCurrentData } from '@component-controls/storybook-custom-docs';

export interface BlockContextProviderProps {
id?: string;
Expand All @@ -10,9 +10,8 @@ export const BlockContextProvider: React.FC<BlockContextProviderProps> = ({
children,
id,
}) => {
const defaultStoyId = useStoryId();
const { storyId: defaultStoyId, docId } = useCurrentData();
const storyId = id ? id : defaultStoyId;
const docId = storyId && store ? store.stories[storyId].doc : undefined;
return (
<BlocksContextProvider store={store} storyId={storyId} docId={docId}>
{children}
Expand Down
6 changes: 2 additions & 4 deletions integrations/storybook/src/docs-page/DocsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ import {
} from '@component-controls/blocks';
import { ThemeProvider } from '@component-controls/components';
import {
useStoryId,
useCurrentData,
getGlobalOptions,
} from '@component-controls/storybook-custom-docs';
import { store } from '@component-controls/store/live_store';

export const PageContextContainer: FC = ({ children }) => {
const options = React.useMemo(() => getGlobalOptions(), []);
const storyId = useStoryId();
const docId = storyId && store ? store.stories[storyId].doc : undefined;
console.group('HERE', docId);
const { storyId, docId } = useCurrentData();
return (
<ThemeProvider theme={store.config.theme}>
<BlockContextProvider
Expand Down
40 changes: 28 additions & 12 deletions misc/storybook-custom-docs/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ export * from './types';
export const getGlobalOptions = (): any => {
const store =
window &&
//@ts-ignore
window.__STORYBOOK_CLIENT_API__ &&
//@ts-ignore
window.__STORYBOOK_CLIENT_API__.store();
(window as any).__STORYBOOK_CLIENT_API__ &&
(window as any).__STORYBOOK_CLIENT_API__.store();
//@ts-ignore
return store._globalMetadata;
};
Expand All @@ -25,10 +23,8 @@ export const getGlobalOptions = (): any => {
export const getCurrentStoryId = (): string | undefined => {
const store =
window &&
//@ts-ignore
window.__STORYBOOK_CLIENT_API__ &&
//@ts-ignore
window.__STORYBOOK_CLIENT_API__.store();
(window as any).__STORYBOOK_CLIENT_API__ &&
(window as any).__STORYBOOK_CLIENT_API__.store();

const selection = store.getSelection();
//@ts-ignore
Expand All @@ -42,9 +38,9 @@ const getGlobalStoryId = (): string => {
}
return globalStoryId;
};

/**
* React hook hook that tracks the changes to the current story and returns it's id
* @param defaultId initial story value, if not provided will return the current story
* @returns a story id as a React hook, when the the current story changes, will call back
*/
export const useStoryId = () => {
Expand All @@ -66,16 +62,36 @@ export const useStoryId = () => {
return storyId;
};

/**
* React hook hook that tracks the changes to the current story and returns the data
* @returns a story id , document id, name and parameters
*/

export const useCurrentData = (): {
storyId: string;
docId: string;
name: string;
parameters: any;
} => {
const storyId = useStoryId();
const storyStore = (window as any).__STORYBOOK_CLIENT_API__._storyStore;
const data = storyStore.fromId(storyId);
const { kind, name, parameters = {} } = data || {};
return {
storyId,
docId: kind,
name,
parameters,
};
};
/**
* React hook - returns a context similar (but not identical) that can be used as an input attribute to `<DocsContainer />`
*/
export const useContext = () => {
const channel = addons.getChannel();
const storyId = useStoryId();
//@ts-ignore
const clientApi = window.__STORYBOOK_CLIENT_API__;
const clientApi = (window as any).__STORYBOOK_CLIENT_API__;
const storyStore = clientApi._storyStore;
//@ts-ignore
const configApi = new ConfigApi({
storyStore,
//@ts-ignore
Expand Down

0 comments on commit 4014d65

Please sign in to comment.