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, H4 } from '~/components/plugins/Headings';
7import {
8  CommentTagData,
9  DefaultPropsDefinitionData,
10  PropData,
11  PropsDefinitionData,
12  TypeDeclarationData,
13  TypePropertyData,
14} from '~/components/plugins/api/APIDataTypes';
15import { CommentTextBlock, resolveTypeName } from '~/components/plugins/api/APISectionUtils';
16
17export type APISectionPropsProps = {
18  data: PropsDefinitionData[];
19  defaultProps: DefaultPropsDefinitionData;
20};
21
22const UNKNOWN_VALUE = '...';
23
24const extractDefaultPropValue = (
25  { comment, name }: PropData,
26  defaultProps: DefaultPropsDefinitionData
27): string | undefined => {
28  const annotationDefault = comment?.tags?.filter((tag: CommentTagData) => tag.tag === 'default');
29  if (annotationDefault?.length) {
30    return annotationDefault[0].text;
31  }
32  return defaultProps?.type?.declaration?.children?.filter(
33    (defaultProp: TypePropertyData) => defaultProp.name === name
34  )[0]?.defaultValue;
35};
36
37const renderInheritedProp = (ip: TypeDeclarationData) => {
38  const component = ip?.typeArguments ? ip.typeArguments[0]?.queryType?.name : null;
39  return component ? (
40    <LI key={`inherited-prop-${component}`}>
41      <InlineCode>{component}</InlineCode>
42    </LI>
43  ) : null;
44};
45
46const renderInheritedProps = (data: TypeDeclarationData[]): JSX.Element | undefined => {
47  const inheritedProps = data.filter((ip: TypeDeclarationData) => ip.type === 'reference');
48  if (inheritedProps.length) {
49    return (
50      <div>
51        <H4>Inherited Props</H4>
52        <UL>{inheritedProps.map(renderInheritedProp)}</UL>
53      </div>
54    );
55  }
56  return undefined;
57};
58
59const renderProps = (
60  { name, type }: PropsDefinitionData,
61  defaultValues: DefaultPropsDefinitionData
62): JSX.Element => {
63  const propsDeclarations = type.types.filter((e: TypeDeclarationData) => e.declaration);
64  return (
65    <div key={`props-definition-${name}`}>
66      <UL>
67        {propsDeclarations?.map((def: TypeDeclarationData) =>
68          def.declaration?.children.map((prop: PropData) =>
69            renderProp(prop, extractDefaultPropValue(prop, defaultValues))
70          )
71        )}
72      </UL>
73      {renderInheritedProps(type.types)}
74    </div>
75  );
76};
77
78const renderProp = ({ comment, name, type }: PropData, defaultValue?: string) => (
79  <LI key={`prop-entry-${name}`}>
80    <H4>{name}</H4>
81    <P>
82      Type: <InlineCode>{resolveTypeName(type)}</InlineCode>
83      {defaultValue && defaultValue !== UNKNOWN_VALUE ? (
84        <span>
85          &emsp;
86          {'Default: '}
87          <InlineCode>{defaultValue}</InlineCode>
88        </span>
89      ) : null}
90    </P>
91    <CommentTextBlock comment={comment} />
92  </LI>
93);
94
95const APISectionProps: React.FC<APISectionPropsProps> = ({ data, defaultProps }) =>
96  data?.length ? (
97    <>
98      <H2 key="props-header">Props</H2>
99      {data.map((propsDefinition: PropsDefinitionData) =>
100        renderProps(propsDefinition, defaultProps)
101      )}
102    </>
103  ) : null;
104
105export default APISectionProps;
106