Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/ui-components/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@node-core/ui-components",
"version": "1.6.0",
"version": "1.6.1",
"type": "module",
"exports": {
"./*": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@reference "../../../styles/index.css";

.header {
@apply flex
items-start
gap-1;
}

.attribute {
@apply font-ibm-plex-mono
inline-flex
flex-wrap
items-center
gap-1
text-sm
font-semibold;

.longName {
@apply break-all
sm:break-keep;
}

&.return {
@apply font-open-sans
shrink-0;

svg {
@apply size-4;
}
}
}

.type {
@apply font-ibm-plex-mono
inline-flex
flex-wrap
gap-0.5
text-sm
break-all;

a {
@apply text-green-700
dark:text-green-400;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ArrowTurnDownLeftIcon } from '@heroicons/react/24/outline';
import classNames from 'classnames';

import type Signature from '#ui/Common/Signature';
import type { ComponentProps, FC } from 'react';

import styles from './index.module.css';

type SignatureHeaderProps = { isReturn?: boolean } & Omit<
ComponentProps<typeof Signature>,
'title' | 'description'
>;

const SignatureHeader: FC<SignatureHeaderProps> = ({
name,
type,
optional,
isReturn = false,
}) => (
<div className={styles.header}>
{name && (
<span
className={classNames(styles.attribute, {
[styles.return]: isReturn,
})}
>
{isReturn && <ArrowTurnDownLeftIcon />}
<span
className={classNames({
[styles.longName]: name.length > 16,
})}
>
{name}:
{optional && (
<span
role="img"
aria-label="Optional"
data-tooltip="Optional"
tabIndex={0}
>
?
</span>
)}
</span>
</span>
)}
{type && <span className={styles.type}>{type}</span>}
</div>
);

export default SignatureHeader;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@reference "../../../styles/index.css";

.item {
@apply flex
flex-col
gap-1;
}

.return {
@apply rounded-sm
bg-green-100
px-4
py-3
dark:bg-neutral-900/40;
}

.children {
@apply relative
flex
flex-col
rounded-sm
border
border-neutral-200
dark:border-neutral-900;

&:has(> .return:only-child) {
@apply border-0;
}

&:not(:has(.return:only-child)) .return {
@apply mx-4
mb-3;
}

.item:not(.return) {
@apply mx-4
py-3;
}

.item:not(:last-child, :has(+ .return)) {
@apply border-b
border-neutral-200
dark:border-neutral-900;
}
}

.description {
@apply text-sm
break-all;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import classNames from 'classnames';

import SignatureHeader from '#ui/Common/Signature/SignatureHeader';

import type Signature from '#ui/Common/Signature';
import type { ComponentProps, FC, PropsWithChildren } from 'react';

import styles from './index.module.css';

type SignatureItemProps = Omit<ComponentProps<typeof Signature>, 'title'>;

const SignatureItem: FC<PropsWithChildren<SignatureItemProps>> = ({
kind = 'default',
name,
type,
description,
optional,
children,
}) => (
<div
className={classNames(styles.item, {
[styles.return]: kind === 'return',
})}
>
<SignatureHeader
name={name}
type={type}
optional={optional}
isReturn={kind === 'return'}
/>
{description && <div className={styles.description}>{description}</div>}
{children && <div className={styles.children}>{children}</div>}
</div>
);

export default SignatureItem;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@reference "../../../styles/index.css";

.container {
@apply flex
flex-col
gap-3;
}

.title {
@apply text-base
font-semibold;
}

.root {
@apply flex
flex-col
gap-4
rounded-sm
border
border-neutral-200
px-4
py-3
dark:border-neutral-900;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useId } from 'react';

import type Signature from '#ui/Common/Signature';
import type { ComponentProps, FC, PropsWithChildren } from 'react';

import styles from './index.module.css';

type SignatureRootProps = Pick<ComponentProps<typeof Signature>, 'title'>;

const SignatureRoot: FC<PropsWithChildren<SignatureRootProps>> = ({
title,
children,
}) => {
const titleId = useId();

return (
<section className={styles.container} aria-labelledby={titleId}>
<div className={styles.title} id={titleId}>
{title}
</div>
<div className={styles.root}>{children}</div>
</section>
);
};

export default SignatureRoot;
100 changes: 100 additions & 0 deletions packages/ui-components/src/Common/Signature/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import Signature from '#ui/Common/Signature';

import type { Meta as MetaObj, StoryObj } from '@storybook/react-webpack5';

type Story = StoryObj<typeof Signature>;
type Meta = MetaObj<typeof Signature>;

export const Default: Story = {
args: {
title: 'Attributes',
children: (
<>
<Signature
name="attribute1"
type={
<>
<a href="#">&lt;Type1&gt;</a>|<a href="#">&lt;Type2&gt;</a>
</>
}
/>
<Signature
name="attribute2"
optional
type={<a href="#">&lt;Object&gt;</a>}
description="An optional attribute."
>
<Signature name="option1" type={<a href="#">&lt;Type1&gt;</a>} />
<Signature name="option2" type={<a href="#">&lt;Type2&gt;</a>} />
<Signature
name="option3"
type={<a href="#">&lt;Type3&gt;</a>}
description="One of the available options."
/>
</Signature>
<Signature
name="Returns"
type={<a href="#">&lt;Type4&gt;</a>}
description="Returns the result of the function."
kind="return"
/>
</>
),
},
};

export const WithLongAttributeNames: Story = {
args: {
title: 'Attributes',
children: (
<>
<Signature
name="thisIsAnAttributeWithAnExcessivelyLongNameToTestTextWrapping"
type={
<>
<a href="#">&lt;Type1&gt;</a>|<a href="#">&lt;Type3&gt;</a>
</>
}
/>
</>
),
},
};

export const WithLongTypeAndAttributeNames: Story = {
args: {
title: 'Attributes',
children: (
<>
<Signature
name="attribute1"
type={
<>
<a href="#">
&lt;ThisIsATypeWithAnExcessivelyLongNameToTestTextWrapping&gt;
</a>
</>
}
/>
</>
),
},
};

export const OptionalAttribute: Story = {
args: {
title: 'Attributes',
children: (
<Signature
name="optionalAttribute"
optional
type={<a href="#">&lt;Object&gt;</a>}
description="An optional attribute."
/>
),
},
};

export default {
component: Signature,
} as Meta;
41 changes: 41 additions & 0 deletions packages/ui-components/src/Common/Signature/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import SignatureItem from '#ui/Common/Signature/SignatureItem';
import SignatureRoot from '#ui/Common/Signature/SignatureRoot';

import type { FC, PropsWithChildren, ReactNode } from 'react';

export type SignatureProps = {
title?: string;
kind?: 'default' | 'return';
name?: string;
type?: ReactNode;
description?: ReactNode;
optional?: boolean;
};

const Signature: FC<PropsWithChildren<SignatureProps>> = ({
kind = 'default',
name,
type,
description,
optional,
title,
children,
}) => {
if (title) {
return <SignatureRoot title={title}>{children}</SignatureRoot>;
}

return (
<SignatureItem
kind={kind}
name={name}
type={type}
description={description}
optional={optional}
>
{children}
</SignatureItem>
);
};

export default Signature;
Loading
Loading