Skip to content

Commit

Permalink
feat: add textArea component (#78)
Browse files Browse the repository at this point in the history
Signed-off-by: Lukas.J.Han <[email protected]>
  • Loading branch information
lukasjhan authored Aug 20, 2024
1 parent f90594f commit 5f68745
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 1 deletion.
79 changes: 79 additions & 0 deletions packages/core/lib/components/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { forwardRef, useState } from 'react';
import { Label } from './Label';

type TextAreaProps = {
id: string;
title?: string;
description?: string;
size?: 'small' | 'medium' | 'large';
maxLength?: number;
} & React.TextareaHTMLAttributes<HTMLTextAreaElement>;

export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
(
{
title,
description,
id,
placeholder,
size = 'medium',
maxLength,
onChange,
...props
},
ref
) => {
const [charCount, setCharCount] = useState(0);

const sizeClasses = {
small: 'h-24',
medium: 'h-32',
large: 'h-40',
}[size];

const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setCharCount(e.target.value.length);
if (onChange) {
onChange(e);
}
};

return (
<div className="flex flex-col gap-1 justify-center">
{title && (
<Label htmlFor={id} weight="bold">
{title}
</Label>
)}
{description && (
<Label size={'s'} color={'gray-50'}>
{description}
</Label>
)}
<div className="relative">
<textarea
ref={ref}
id={id}
className={`
w-full ${sizeClasses} px-4 py-3 text-gray-70 border rounded-4
focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary mt-3
border-gray-50 transition duration-150 ease-in-out resize-none
`}
placeholder={placeholder}
maxLength={maxLength}
onChange={handleChange}
{...props}
/>
{maxLength && (
<div className="flex justify-end gap-1">
<Label color={'primary'} size={'xs'}>
{charCount}
</Label>
<Label size={'xs'}>{`/${maxLength}`}</Label>
</div>
)}
</div>
</div>
);
}
);
3 changes: 2 additions & 1 deletion packages/core/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Tag } from './components/Tag';
import { Spinner } from './components/Spinner';
import { Badge } from './components/Badge';
import { TextInput } from './components/TextInput';
import { TextArea } from './components/TextArea';

export { Display, Heading, Title, Body, Detail, Label, Link, colors };
export { Button, LinkButton, Tag, Spinner, Badge, TextInput };
export { Button, LinkButton, Tag, Spinner, Badge, TextInput, TextArea };
123 changes: 123 additions & 0 deletions stories/core/TextArea.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import { TextArea } from '../../packages/core/lib';

const meta = {
title: 'Components/TextArea',
component: TextArea,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
size: {
options: ['small', 'medium', 'large'],
control: {
type: 'select',
},
},
onChange: { action: 'changed' },
},
} satisfies Meta<typeof TextArea>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
id: 'text-area-id',
title: 'Title',
description: 'Description',
placeholder: 'Placeholder',
size: 'medium',
maxLength: 100,
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) =>
console.log(e.target.value),
},
};

export const NoMaxLength: Story = {
args: {
id: 'text-area-id-3',
title: 'Title',
description: 'Description',
placeholder: 'Placeholder',
size: 'medium',
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) =>
console.log(e.target.value),
},
};

export const Small: Story = {
args: {
id: 'text-area-id-2',
title: 'Title',
description: 'Description',
placeholder: 'Placeholder',
size: 'small',
maxLength: 100,
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) =>
console.log(e.target.value),
},
};

export const Medium: Story = {
args: {
id: 'text-area-id-4',
title: 'Title',
description: 'Description',
placeholder: 'Placeholder',
size: 'medium',
maxLength: 100,
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) =>
console.log(e.target.value),
},
};

export const Large: Story = {
args: {
id: 'text-area-id-5',
title: 'Title',
description: 'Description',
placeholder: 'Placeholder',
size: 'large',
maxLength: 100,
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) =>
console.log(e.target.value),
},
};

export const NoTitle: Story = {
args: {
id: 'text-area-id-6',
description: 'Description',
placeholder: 'Placeholder',
size: 'medium',
maxLength: 100,
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) =>
console.log(e.target.value),
},
};

export const NoDescription: Story = {
args: {
id: 'text-area-id-7',
placeholder: 'Placeholder',
size: 'medium',
maxLength: 100,
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) =>
console.log(e.target.value),
},
};

export const NoPlaceholder: Story = {
args: {
id: 'text-area-id-8',
title: 'Title',
description: 'Description',
size: 'medium',
maxLength: 100,
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) =>
console.log(e.target.value),
},
};

0 comments on commit 5f68745

Please sign in to comment.