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