diff --git a/packages/ui-components/package.json b/packages/ui-components/package.json index 0844f43a9d062..3ba8e119f0aa5 100644 --- a/packages/ui-components/package.json +++ b/packages/ui-components/package.json @@ -1,6 +1,6 @@ { "name": "@node-core/ui-components", - "version": "1.6.0", + "version": "1.6.1", "type": "module", "exports": { "./*": { diff --git a/packages/ui-components/src/Common/Signature/SignatureHeader/index.module.css b/packages/ui-components/src/Common/Signature/SignatureHeader/index.module.css new file mode 100644 index 0000000000000..da2da6867d349 --- /dev/null +++ b/packages/ui-components/src/Common/Signature/SignatureHeader/index.module.css @@ -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; + } +} diff --git a/packages/ui-components/src/Common/Signature/SignatureHeader/index.tsx b/packages/ui-components/src/Common/Signature/SignatureHeader/index.tsx new file mode 100644 index 0000000000000..ee8040b13df0c --- /dev/null +++ b/packages/ui-components/src/Common/Signature/SignatureHeader/index.tsx @@ -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, + 'title' | 'description' +>; + +const SignatureHeader: FC = ({ + name, + type, + optional, + isReturn = false, +}) => ( +
+ {name && ( + + {isReturn && } + 16, + })} + > + {name}: + {optional && ( + + ? + + )} + + + )} + {type && {type}} +
+); + +export default SignatureHeader; diff --git a/packages/ui-components/src/Common/Signature/SignatureItem/index.module.css b/packages/ui-components/src/Common/Signature/SignatureItem/index.module.css new file mode 100644 index 0000000000000..d1554950a9370 --- /dev/null +++ b/packages/ui-components/src/Common/Signature/SignatureItem/index.module.css @@ -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; +} diff --git a/packages/ui-components/src/Common/Signature/SignatureItem/index.tsx b/packages/ui-components/src/Common/Signature/SignatureItem/index.tsx new file mode 100644 index 0000000000000..df079276d70dd --- /dev/null +++ b/packages/ui-components/src/Common/Signature/SignatureItem/index.tsx @@ -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, 'title'>; + +const SignatureItem: FC> = ({ + kind = 'default', + name, + type, + description, + optional, + children, +}) => ( +
+ + {description &&
{description}
} + {children &&
{children}
} +
+); + +export default SignatureItem; diff --git a/packages/ui-components/src/Common/Signature/SignatureRoot/index.module.css b/packages/ui-components/src/Common/Signature/SignatureRoot/index.module.css new file mode 100644 index 0000000000000..15d730563dc28 --- /dev/null +++ b/packages/ui-components/src/Common/Signature/SignatureRoot/index.module.css @@ -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; +} diff --git a/packages/ui-components/src/Common/Signature/SignatureRoot/index.tsx b/packages/ui-components/src/Common/Signature/SignatureRoot/index.tsx new file mode 100644 index 0000000000000..79e3f145b0d84 --- /dev/null +++ b/packages/ui-components/src/Common/Signature/SignatureRoot/index.tsx @@ -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, 'title'>; + +const SignatureRoot: FC> = ({ + title, + children, +}) => { + const titleId = useId(); + + return ( +
+
+ {title} +
+
{children}
+
+ ); +}; + +export default SignatureRoot; diff --git a/packages/ui-components/src/Common/Signature/index.stories.tsx b/packages/ui-components/src/Common/Signature/index.stories.tsx new file mode 100644 index 0000000000000..686a11779b58b --- /dev/null +++ b/packages/ui-components/src/Common/Signature/index.stories.tsx @@ -0,0 +1,100 @@ +import Signature from '#ui/Common/Signature'; + +import type { Meta as MetaObj, StoryObj } from '@storybook/react-webpack5'; + +type Story = StoryObj; +type Meta = MetaObj; + +export const Default: Story = { + args: { + title: 'Attributes', + children: ( + <> + + <Type1>|<Type2> + + } + /> + <Object>} + description="An optional attribute." + > + <Type1>} /> + <Type2>} /> + <Type3>} + description="One of the available options." + /> + + <Type4>} + description="Returns the result of the function." + kind="return" + /> + + ), + }, +}; + +export const WithLongAttributeNames: Story = { + args: { + title: 'Attributes', + children: ( + <> + + <Type1>|<Type3> + + } + /> + + ), + }, +}; + +export const WithLongTypeAndAttributeNames: Story = { + args: { + title: 'Attributes', + children: ( + <> + + + <ThisIsATypeWithAnExcessivelyLongNameToTestTextWrapping> + + + } + /> + + ), + }, +}; + +export const OptionalAttribute: Story = { + args: { + title: 'Attributes', + children: ( + <Object>} + description="An optional attribute." + /> + ), + }, +}; + +export default { + component: Signature, +} as Meta; diff --git a/packages/ui-components/src/Common/Signature/index.tsx b/packages/ui-components/src/Common/Signature/index.tsx new file mode 100644 index 0000000000000..e24ef4fca18cc --- /dev/null +++ b/packages/ui-components/src/Common/Signature/index.tsx @@ -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> = ({ + kind = 'default', + name, + type, + description, + optional, + title, + children, +}) => { + if (title) { + return {children}; + } + + return ( + + {children} + + ); +}; + +export default Signature; diff --git a/packages/ui-components/src/Containers/FunctionSignature/index.stories.tsx b/packages/ui-components/src/Containers/FunctionSignature/index.stories.tsx new file mode 100644 index 0000000000000..4aebee4bdee88 --- /dev/null +++ b/packages/ui-components/src/Containers/FunctionSignature/index.stories.tsx @@ -0,0 +1,152 @@ +import FunctionSignature from '#ui/Containers/FunctionSignature'; + +import type { Meta as MetaObj, StoryObj } from '@storybook/react-webpack5'; + +type Story = StoryObj; +type Meta = MetaObj; + +export const Default: Story = { + args: { + title: 'Attributes', + items: [ + { + name: 'streams', + type: ( + <> + <Stream[]>|<Iterable[]>| + <AsyncIterable[]>| + <Function[]> + + ), + }, + { + name: 'options', + optional: true, + type: <Object>, + children: [ + { + name: 'Signal', + type: <AbortSignal>, + }, + { + name: 'end', + type: <boolean>, + description: ( + <> + End the destination stream when the source stream ends. + Transform streams are always ended, even if this value is  + false.Default: true. + + ), + }, + ], + }, + { + name: 'Returns', + type: <Promise>, + description: 'Fulfills when the pipeline is complete.', + kind: 'return', + }, + ], + }, +}; + +export const Nested: Story = { + args: { + title: 'Attributes', + items: [ + { + name: 'source', + type: ( + <> + <Stream>|<Iterable>| + <AsyncIterable>| + <Function> + + ), + children: [ + { + name: 'attribute1', + type: <Attribute1>, + }, + { + name: 'attribute2', + type: <Attribute2>, + }, + { + name: 'attribute3', + type: <Attribute3>, + }, + { + name: 'Returns', + kind: 'return', + description: 'description', + type: ( + <> + <Promise>| + <AsyncIterable> + + ), + }, + ], + }, + { + name: '...transforms', + type: ( + <> + <Stream>|<Function> + + ), + children: [ + { + name: 'source', + description: 'description', + type: <AsyncIterable>, + children: [ + { + name: 'Returns', + kind: 'return', + description: 'description', + type: ( + <> + <Promise>| + <AsyncIterable> + + ), + }, + ], + }, + ], + }, + ], + }, +}; + +export const ReturnType: Story = { + args: { + items: [ + { + name: 'Returns', + type: <Promise>, + description: 'Fulfills when the pipeline is complete.', + kind: 'return', + }, + ], + }, +}; + +export const HasOnlyTypeDefinition: Story = { + args: { + title: 'Type', + items: [ + { + type: <Promise>, + description: 'A simple type definition.', + }, + ], + }, +}; + +export default { + component: FunctionSignature, +} as Meta; diff --git a/packages/ui-components/src/Containers/FunctionSignature/index.tsx b/packages/ui-components/src/Containers/FunctionSignature/index.tsx new file mode 100644 index 0000000000000..96eeaf00b53be --- /dev/null +++ b/packages/ui-components/src/Containers/FunctionSignature/index.tsx @@ -0,0 +1,42 @@ +import Signature from '#ui/Common/Signature'; + +import type { ComponentProps, FC } from 'react'; + +type SignatureDefinition = Omit< + ComponentProps, + 'children' +> & { + children?: Array; +}; + +type FunctionSignatureProps = { + title?: string; + items: Array; +}; + +const renderSignature = (param: SignatureDefinition, index: number) => ( + + {param.children?.map((child, i) => renderSignature(child, i))} + +); + +const FunctionSignature: FC = ({ title, items }) => { + if (title) { + return ( + + {items.map((param, i) => renderSignature(param, i))} + + ); + } + + return items.map((param, i) => renderSignature(param, i)); +}; + +export default FunctionSignature;