From 80451b1bb9990158c7c4aa01f109e97924880b7f Mon Sep 17 00:00:00 2001 From: Pedro Nauck Date: Tue, 19 Feb 2019 13:06:28 -0300 Subject: [PATCH] feat: new Props component --- README.md | 4 +- .../src/components/ui/Props.tsx | 93 +++++++++ .../src/components/ui/index.tsx | 1 + core/docz-theme-default/src/index.tsx | 1 + core/docz/src/components/Props.tsx | 109 ++++++++++ core/docz/src/components/PropsTable.tsx | 190 ------------------ core/docz/src/index.ts | 2 +- core/docz/src/utils/humanize-prop.ts | 2 +- examples/basic/src/components/Alert.jsx | 1 - examples/basic/src/components/Alert.mdx | 4 +- examples/basic/src/components/Button.jsx | 5 +- examples/basic/src/components/Button.mdx | 4 +- examples/flow/src/components/Alert.mdx | 4 +- examples/flow/src/components/Button.mdx | 4 +- examples/gatsby/src/components/Alert.mdx | 4 +- examples/gatsby/src/components/Button.mdx | 4 +- .../react-native/src/components/Alert.mdx | 4 +- .../react-native/src/components/Button.mdx | 4 +- .../src/components/Alert.mdx | 4 +- .../src/components/Button.mdx | 4 +- examples/typescript/src/components/Alert.mdx | 4 +- examples/typescript/src/components/Button.mdx | 4 +- 22 files changed, 236 insertions(+), 220 deletions(-) create mode 100644 core/docz-theme-default/src/components/ui/Props.tsx create mode 100644 core/docz/src/components/Props.tsx delete mode 100644 core/docz/src/components/PropsTable.tsx diff --git a/README.md b/README.md index d2dab90f5..62eab81eb 100644 --- a/README.md +++ b/README.md @@ -128,12 +128,12 @@ Then create some `.mdx` anywhere inside your project: name: Button --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import Button from './' # Button - + ## Basic usage diff --git a/core/docz-theme-default/src/components/ui/Props.tsx b/core/docz-theme-default/src/components/ui/Props.tsx new file mode 100644 index 000000000..180a82466 --- /dev/null +++ b/core/docz-theme-default/src/components/ui/Props.tsx @@ -0,0 +1,93 @@ +import * as React from 'react' +import { useMemo } from 'react' +import { PropsComponentProps, useComponents } from 'docz' +import styled from 'styled-components' + +import { get } from '@utils/theme' + +const Wrapper = styled.div` + display: flex; + flex-direction: column; + + & ~ & { + margin-top: 20px; + } +` + +const Title = styled.div` + display: flex; + border-bottom: 1px solid ${get('colors.sidebarBg')}; +` + +const PropName = styled.span` + background: ${get('colors.sidebarBg')}; + color: ${get('colors.sidebarText')}; + padding: 5px 10px; + border-radius: 4px 4px 0 0; + font-size: 14px; + + & ~ & { + margin-left: 5px; + } +` + +const PropType = styled(PropName)` + color: ${get('colors.blockquoteColor')}; +` + +const PropDefaultValue = styled(PropType)` + background: transparent; + padding-left: 0; + padding-right: 0; +` + +const PropRequired = styled(PropType)` + flex: 1; + text-align: right; + background: transparent; + color: ${get('colors.blockquoteColor')}; + opacity: 0.5; +` + +export const Props: React.SFC = ({ + props, + getPropType, +}) => { + const entries = Object.entries(props) + const components = useComponents() + const Paragraph = useMemo( + () => styled(components.P || 'p')` + font-size: 14px; + color: ${get('colors.sidebarTex')}; + `, + [] + ) + + return ( + + {entries.map(([key, prop]) => ( + + + <PropName>{key}</PropName> + <PropType>{getPropType(prop)}</PropType> + {prop.defaultValue && ( + <PropDefaultValue> + {prop.defaultValue.value === "''" ? ( + <em>= [Empty String]</em> + ) : ( + <em>= {prop.defaultValue.value.replace(/\'/g, '"')}</em> + )} + </PropDefaultValue> + )} + {prop.required && ( + <PropRequired> + <em>required</em> + </PropRequired> + )} + + {prop.description && {prop.description}} + + ))} + + ) +} diff --git a/core/docz-theme-default/src/components/ui/index.tsx b/core/docz-theme-default/src/components/ui/index.tsx index d70b26c9b..4412bdc5d 100644 --- a/core/docz-theme-default/src/components/ui/index.tsx +++ b/core/docz-theme-default/src/components/ui/index.tsx @@ -15,5 +15,6 @@ export { OrderedList } from './OrderedList' export { Page } from './Page' export { Paragraph } from './Paragraph' export { Pre } from './Pre' +export { Props } from './Props' export { Table } from './Table' export { UnorderedList } from './UnorderedList' diff --git a/core/docz-theme-default/src/index.tsx b/core/docz-theme-default/src/index.tsx index 384d004ea..0c40d5be3 100644 --- a/core/docz-theme-default/src/index.tsx +++ b/core/docz-theme-default/src/index.tsx @@ -27,6 +27,7 @@ export const componentsMap = { page: components.Page, playground: components.AsyncPlayground, pre: components.Pre, + props: components.Props, table: components.Table, ul: components.UnorderedList, } diff --git a/core/docz/src/components/Props.tsx b/core/docz/src/components/Props.tsx new file mode 100644 index 000000000..40fb78788 --- /dev/null +++ b/core/docz/src/components/Props.tsx @@ -0,0 +1,109 @@ +import * as React from 'react' +import { SFC, ComponentType } from 'react' +import { last, get } from 'lodash/fp' +import capitalize from 'capitalize' + +import { doczState } from '../state' +import { useComponents } from '../hooks' +import { humanize } from '../utils/humanize-prop' + +export interface EnumValue { + value: string + computed: boolean +} + +export interface FlowTypeElement { + name: string + value: string +} + +export interface FlowTypeArgs { + name: string + type: { + name: string + } +} + +export interface PropType { + name: string + value?: any + raw?: any + computed?: boolean +} + +export interface FlowType extends PropType { + elements: FlowTypeElement[] + name: string + raw: string + type?: string + computed?: boolean + signature?: { + arguments: FlowTypeArgs[] + return: { + name: string + } + } +} + +export interface Prop { + required: boolean + description?: string + type: PropType + defaultValue?: { + value: string + computed: boolean + } + flowType?: FlowType +} + +export type ComponentWithDocGenInfo = ComponentType & { + __docgenInfo: { + description?: string + props?: Record + } +} + +export interface PropsProps { + of: ComponentWithDocGenInfo +} + +export const getPropType = (prop: Prop) => { + const propName = prop.flowType ? prop.flowType.name : prop.type.name + const isEnum = propName.startsWith('"') || propName === 'enum' + const name = capitalize(isEnum ? 'enum' : propName) + const value = prop.type && prop.type.value + + if (!name) return null + + if ( + (isEnum && typeof value === 'string') || + (!prop.flowType && !isEnum && !value) || + (prop.flowType && !prop.flowType.elements) + ) { + return name + } + + return prop.flowType ? humanize(prop.flowType) : humanize(prop.type) +} + +export interface PropsComponentProps { + props: Record + getPropType(prop: Prop): string +} + +export const Props: SFC = ({ of: component }) => { + const components = useComponents() + const { props: stateProps } = React.useContext(doczState.context) + const filename = get('__filemeta.filename', component) + const found = + stateProps && + stateProps.length > 0 && + stateProps.find(item => item.key === filename) + + const definition = last(found ? found.value : []) + const props = get('props', definition) + + if (!props) return null + if (!components.props) return null + return +} diff --git a/core/docz/src/components/PropsTable.tsx b/core/docz/src/components/PropsTable.tsx deleted file mode 100644 index 16159338b..000000000 --- a/core/docz/src/components/PropsTable.tsx +++ /dev/null @@ -1,190 +0,0 @@ -import * as React from 'react' -import { CSSProperties, Fragment, SFC, ComponentType } from 'react' -import { last, get } from 'lodash/fp' -import capitalize from 'capitalize' - -import { doczState } from '../state' -import { useComponents } from '../hooks' -import { humanize } from '../utils/humanize-prop' - -export interface StylesMap { - [s: string]: CSSProperties -} - -const styles: StylesMap = { - thead: { - textAlign: 'left', - }, -} - -export interface EnumValue { - value: string - computed: boolean -} - -export interface FlowTypeElement { - name: string - value: string -} - -export interface FlowTypeArgs { - name: string - type: { - name: string - } -} - -export interface PropType { - name: string - value?: any - raw?: any - computed?: boolean -} - -export interface FlowType extends PropType { - elements: FlowTypeElement[] - name: string - raw: string - type?: string - computed?: boolean - signature?: { - arguments: FlowTypeArgs[] - return: { - name: string - } - } -} - -export interface Prop { - required: boolean - description?: string - type: PropType - defaultValue?: { - value: string - computed: boolean - } - flowType?: FlowType -} - -export type ComponentWithDocGenInfo = ComponentType & { - __docgenInfo: { - description?: string - props?: Record - } -} - -export interface PropsTable { - of: ComponentWithDocGenInfo - components: { - [key: string]: ComponentType - } -} - -export type TooltipComponent = React.ComponentType<{ - text: React.ReactNode - children: React.ReactNode -}> - -export const getPropType = (prop: Prop, Tooltip?: TooltipComponent) => { - const propName = prop.flowType ? prop.flowType.name : prop.type.name - const isEnum = propName.startsWith('"') || propName === 'enum' - const name = capitalize(isEnum ? 'enum' : propName) - const value = prop.type && prop.type.value - - if (!name) return null - - if ( - !Tooltip || - (isEnum && typeof value === 'string') || - (!prop.flowType && !isEnum && !value) || - (prop.flowType && !prop.flowType.elements) - ) { - return name - } - - return prop.flowType ? ( - {name} - ) : ( - {name} - ) -} - -export const PropsTable: SFC = ({ of: component }) => { - const components = useComponents() - const { props: stateProps } = React.useContext(doczState.context) - const filename = get('__filemeta.filename', component) - const found = - stateProps && - stateProps.length > 0 && - stateProps.find(item => item.key === filename) - - const definition: any = last(found ? found.value : []) - const props = get('props', definition) - - if (!props) return null - - const hasDescription = Object.keys(props).some((name: string) => { - const description = get(`${name}.description`, props) - return Boolean(description) && Boolean(get('length', description)) - }) - - const Table = components.table || 'table' - const Thead = components.thead || 'thead' - const Tr = components.tr || 'tr' - const Th = components.th || 'th' - const Tbody = components.tbody || 'tbody' - const Td = components.td || 'td' - const Tooltip = components.tooltip - - return ( - - - - - - - - - {hasDescription && ( - - )} - - - - {props && - Object.keys(props).map((name: string) => { - const prop = props[name] - - if (!prop.flowType && !prop.type) return null - return ( - - - - - {!prop.defaultValue ? ( - - ) : ( - - )} - {hasDescription && ( - - )} - - ) - })} - -
PropertyTypeRequiredDefault - Description -
{name}{getPropType(prop, Tooltip)}{String(prop.required)} - - - - {prop.defaultValue.value === "''" ? ( - [Empty String] - ) : ( - prop.defaultValue && - prop.defaultValue.value.replace(/\'/g, '') - )} - {prop.description && prop.description}
-
- ) -} diff --git a/core/docz/src/index.ts b/core/docz/src/index.ts index dc46b706f..f68614077 100644 --- a/core/docz/src/index.ts +++ b/core/docz/src/index.ts @@ -1,7 +1,7 @@ export { AsyncRoute, loadRoute } from './components/AsyncRoute' export { Link, LinkProps } from './components/Link' export { Playground } from './components/Playground' -export { PropsTable } from './components/PropsTable' +export { Props, PropsComponentProps } from './components/Props' export { Routes } from './components/Routes' export * from './hooks' diff --git a/core/docz/src/utils/humanize-prop.ts b/core/docz/src/utils/humanize-prop.ts index ef624927a..124113218 100644 --- a/core/docz/src/utils/humanize-prop.ts +++ b/core/docz/src/utils/humanize-prop.ts @@ -1,6 +1,6 @@ import capitalize from 'capitalize' -import { PropType, FlowType } from '../components/PropsTable' +import { PropType, FlowType } from '../components/Props' const RE_OBJECTOF = /(?:React\.)?(?:PropTypes\.)?objectOf\((?:React\.)?(?:PropTypes\.)?(\w+)\)/ diff --git a/examples/basic/src/components/Alert.jsx b/examples/basic/src/components/Alert.jsx index 51797cf64..05a428add 100644 --- a/examples/basic/src/components/Alert.jsx +++ b/examples/basic/src/components/Alert.jsx @@ -20,7 +20,6 @@ const AlertStyled = styled('div')` export const Alert = props => Alert.propTypes = { - /** `info`, `positive`, `negative`, or `warning` */ kind: t.oneOf(['info', 'positive', 'negative', 'warning']), } diff --git a/examples/basic/src/components/Alert.mdx b/examples/basic/src/components/Alert.mdx index 03a0ec9ef..8ec16abac 100644 --- a/examples/basic/src/components/Alert.mdx +++ b/examples/basic/src/components/Alert.mdx @@ -3,14 +3,14 @@ name: Alert menu: Components --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import { Alert } from './Alert' # Alert ## Properties - + ## Basic usage diff --git a/examples/basic/src/components/Button.jsx b/examples/basic/src/components/Button.jsx index bfc18edbd..6d31d8e57 100644 --- a/examples/basic/src/components/Button.jsx +++ b/examples/basic/src/components/Button.jsx @@ -63,9 +63,12 @@ export const Button = ({ children, ...props }) => ( ) Button.propTypes = { + /** + * This is a pretty fucking good description for this prop + */ scales: t.oneOf(['small', 'normal', 'big']), kind: t.oneOf(['primary', 'secondary', 'cancel', 'dark', 'gray']), - outline: t.bool, + outline: t.bool.isRequired, } Button.defaultProps = { diff --git a/examples/basic/src/components/Button.mdx b/examples/basic/src/components/Button.mdx index ccb5530c0..8fc031a68 100644 --- a/examples/basic/src/components/Button.mdx +++ b/examples/basic/src/components/Button.mdx @@ -3,7 +3,7 @@ name: Button menu: Components --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import { Button } from './Button' # Button @@ -19,7 +19,7 @@ Buttons make common actions more obvious and help users more easily perform them ## Properties - + ## Basic usage diff --git a/examples/flow/src/components/Alert.mdx b/examples/flow/src/components/Alert.mdx index 03a0ec9ef..8ec16abac 100644 --- a/examples/flow/src/components/Alert.mdx +++ b/examples/flow/src/components/Alert.mdx @@ -3,14 +3,14 @@ name: Alert menu: Components --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import { Alert } from './Alert' # Alert ## Properties - + ## Basic usage diff --git a/examples/flow/src/components/Button.mdx b/examples/flow/src/components/Button.mdx index 429f89c9a..e3f79a756 100644 --- a/examples/flow/src/components/Button.mdx +++ b/examples/flow/src/components/Button.mdx @@ -3,7 +3,7 @@ name: Button menu: Components --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import { Button } from './Button' # Button @@ -19,7 +19,7 @@ Buttons make common actions more obvious and help users more easily perform them ## Properties - + ## Basic usage diff --git a/examples/gatsby/src/components/Alert.mdx b/examples/gatsby/src/components/Alert.mdx index f489c8f4d..c0eab1417 100644 --- a/examples/gatsby/src/components/Alert.mdx +++ b/examples/gatsby/src/components/Alert.mdx @@ -3,14 +3,14 @@ name: Alert menu: Components --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import { Alert } from './Alert' # Alert ## Properties - + ## Basic usage diff --git a/examples/gatsby/src/components/Button.mdx b/examples/gatsby/src/components/Button.mdx index ccb5530c0..8fc031a68 100644 --- a/examples/gatsby/src/components/Button.mdx +++ b/examples/gatsby/src/components/Button.mdx @@ -3,7 +3,7 @@ name: Button menu: Components --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import { Button } from './Button' # Button @@ -19,7 +19,7 @@ Buttons make common actions more obvious and help users more easily perform them ## Properties - + ## Basic usage diff --git a/examples/react-native/src/components/Alert.mdx b/examples/react-native/src/components/Alert.mdx index 1be09f8c4..15dfd8cba 100644 --- a/examples/react-native/src/components/Alert.mdx +++ b/examples/react-native/src/components/Alert.mdx @@ -3,14 +3,14 @@ name: Alert menu: Components --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import { Alert, Text } from './Alert' # Alert ## Properties - + ## Basic usage diff --git a/examples/react-native/src/components/Button.mdx b/examples/react-native/src/components/Button.mdx index 9c190ab6f..2d4274f2a 100644 --- a/examples/react-native/src/components/Button.mdx +++ b/examples/react-native/src/components/Button.mdx @@ -3,7 +3,7 @@ name: Button menu: Components --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import { Button } from './Button' # Button @@ -19,7 +19,7 @@ Buttons make common actions more obvious and help users more easily perform them ## Properties - + ## Basic usage diff --git a/examples/styled-components/src/components/Alert.mdx b/examples/styled-components/src/components/Alert.mdx index 03a0ec9ef..8ec16abac 100644 --- a/examples/styled-components/src/components/Alert.mdx +++ b/examples/styled-components/src/components/Alert.mdx @@ -3,14 +3,14 @@ name: Alert menu: Components --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import { Alert } from './Alert' # Alert ## Properties - + ## Basic usage diff --git a/examples/styled-components/src/components/Button.mdx b/examples/styled-components/src/components/Button.mdx index ccb5530c0..8fc031a68 100644 --- a/examples/styled-components/src/components/Button.mdx +++ b/examples/styled-components/src/components/Button.mdx @@ -3,7 +3,7 @@ name: Button menu: Components --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import { Button } from './Button' # Button @@ -19,7 +19,7 @@ Buttons make common actions more obvious and help users more easily perform them ## Properties - + ## Basic usage diff --git a/examples/typescript/src/components/Alert.mdx b/examples/typescript/src/components/Alert.mdx index 03a0ec9ef..8ec16abac 100644 --- a/examples/typescript/src/components/Alert.mdx +++ b/examples/typescript/src/components/Alert.mdx @@ -3,14 +3,14 @@ name: Alert menu: Components --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import { Alert } from './Alert' # Alert ## Properties - + ## Basic usage diff --git a/examples/typescript/src/components/Button.mdx b/examples/typescript/src/components/Button.mdx index ccb5530c0..8fc031a68 100644 --- a/examples/typescript/src/components/Button.mdx +++ b/examples/typescript/src/components/Button.mdx @@ -3,7 +3,7 @@ name: Button menu: Components --- -import { Playground, PropsTable } from 'docz' +import { Playground, Props } from 'docz' import { Button } from './Button' # Button @@ -19,7 +19,7 @@ Buttons make common actions more obvious and help users more easily perform them ## Properties - + ## Basic usage