1import React from 'react';
2import ReactMarkdown from 'react-markdown';
3
4import { InlineCode } from '~/components/base/code';
5import { B, P } from '~/components/base/paragraph';
6import { H2, H3Code, H4 } from '~/components/plugins/Headings';
7import {
8  ClassDefinitionData,
9  GeneratedData,
10  PropData,
11} from '~/components/plugins/api/APIDataTypes';
12import { renderMethod } from '~/components/plugins/api/APISectionMethods';
13import { renderProp } from '~/components/plugins/api/APISectionProps';
14import {
15  CommentTextBlock,
16  getTagData,
17  mdComponents,
18  resolveTypeName,
19  STYLES_APIBOX,
20  STYLES_NESTED_SECTION_HEADER,
21  TypeDocKind,
22} from '~/components/plugins/api/APISectionUtils';
23
24export type APISectionClassesProps = {
25  data: GeneratedData[];
26};
27
28const isProp = (child: PropData) =>
29  child.kind === TypeDocKind.Property &&
30  !child.overwrites &&
31  !child.name.startsWith('_') &&
32  !child.implementationOf;
33
34const isMethod = (child: PropData) =>
35  child.kind === TypeDocKind.Method &&
36  !child.overwrites &&
37  !child.name.startsWith('_') &&
38  !child?.implementationOf;
39
40const renderClass = (clx: ClassDefinitionData, hasMultipleClasses: boolean): JSX.Element => {
41  const { name, comment, type, extendedTypes, children, implementedTypes } = clx;
42  const properties = children?.filter(isProp);
43  const methods = children
44    ?.filter(isMethod)
45    .sort((a: PropData, b: PropData) => a.name.localeCompare(b.name));
46  const returnComment = getTagData('returns', comment);
47
48  return (
49    <div key={`class-definition-${name}`} css={STYLES_APIBOX}>
50      {hasMultipleClasses ? (
51        <H3Code>
52          <InlineCode>{name}</InlineCode>
53        </H3Code>
54      ) : (
55        <H2>{name}</H2>
56      )}
57      {(extendedTypes?.length || implementedTypes?.length) && (
58        <P>
59          <B>Type: </B>
60          {type ? <InlineCode>{resolveTypeName(type)}</InlineCode> : 'Class'}
61          {extendedTypes?.length && (
62            <>
63              <span> extends </span>
64              {extendedTypes.map(extendedType => (
65                <InlineCode key={`extends-${extendedType.name}`}>
66                  {resolveTypeName(extendedType)}
67                </InlineCode>
68              ))}
69            </>
70          )}
71          {implementedTypes?.length && (
72            <>
73              <span> implements </span>
74              {implementedTypes.map(implementedType => (
75                <InlineCode key={`implements-${implementedType.name}`}>
76                  {resolveTypeName(implementedType)}
77                </InlineCode>
78              ))}
79            </>
80          )}
81        </P>
82      )}
83      <CommentTextBlock comment={comment} />
84      {returnComment && (
85        <>
86          <div css={STYLES_NESTED_SECTION_HEADER}>
87            <H4>Returns</H4>
88          </div>
89          <ReactMarkdown components={mdComponents}>{returnComment.text}</ReactMarkdown>
90        </>
91      )}
92      {properties?.length ? (
93        <>
94          {hasMultipleClasses ? (
95            <div css={STYLES_NESTED_SECTION_HEADER}>
96              <H4>{name} Properties</H4>
97            </div>
98          ) : (
99            <H2>{name} Properties</H2>
100          )}
101          <div>
102            {properties.map(property =>
103              renderProp(property, property?.defaultValue, !hasMultipleClasses)
104            )}
105          </div>
106        </>
107      ) : null}
108      {methods?.length && (
109        <>
110          {hasMultipleClasses ? (
111            <div css={STYLES_NESTED_SECTION_HEADER}>
112              <H4>{name} Methods</H4>
113            </div>
114          ) : (
115            <H2>{name} Methods</H2>
116          )}
117          {methods.map((method, index) =>
118            renderMethod(method, index, methods.length, undefined, undefined, !hasMultipleClasses)
119          )}
120        </>
121      )}
122    </div>
123  );
124};
125
126const APISectionClasses = ({ data }: APISectionClassesProps) => {
127  if (data?.length) {
128    const hasMultipleClasses = data.length > 1;
129    return (
130      <>
131        {hasMultipleClasses ? <H2>Classes</H2> : null}
132        {data.map(cls => renderClass(cls, hasMultipleClasses))}
133      </>
134    );
135  }
136  return null;
137};
138
139export default APISectionClasses;
140