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