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