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