1import { css } from '@emotion/react'; 2import React from 'react'; 3 4import { InlineCode } from '~/components/base/code'; 5import { H4 } from '~/components/base/headings'; 6import { LI, UL } from '~/components/base/list'; 7import { P } from '~/components/base/paragraph'; 8import { H2, H3, H3Code } from '~/components/plugins/Headings'; 9import { 10 CommentTagData, 11 DefaultPropsDefinitionData, 12 PropData, 13 PropsDefinitionData, 14 TypeDefinitionData, 15} from '~/components/plugins/api/APIDataTypes'; 16import { 17 CommentTextBlock, 18 getCommentOrSignatureComment, 19 renderTypeOrSignatureType, 20 resolveTypeName, 21 STYLES_SECONDARY, 22} from '~/components/plugins/api/APISectionUtils'; 23 24export type APISectionPropsProps = { 25 data: PropsDefinitionData[]; 26 defaultProps?: DefaultPropsDefinitionData; 27 header?: string; 28}; 29 30const UNKNOWN_VALUE = '...'; 31 32const PROP_LIST_ELEMENT_STYLE = css` 33 padding: 0; 34`; 35 36const extractDefaultPropValue = ( 37 { comment, name }: PropData, 38 defaultProps?: DefaultPropsDefinitionData 39): string | undefined => { 40 const annotationDefault = comment?.tags?.filter((tag: CommentTagData) => tag.tag === 'default'); 41 if (annotationDefault?.length) { 42 return annotationDefault[0].text; 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 <InlineCode>{resolveTypeName(ip)}</InlineCode> 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 <UL> 89 {propsDeclarations?.map(prop => 90 prop 91 ? renderProp(prop, extractDefaultPropValue(prop, defaultValues), exposeInSidebar) 92 : null 93 )} 94 </UL> 95 {renderInheritedProps(type.types, exposeInSidebar)} 96 </div> 97 ); 98}; 99 100const renderProp = ( 101 { comment, name, type, flags, signatures }: PropData, 102 defaultValue?: string, 103 exposeInSidebar?: boolean 104) => ( 105 <LI key={`prop-entry-${name}`} customCss={exposeInSidebar ? PROP_LIST_ELEMENT_STYLE : undefined}> 106 {exposeInSidebar ? <H3>{name}</H3> : <H4>{name}</H4>} 107 <P> 108 {flags?.isOptional && <span css={STYLES_SECONDARY}>Optional • </span>} 109 <span css={STYLES_SECONDARY}>Type:</span> {renderTypeOrSignatureType(type, signatures, true)} 110 {defaultValue && defaultValue !== UNKNOWN_VALUE ? ( 111 <span> 112 <span css={STYLES_SECONDARY}> • Default:</span>{' '} 113 <InlineCode>{defaultValue}</InlineCode> 114 </span> 115 ) : null} 116 </P> 117 <CommentTextBlock comment={getCommentOrSignatureComment(comment, signatures)} /> 118 </LI> 119); 120 121const APISectionProps: React.FC<APISectionPropsProps> = ({ 122 data, 123 defaultProps, 124 header = 'Props', 125}) => 126 data?.length ? ( 127 <> 128 {header === 'Props' ? ( 129 <H2 key="props-header">{header}</H2> 130 ) : ( 131 <> 132 <H3Code key={`${header}-props-header`}> 133 <InlineCode>{header}</InlineCode> 134 </H3Code> 135 <br /> 136 </> 137 )} 138 {data.map((propsDefinition: PropsDefinitionData) => 139 renderProps(propsDefinition, defaultProps, header === 'Props') 140 )} 141 </> 142 ) : null; 143 144export default APISectionProps; 145