-
-
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.
Addon-docs: DocsPage and doc blocks (#7119)
Addon-docs: DocsPage and doc blocks
- Loading branch information
Showing
51 changed files
with
2,374 additions
and
10 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 |
---|---|---|
@@ -0,0 +1 @@ | ||
module.exports = require('./dist/blocks'); |
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 |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* eslint-disable no-underscore-dangle */ | ||
import React from 'react'; | ||
import { Description, DescriptionProps as PureDescriptionProps } from '@storybook/components'; | ||
import { DocsContext, DocsContextProps } from './DocsContext'; | ||
import { Component, CURRENT_SELECTION } from './shared'; | ||
|
||
export enum DescriptionType { | ||
INFO = 'info', | ||
NOTES = 'notes', | ||
DOCGEN = 'docgen', | ||
AUTO = 'auto', | ||
} | ||
|
||
type Notes = string | any; | ||
type Info = string | any; | ||
|
||
interface DescriptionProps { | ||
of?: '.' | Component; | ||
type?: DescriptionType; | ||
markdown?: string; | ||
} | ||
|
||
const getNotes = (notes?: Notes) => | ||
notes && (typeof notes === 'string' ? notes : notes.markdown || notes.text); | ||
|
||
const getInfo = (info?: Info) => info && (typeof info === 'string' ? info : info.text); | ||
|
||
const getDocgen = (component?: Component) => | ||
(component && component.__docgenInfo && component.__docgenInfo.description) || ''; | ||
|
||
export const getDescriptionProps = ( | ||
{ of, type, markdown }: DescriptionProps, | ||
{ parameters }: DocsContextProps | ||
): PureDescriptionProps => { | ||
if (markdown) { | ||
return { markdown }; | ||
} | ||
const { component, notes, info } = parameters; | ||
const target = of === CURRENT_SELECTION ? component : of; | ||
switch (type) { | ||
case DescriptionType.INFO: | ||
return { markdown: getInfo(info) }; | ||
case DescriptionType.NOTES: | ||
return { markdown: getNotes(notes) }; | ||
case DescriptionType.DOCGEN: | ||
return { markdown: getDocgen(target) }; | ||
case DescriptionType.AUTO: | ||
default: | ||
return { | ||
markdown: ` | ||
${getNotes(notes) || getInfo(info) || ''} | ||
${getDocgen(target)} | ||
`.trim(), | ||
}; | ||
} | ||
}; | ||
|
||
const DescriptionContainer: React.FunctionComponent<DescriptionProps> = props => ( | ||
<DocsContext.Consumer> | ||
{context => { | ||
const { markdown } = getDescriptionProps(props, context); | ||
return markdown && <Description markdown={markdown} />; | ||
}} | ||
</DocsContext.Consumer> | ||
); | ||
|
||
export { DescriptionContainer as Description }; |
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,52 @@ | ||
/* eslint-disable react/destructuring-assignment */ | ||
|
||
import React from 'react'; | ||
// import { MDXProvider } from '@mdx-js/react'; | ||
import { Global, createGlobal, ThemeProvider, ensure as ensureTheme } from '@storybook/theming'; | ||
import { DocumentFormatting, DocsWrapper, DocsContent } from '@storybook/components'; | ||
import { DocsContextProps, DocsContext } from './DocsContext'; | ||
|
||
interface DocsContainerProps { | ||
context: DocsContextProps; | ||
content: React.ElementType<any>; | ||
} | ||
|
||
const defaultComponents = { | ||
// p: ({ children }) => <b>{children}</b>, | ||
wrapper: DocumentFormatting, | ||
}; | ||
|
||
const globalWithOverflow = (args: any) => { | ||
const global = createGlobal(args); | ||
const { body, ...rest } = global; | ||
const { overflow, ...bodyRest } = body; | ||
return { | ||
body: bodyRest, | ||
...rest, | ||
}; | ||
}; | ||
|
||
export const DocsContainer: React.FunctionComponent<DocsContainerProps> = ({ | ||
context, | ||
content: MDXContent, | ||
}) => { | ||
const parameters = (context && context.parameters) || {}; | ||
const options = parameters.options || {}; | ||
const theme = ensureTheme(options.theme); | ||
const { components: userComponents = null } = options.docs || {}; | ||
const components = { ...defaultComponents, ...userComponents }; | ||
return ( | ||
<DocsContext.Provider value={context}> | ||
<ThemeProvider theme={theme}> | ||
<Global styles={globalWithOverflow} /> | ||
{/* <MDXProvider components={components}> */} | ||
<DocsWrapper> | ||
<DocsContent> | ||
<MDXContent components={components} /> | ||
</DocsContent> | ||
</DocsWrapper> | ||
{/* </MDXProvider> */} | ||
</ThemeProvider> | ||
</DocsContext.Provider> | ||
); | ||
}; |
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,23 @@ | ||
import React from 'react'; | ||
|
||
export interface DocsContextProps { | ||
id?: string; | ||
selectedKind?: string; | ||
selectedStory?: string; | ||
|
||
/** | ||
* mdxKind is a statically-generated "kind" that corresponds to the | ||
* component that's being documented in the MDX file, It's combined | ||
* with the MDX story name `<Story name='story name'>...</Story>` to | ||
* generate a storyId. In the case that the user is viewing a non-MDX | ||
* story, the value of `mdxKind` will be the currently-selected kind. | ||
* (I can't remember the corner case in which using the currentl-selected | ||
* kind breaks down in MDX-defined stories, but there is one!) | ||
*/ | ||
mdxKind?: string; | ||
parameters?: any; | ||
storyStore?: any; | ||
forceRender?: () => void; | ||
} | ||
|
||
export const DocsContext: React.Context<DocsContextProps> = React.createContext({}); |
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,140 @@ | ||
import React from 'react'; | ||
|
||
import { parseKind } from '@storybook/router'; | ||
import { styled } from '@storybook/theming'; | ||
import { DocsPage as PureDocsPage, DocsPageProps } from '@storybook/components'; | ||
import { DocsContext, DocsContextProps } from './DocsContext'; | ||
import { DocsContainer } from './DocsContainer'; | ||
import { Description } from './Description'; | ||
import { Story } from './Story'; | ||
import { Preview } from './Preview'; | ||
import { Props } from './Props'; | ||
|
||
enum DocsStoriesType { | ||
ALL = 'all', | ||
PRIMARY = 'primary', | ||
REST = 'rest', | ||
} | ||
|
||
interface DocsStoriesProps { | ||
type?: DocsStoriesType; | ||
} | ||
|
||
interface DocsStoryProps { | ||
id: string; | ||
name: string; | ||
description?: string; | ||
expanded?: boolean; | ||
} | ||
|
||
interface StoryData { | ||
id: string; | ||
kind: string; | ||
name: string; | ||
parameters?: any; | ||
} | ||
|
||
const getDocsStories = (type: DocsStoriesType, componentStories: StoryData[]): DocsStoryProps[] => { | ||
let stories = componentStories; | ||
if (type !== DocsStoriesType.ALL) { | ||
const primary = stories.find(s => s.parameters && s.parameters.primary); | ||
const [first, ...rest] = stories; | ||
if (type === DocsStoriesType.PRIMARY) { | ||
stories = [primary || first]; | ||
} else { | ||
stories = primary ? stories.filter(s => !s.parameters || !s.parameters.primary) : rest; | ||
} | ||
} | ||
return stories.map(({ id, name, parameters: { notes, info } }) => ({ | ||
id, | ||
name, | ||
description: notes || info || null, | ||
})); | ||
}; | ||
|
||
const StoriesHeading = styled.h2(); | ||
const StoryHeading = styled.h3(); | ||
|
||
const DocsStory: React.FunctionComponent<DocsStoryProps> = ({ | ||
id, | ||
name, | ||
description, | ||
expanded = true, | ||
}) => ( | ||
<> | ||
{expanded && <StoryHeading>{name}</StoryHeading>} | ||
{expanded && description && <Description markdown={description} />} | ||
<Preview> | ||
<Story id={id} /> | ||
</Preview> | ||
</> | ||
); | ||
|
||
const DocsStories: React.FunctionComponent<DocsStoriesProps> = ({ type = DocsStoriesType.ALL }) => ( | ||
<DocsContext.Consumer> | ||
{({ selectedKind, storyStore }) => { | ||
const componentStories = (storyStore.raw() as StoryData[]).filter( | ||
s => s.kind === selectedKind | ||
); | ||
const stories = getDocsStories(type, componentStories); | ||
if (stories.length === 0) { | ||
return null; | ||
} | ||
const expanded = type !== DocsStoriesType.PRIMARY; | ||
return ( | ||
<> | ||
{expanded && <StoriesHeading>Stories</StoriesHeading>} | ||
{stories.map(s => ( | ||
<DocsStory key={s.id} expanded={expanded} {...s} /> | ||
))} | ||
</> | ||
); | ||
}} | ||
</DocsContext.Consumer> | ||
); | ||
|
||
const getDocsPageProps = (context: DocsContextProps): DocsPageProps => { | ||
const { selectedKind, selectedStory, parameters } = context; | ||
const { | ||
hierarchyRootSeparator: rootSeparator, | ||
hierarchySeparator: groupSeparator, | ||
} = (parameters && parameters.options) || { | ||
hierarchyRootSeparator: '|', | ||
hierarchySeparator: '/', | ||
}; | ||
|
||
const { groups } = parseKind(selectedKind, { rootSeparator, groupSeparator }); | ||
const title = (groups && groups[groups.length - 1]) || selectedKind; | ||
|
||
return { | ||
title, | ||
subtitle: parameters && parameters.componentDescription, | ||
}; | ||
}; | ||
|
||
const DocsPage: React.FunctionComponent = () => ( | ||
<DocsContext.Consumer> | ||
{context => { | ||
const docsPageProps = getDocsPageProps(context); | ||
return ( | ||
<PureDocsPage {...docsPageProps}> | ||
<Description of="." /> | ||
<DocsStories type={DocsStoriesType.PRIMARY} /> | ||
<Props of="." /> | ||
<DocsStories type={DocsStoriesType.REST} /> | ||
</PureDocsPage> | ||
); | ||
}} | ||
</DocsContext.Consumer> | ||
); | ||
|
||
interface DocsPageWrapperProps { | ||
context: DocsContextProps; | ||
} | ||
|
||
const DocsPageWrapper: React.FunctionComponent<DocsPageWrapperProps> = ({ context }) => ( | ||
/* eslint-disable react/destructuring-assignment */ | ||
<DocsContainer context={{ ...context, mdxKind: context.selectedKind }} content={DocsPage} /> | ||
); | ||
|
||
export { DocsPageWrapper as DocsPage }; |
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,16 @@ | ||
import React from 'react'; | ||
|
||
type Decorator = (...args: any) => any; | ||
|
||
interface MetaProps { | ||
title: string; | ||
decorators?: [Decorator]; | ||
parameters?: any; | ||
} | ||
|
||
/** | ||
* This component is used to declare component metadata in docs | ||
* and gets transformed into a default export underneath the hood. | ||
* It doesn't actually render anything. | ||
*/ | ||
export const Meta: React.FunctionComponent<MetaProps> = props => null; |
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,48 @@ | ||
import React, { ReactNodeArray } from 'react'; | ||
import { Preview as PurePreview, PreviewProps as PurePreviewProps } from '@storybook/components'; | ||
import { toId } from '@storybook/router'; | ||
import { getSourceProps } from './Source'; | ||
import { DocsContext, DocsContextProps } from './DocsContext'; | ||
|
||
export enum SourceState { | ||
OPEN = 'open', | ||
CLOSED = 'closed', | ||
NONE = 'none', | ||
} | ||
|
||
type PreviewProps = PurePreviewProps & { | ||
withSource?: SourceState; | ||
}; | ||
|
||
const getPreviewProps = ( | ||
{ | ||
withSource = SourceState.CLOSED, | ||
children, | ||
...props | ||
}: PreviewProps & { children?: React.ReactNode }, | ||
{ mdxKind, storyStore }: DocsContextProps | ||
): PurePreviewProps => { | ||
if (withSource === SourceState.NONE && !children) { | ||
return props; | ||
} | ||
const childArray: ReactNodeArray = Array.isArray(children) ? children : [children]; | ||
const stories = childArray.filter( | ||
(c: React.ReactElement) => c.props && (c.props.id || c.props.name) | ||
) as React.ReactElement[]; | ||
const targetIds = stories.map(s => s.props.id || toId(mdxKind, s.props.name)); | ||
const sourceProps = getSourceProps({ ids: targetIds }, { storyStore }); | ||
return { | ||
...props, // pass through columns etc. | ||
withSource: sourceProps, | ||
isExpanded: withSource === SourceState.OPEN, | ||
}; | ||
}; | ||
|
||
export const Preview: React.FunctionComponent<PreviewProps> = props => ( | ||
<DocsContext.Consumer> | ||
{context => { | ||
const previewProps = getPreviewProps(props, context); | ||
return <PurePreview {...previewProps}>{props.children}</PurePreview>; | ||
}} | ||
</DocsContext.Consumer> | ||
); |
Oops, something went wrong.
d579617
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully aliased the URL https://monorepo-da3lrbxic.now.sh to the following aliases.