-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
369 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import { fn } from '@storybook/test'; | ||
import React from 'react'; | ||
|
||
import { Textarea } from './Textarea'; | ||
|
||
const meta = { | ||
title: 'Forms/Textarea', | ||
component: Textarea, | ||
tags: ['autodocs'], | ||
} satisfies Meta<typeof Textarea>; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Default: Story = { | ||
render: (args: Story['args']) => { | ||
const { value, onChange, ...rest } = args; | ||
const [textareaValue, setTextareaValue] = React.useState(value); | ||
return ( | ||
<Textarea | ||
value={textareaValue} | ||
onChange={(event) => { | ||
setTextareaValue(event.target.value); | ||
onChange(event); | ||
}} | ||
{...rest} | ||
/> | ||
); | ||
}, | ||
decorators: [ | ||
(Story) => ( | ||
<div className="ds-max-w-[480px]"> | ||
<Story /> | ||
</div> | ||
), | ||
], | ||
parameters: { | ||
design: { | ||
type: 'figma', | ||
url: 'https://www.figma.com/design/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=5805-3164', | ||
}, | ||
docs: { | ||
description: { | ||
story: 'This is a input field component for displaying and editing a value with a label text.', | ||
}, | ||
}, | ||
}, | ||
args: { | ||
value: 'Lorem ipsum dolor sit amet', | ||
onChange: fn(), | ||
label: 'Label text', | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { fireEvent, render, screen } from '@testing-library/react'; | ||
import { describe, expect, it, vi } from 'vitest'; | ||
import { Textarea } from './Textarea'; | ||
|
||
describe('Textarea', () => { | ||
const placeholder = 'Enter text'; | ||
|
||
it('renders without crashing', () => { | ||
const onChange = vi.fn(); | ||
const { container } = render(<Textarea onChange={onChange} placeholder={placeholder} />); | ||
const textarea = screen.getByPlaceholderText(placeholder); | ||
expect(textarea).toBeInTheDocument(); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
|
||
it('displays the label when hideLabel is false', () => { | ||
const onChange = vi.fn(); | ||
const { container } = render(<Textarea onChange={onChange} label="Test Label" placeholder="Enter text" />); | ||
const label = screen.getByText('Test Label'); | ||
expect(label).toBeInTheDocument(); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
|
||
it('hides the label when hideLabel is true', () => { | ||
const onChange = vi.fn(); | ||
const { container } = render(<Textarea onChange={onChange} hideLabel={true} placeholder="Enter text" />); | ||
const label = screen.queryByText('Test Label'); | ||
expect(label).not.toBeInTheDocument(); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
|
||
it('calls onChange when the value changes', () => { | ||
const onChange = vi.fn(); | ||
const { container } = render(<Textarea onChange={onChange} placeholder="Enter text" />); | ||
const textarea = screen.getByPlaceholderText(placeholder); | ||
fireEvent.change(textarea, { target: { value: 'New value' } }); | ||
expect(onChange).toHaveBeenCalledTimes(1); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
|
||
it('calls onBlur when the textarea loses focus', () => { | ||
const onChange = vi.fn(); | ||
const onBlur = vi.fn(); | ||
const { container } = render(<Textarea onChange={onChange} onBlur={onBlur} placeholder="Enter text" />); | ||
const textarea = screen.getByPlaceholderText(placeholder); | ||
fireEvent.blur(textarea); | ||
expect(onBlur).toHaveBeenCalledTimes(1); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
|
||
it('displays help text when provided', () => { | ||
const onChange = vi.fn(); | ||
const { container } = render(<Textarea onChange={onChange} help="Help text" placeholder="Enter text" />); | ||
const helpText = screen.getByText('Help text'); | ||
expect(helpText).toBeInTheDocument(); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
|
||
it('sets the correct number of rows', () => { | ||
const onChange = vi.fn(); | ||
const { container } = render(<Textarea onChange={onChange} rows={5} placeholder="Enter text" />); | ||
const textarea = screen.getByPlaceholderText(placeholder); | ||
expect(textarea).toHaveAttribute('rows', '5'); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import React from 'react'; | ||
import { tidyClasses as tc } from '../../utils'; | ||
|
||
interface BaseTextareaProps { | ||
/** The name of the textarea */ | ||
name?: string; | ||
/** The value of the textarea */ | ||
value?: string; | ||
/** The function to call when the textarea loses focus */ | ||
onBlur?: (event: React.FocusEvent<HTMLTextAreaElement>) => void; | ||
/** The function to call when the value of the textarea changes */ | ||
onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void; | ||
/** The placeholder text to display in the textarea */ | ||
placeholder?: string; | ||
/** The help text to display below the textarea */ | ||
help?: string; | ||
/** The number of rows to display in the textarea */ | ||
rows?: number; | ||
/** Additional classes to add to the textarea */ | ||
className?: string; | ||
} | ||
|
||
interface HideLabelProps extends BaseTextareaProps { | ||
/** The label text is not shown when hideLabel is true */ | ||
label?: never; | ||
/** Hide label */ | ||
hideLabel?: true; | ||
/** The placeholder text to display in the textarea is required when hideLabel is true */ | ||
placeholder: string; | ||
} | ||
interface ShowLabelProps extends BaseTextareaProps { | ||
/** The label text to display above the textarea */ | ||
label: string; | ||
/** Hide label */ | ||
hideLabel?: false; | ||
/** The placeholder text to display in the textarea */ | ||
placeholder?: string; | ||
} | ||
|
||
export type TextareaProps = ShowLabelProps | HideLabelProps; | ||
|
||
/** Textareas are multi-line text boxes that allow users to input custom text entries with a keyboard. Various options can be shown with the field to communicate the input requirements. */ | ||
export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(function Textarea( | ||
{ name, value, onBlur, onChange, placeholder, label, hideLabel = false, help, rows, className = '' }: TextareaProps, | ||
ref, | ||
) { | ||
const inputId = React.useId(); | ||
const helpId = React.useId(); | ||
return ( | ||
<> | ||
<label | ||
htmlFor={inputId} | ||
className={tc([ | ||
hideLabel ? 'ds-hidden' : '', | ||
'ds-mb-4 ds-inline-block ds-align-top ds-text-form-label ds-font-arial ds-text-black', | ||
])} | ||
> | ||
{label} | ||
</label> | ||
<textarea | ||
ref={ref} | ||
id={inputId} | ||
name={name} | ||
value={value} | ||
onBlur={onBlur} | ||
onChange={onChange} | ||
rows={rows} | ||
placeholder={placeholder} | ||
autoComplete="off" | ||
aria-describedby={help ? helpId : undefined} | ||
className={tc([ | ||
'ds-block ds-w-full ds-rounded ds-border ds-border-border-gray ds-bg-white ds-p-5 ds-text-black ds-outline-none placeholder:ds-text-secondary-gray ds-font-arial ds-text-body-md', | ||
className, | ||
])} | ||
/> | ||
{help && ( | ||
<div id={helpId} className="ds-mt-2 ds-block ds-text-help ds-text-secondary-gray ds-font-arial"> | ||
{help} | ||
</div> | ||
)} | ||
</> | ||
); | ||
}); |
Oops, something went wrong.