Skip to content

Commit abce081

Browse files
canerakdasovflowd
authored andcommitted
feat(ui-components): add Signature and FunctionSignature components
1 parent 377f606 commit abce081

File tree

10 files changed

+565
-0
lines changed

10 files changed

+565
-0
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
@reference "../../../styles/index.css";
2+
3+
.header {
4+
@apply flex
5+
items-start
6+
gap-1;
7+
}
8+
9+
.attribute {
10+
@apply font-ibm-plex-mono
11+
inline-flex
12+
flex-wrap
13+
items-center
14+
gap-1
15+
text-sm
16+
font-semibold
17+
break-all;
18+
19+
&.return {
20+
@apply font-open-sans;
21+
22+
svg {
23+
@apply size-4;
24+
}
25+
}
26+
}
27+
28+
.type {
29+
@apply font-ibm-plex-mono
30+
inline-flex
31+
flex-wrap
32+
gap-0.5
33+
text-sm
34+
break-all;
35+
36+
a {
37+
@apply text-green-700
38+
dark:text-green-400;
39+
}
40+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { ArrowTurnDownLeftIcon } from '@heroicons/react/24/outline';
2+
import classNames from 'classnames';
3+
4+
import type Signature from '#ui/Common/Signature';
5+
import type { ComponentProps, FC } from 'react';
6+
7+
import styles from './index.module.css';
8+
9+
type SignatureHeaderProps = { isReturn?: boolean } & Omit<
10+
ComponentProps<typeof Signature>,
11+
'title' | 'description'
12+
>;
13+
14+
const SignatureHeader: FC<SignatureHeaderProps> = ({
15+
name,
16+
type,
17+
optional,
18+
isReturn = false,
19+
}) => (
20+
<div className={styles.header}>
21+
{name && (
22+
<span
23+
className={classNames(styles.attribute, {
24+
[styles.return]: isReturn,
25+
})}
26+
>
27+
{isReturn && <ArrowTurnDownLeftIcon />}
28+
<span>
29+
{name}:
30+
{optional && (
31+
<span
32+
className={styles.optional}
33+
role="img"
34+
aria-label="Optional"
35+
data-tooltip="Optional"
36+
tabIndex={0}
37+
>
38+
?
39+
</span>
40+
)}
41+
</span>
42+
</span>
43+
)}
44+
{type && <span className={styles.type}>{type}</span>}
45+
</div>
46+
);
47+
48+
export default SignatureHeader;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
@reference "../../../styles/index.css";
2+
3+
.item {
4+
@apply flex
5+
flex-col
6+
gap-1;
7+
}
8+
9+
.return {
10+
@apply rounded-sm
11+
bg-green-100
12+
px-4
13+
py-3
14+
dark:bg-neutral-900/40;
15+
}
16+
17+
.children {
18+
@apply relative
19+
flex
20+
flex-col
21+
rounded-sm
22+
border
23+
border-neutral-200
24+
dark:border-neutral-900;
25+
26+
&:has(> .return:only-child) {
27+
@apply border-0;
28+
}
29+
30+
&:not(:has(.return:only-child)) .return {
31+
@apply mx-4
32+
mb-3;
33+
}
34+
35+
.item:not(.return) {
36+
@apply mx-4
37+
py-3;
38+
}
39+
40+
.item:not(:last-child, :has(+ .return)) {
41+
@apply border-b
42+
border-neutral-200
43+
dark:border-neutral-900;
44+
}
45+
}
46+
47+
.description {
48+
@apply text-sm
49+
break-all;
50+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import classNames from 'classnames';
2+
3+
import SignatureHeader from '#ui/Common/Signature/SignatureHeader';
4+
5+
import type Signature from '#ui/Common/Signature';
6+
import type { ComponentProps, FC, PropsWithChildren } from 'react';
7+
8+
import styles from './index.module.css';
9+
10+
type SignatureItemProps = Omit<ComponentProps<typeof Signature>, 'title'>;
11+
12+
const SignatureItem: FC<PropsWithChildren<SignatureItemProps>> = ({
13+
kind = 'default',
14+
name,
15+
type,
16+
description,
17+
optional,
18+
children,
19+
}) => (
20+
<div
21+
className={classNames(styles.item, {
22+
[styles.return]: kind === 'return',
23+
})}
24+
>
25+
<SignatureHeader
26+
name={name}
27+
type={type}
28+
optional={optional}
29+
isReturn={kind === 'return'}
30+
/>
31+
{description && <div className={styles.description}>{description}</div>}
32+
{children && <div className={styles.children}>{children}</div>}
33+
</div>
34+
);
35+
36+
export default SignatureItem;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
@reference "../../../styles/index.css";
2+
3+
.container {
4+
@apply flex
5+
flex-col
6+
gap-3;
7+
}
8+
9+
.title {
10+
@apply text-base
11+
font-semibold;
12+
}
13+
14+
.root {
15+
@apply flex
16+
flex-col
17+
gap-4
18+
rounded-sm
19+
border
20+
border-neutral-200
21+
px-4
22+
py-3
23+
dark:border-neutral-900;
24+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { useId } from 'react';
2+
3+
import type Signature from '#ui/Common/Signature';
4+
import type { ComponentProps, FC, PropsWithChildren } from 'react';
5+
6+
import styles from './index.module.css';
7+
8+
type SignatureRootProps = Pick<ComponentProps<typeof Signature>, 'title'>;
9+
10+
const SignatureRoot: FC<PropsWithChildren<SignatureRootProps>> = ({
11+
title,
12+
children,
13+
}) => {
14+
const titleId = useId();
15+
16+
return (
17+
<section className={styles.container} aria-labelledby={titleId}>
18+
<h3 className={styles.title} id={titleId}>
19+
{title}
20+
</h3>
21+
<div className={styles.root}>{children}</div>
22+
</section>
23+
);
24+
};
25+
26+
export default SignatureRoot;
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import FunctionDefinition from '#ui/Common/Signature';
2+
3+
import type { Meta as MetaObj, StoryObj } from '@storybook/react-webpack5';
4+
5+
type Story = StoryObj<typeof FunctionDefinition>;
6+
type Meta = MetaObj<typeof FunctionDefinition>;
7+
8+
export const Default: Story = {
9+
args: {
10+
title: 'Attributes',
11+
children: (
12+
<>
13+
<FunctionDefinition
14+
name="attribute1"
15+
type={
16+
<>
17+
<a href="#">&lt;Type1&gt;</a>|<a href="#">&lt;Type2&gt;</a>
18+
</>
19+
}
20+
/>
21+
<FunctionDefinition
22+
name="attribute2"
23+
optional
24+
type={<a href="#">&lt;Object&gt;</a>}
25+
description="An optional attribute."
26+
>
27+
<FunctionDefinition
28+
name="option1"
29+
type={<a href="#">&lt;Type3&gt;</a>}
30+
/>
31+
<FunctionDefinition
32+
name="option2"
33+
type={<a href="#">&lt;Type3&gt;</a>}
34+
/>
35+
<FunctionDefinition
36+
name="option3"
37+
type={<a href="#">&lt;Type3&gt;</a>}
38+
description="One of the available options."
39+
/>
40+
</FunctionDefinition>
41+
<FunctionDefinition
42+
name="Returns"
43+
type={<a href="#">&lt;Type4&gt;</a>}
44+
description="Returns the result of the function."
45+
kind="return"
46+
/>
47+
</>
48+
),
49+
},
50+
};
51+
52+
export const WithLongAttributeNames: Story = {
53+
args: {
54+
title: 'Attributes',
55+
children: (
56+
<>
57+
<FunctionDefinition
58+
name="thisIsAnAttributeWithAnExcessivelyLongNameToTestTextWrapping"
59+
type={
60+
<>
61+
<a href="#">&lt;Type1&gt;</a>|<a href="#">&lt;Type2&gt;</a>
62+
</>
63+
}
64+
/>
65+
</>
66+
),
67+
},
68+
};
69+
70+
export const WithLongTypeAndAttributeNames: Story = {
71+
args: {
72+
title: 'Attributes',
73+
children: (
74+
<>
75+
<FunctionDefinition
76+
name="attribute1"
77+
type={
78+
<>
79+
<a href="#">
80+
&lt;ThisIsATypeWithAnExcessivelyLongNameToTestTextWrapping&gt;
81+
</a>
82+
</>
83+
}
84+
/>
85+
</>
86+
),
87+
},
88+
};
89+
90+
export const OptionalAttribute: Story = {
91+
args: {
92+
title: 'Attributes',
93+
children: (
94+
<FunctionDefinition
95+
name="optionalAttribute"
96+
optional
97+
type={<a href="#">&lt;Object&gt;</a>}
98+
description="An optional attribute."
99+
/>
100+
),
101+
},
102+
};
103+
104+
export default {
105+
component: FunctionDefinition,
106+
} as Meta;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import SignatureItem from '#ui/Common/Signature/SignatureItem';
2+
import SignatureRoot from '#ui/Common/Signature/SignatureRoot';
3+
4+
import type { FC, PropsWithChildren, ReactNode } from 'react';
5+
6+
export type SignatureProps = {
7+
title?: string;
8+
kind?: 'default' | 'return';
9+
name?: string;
10+
type?: ReactNode;
11+
description?: ReactNode;
12+
optional?: boolean;
13+
};
14+
15+
const Signature: FC<PropsWithChildren<SignatureProps>> = ({
16+
kind = 'default',
17+
name,
18+
type,
19+
description,
20+
optional,
21+
title,
22+
children,
23+
}) => {
24+
if (title) {
25+
return <SignatureRoot title={title}>{children}</SignatureRoot>;
26+
}
27+
28+
return (
29+
<SignatureItem
30+
kind={kind}
31+
name={name}
32+
type={type}
33+
description={description}
34+
optional={optional}
35+
>
36+
{children}
37+
</SignatureItem>
38+
);
39+
};
40+
41+
export default Signature;

0 commit comments

Comments
 (0)