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