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 DefaultPropsDefinitionData, 11 PropData, 12 PropsDefinitionData, 13 TypeDefinitionData, 14} from '~/components/plugins/api/APIDataTypes'; 15import { 16 CommentTextBlock, 17 getCommentOrSignatureComment, 18 getTagData, 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 = getTagData('default', comment); 41 if (annotationDefault) { 42 return annotationDefault.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 = ({ data, defaultProps, header = 'Props' }: APISectionPropsProps) => 122 data?.length ? ( 123 <> 124 {header === 'Props' ? ( 125 <H2 key="props-header">{header}</H2> 126 ) : ( 127 <> 128 <H3Code key={`${header}-props-header`}> 129 <InlineCode>{header}</InlineCode> 130 </H3Code> 131 <br /> 132 </> 133 )} 134 {data.map((propsDefinition: PropsDefinitionData) => 135 renderProps(propsDefinition, defaultProps, header === 'Props') 136 )} 137 </> 138 ) : null; 139 140export default APISectionProps; 141