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