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