1import { css } from '@emotion/react'; 2import React from 'react'; 3 4import { InlineCode } from '~/components/base/code'; 5import { H4 } from '~/components/base/headings'; 6import { LI, UL } from '~/components/base/list'; 7import { P } from '~/components/base/paragraph'; 8import { H2, H3, H3Code } from '~/components/plugins/Headings'; 9import { 10 CommentTagData, 11 DefaultPropsDefinitionData, 12 PropData, 13 PropsDefinitionData, 14 TypeDefinitionData, 15} from '~/components/plugins/api/APIDataTypes'; 16import { 17 CommentTextBlock, 18 resolveTypeName, 19 STYLES_SECONDARY, 20} from '~/components/plugins/api/APISectionUtils'; 21 22export type APISectionPropsProps = { 23 data: PropsDefinitionData[]; 24 defaultProps?: DefaultPropsDefinitionData; 25 header?: string; 26}; 27 28const UNKNOWN_VALUE = '...'; 29 30const PROP_LIST_ELEMENT_STYLE = css` 31 padding: 0; 32`; 33 34const extractDefaultPropValue = ( 35 { comment, name }: PropData, 36 defaultProps?: DefaultPropsDefinitionData 37): string | undefined => { 38 const annotationDefault = comment?.tags?.filter((tag: CommentTagData) => tag.tag === 'default'); 39 if (annotationDefault?.length) { 40 return annotationDefault[0].text; 41 } 42 return defaultProps?.type?.declaration?.children?.filter( 43 (defaultProp: PropData) => defaultProp.name === name 44 )[0]?.defaultValue; 45}; 46 47const renderInheritedProp = (ip: TypeDefinitionData) => { 48 return ( 49 <LI key={`inherited-prop-${ip.name}-${ip.type}`}> 50 {ip?.typeArguments ? ( 51 <InlineCode>{resolveTypeName(ip)}</InlineCode> 52 ) : ( 53 <InlineCode>{ip.name}</InlineCode> 54 )} 55 </LI> 56 ); 57}; 58 59const renderInheritedProps = ( 60 data: TypeDefinitionData[] | undefined, 61 exposeInSidebar?: boolean 62): JSX.Element | undefined => { 63 const inheritedProps = data?.filter((ip: TypeDefinitionData) => ip.type === 'reference') ?? []; 64 if (inheritedProps.length) { 65 return ( 66 <> 67 {exposeInSidebar ? <H3>Inherited Props</H3> : <H4>Inherited Props</H4>} 68 <UL>{inheritedProps.map(renderInheritedProp)}</UL> 69 </> 70 ); 71 } 72 return undefined; 73}; 74 75const renderProps = ( 76 { name, type }: PropsDefinitionData, 77 defaultValues?: DefaultPropsDefinitionData, 78 exposeInSidebar?: boolean 79): JSX.Element => { 80 const baseTypes = type.types 81 ? type.types?.filter((t: TypeDefinitionData) => t.declaration) 82 : [type]; 83 const propsDeclarations = baseTypes 84 .map(def => def?.declaration?.children) 85 .flat() 86 .filter((dec, i, arr) => arr.findIndex(t => t?.name === dec?.name) === i); 87 88 return ( 89 <div key={`props-definition-${name}`}> 90 <UL> 91 {propsDeclarations?.map(prop => 92 prop 93 ? renderProp(prop, extractDefaultPropValue(prop, defaultValues), exposeInSidebar) 94 : null 95 )} 96 </UL> 97 {renderInheritedProps(type.types, exposeInSidebar)} 98 </div> 99 ); 100}; 101 102const renderProp = ( 103 { comment, name, type, flags }: PropData, 104 defaultValue?: string, 105 exposeInSidebar?: boolean 106) => ( 107 <LI key={`prop-entry-${name}`} customCss={exposeInSidebar ? PROP_LIST_ELEMENT_STYLE : undefined}> 108 {exposeInSidebar ? <H3>{name}</H3> : <H4>{name}</H4>} 109 <P> 110 {flags?.isOptional && <span css={STYLES_SECONDARY}>Optional • </span>} 111 <span css={STYLES_SECONDARY}>Type:</span> <InlineCode>{resolveTypeName(type)}</InlineCode> 112 {defaultValue && defaultValue !== UNKNOWN_VALUE ? ( 113 <span> 114 <span css={STYLES_SECONDARY}> • Default:</span>{' '} 115 <InlineCode>{defaultValue}</InlineCode> 116 </span> 117 ) : null} 118 </P> 119 <CommentTextBlock comment={comment} /> 120 </LI> 121); 122 123const APISectionProps: React.FC<APISectionPropsProps> = ({ 124 data, 125 defaultProps, 126 header = 'Props', 127}) => 128 data?.length ? ( 129 <> 130 {header === 'Props' ? ( 131 <H2 key="props-header">{header}</H2> 132 ) : ( 133 <> 134 <H3Code key={`${header}-props-header`}> 135 <InlineCode>{header}</InlineCode> 136 </H3Code> 137 <br /> 138 </> 139 )} 140 {data.map((propsDefinition: PropsDefinitionData) => 141 renderProps(propsDefinition, defaultProps, header === 'Props') 142 )} 143 </> 144 ) : null; 145 146export default APISectionProps; 147