aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/atoms/forms
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/atoms/forms')
-rw-r--r--src/components/atoms/forms/fields/boolean-field/boolean-field.stories.ts31
-rw-r--r--src/components/atoms/forms/fields/boolean-field/boolean-field.stories.tsx172
-rw-r--r--src/components/atoms/forms/fields/checkbox/checkbox.stories.ts20
-rw-r--r--src/components/atoms/forms/fields/input/input.stories.tsx454
-rw-r--r--src/components/atoms/forms/fields/radio/radio.stories.ts20
-rw-r--r--src/components/atoms/forms/fields/select/select.stories.tsx210
-rw-r--r--src/components/atoms/forms/fields/text-area/text-area.stories.tsx200
-rw-r--r--src/components/atoms/forms/fieldset/fieldset.stories.tsx96
-rw-r--r--src/components/atoms/forms/label/label.stories.ts48
-rw-r--r--src/components/atoms/forms/label/label.stories.tsx119
-rw-r--r--src/components/atoms/forms/legend/legend.stories.tsx38
11 files changed, 556 insertions, 852 deletions
diff --git a/src/components/atoms/forms/fields/boolean-field/boolean-field.stories.ts b/src/components/atoms/forms/fields/boolean-field/boolean-field.stories.ts
new file mode 100644
index 0000000..d1be590
--- /dev/null
+++ b/src/components/atoms/forms/fields/boolean-field/boolean-field.stories.ts
@@ -0,0 +1,31 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { BooleanField } from './boolean-field';
+
+const meta = {
+ component: BooleanField,
+ title: 'Atoms/Forms/Fields/BooleanField',
+} satisfies Meta<typeof BooleanField>;
+
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+export const Checkbox: Story = {
+ args: {
+ id: 'checkbox',
+ isChecked: false,
+ name: 'checkbox',
+ type: 'checkbox',
+ value: 'checkbox',
+ },
+};
+
+export const Radio: Story = {
+ args: {
+ id: 'radio',
+ isChecked: false,
+ name: 'radio',
+ type: 'radio',
+ value: 'radio',
+ },
+};
diff --git a/src/components/atoms/forms/fields/boolean-field/boolean-field.stories.tsx b/src/components/atoms/forms/fields/boolean-field/boolean-field.stories.tsx
deleted file mode 100644
index 60dd352..0000000
--- a/src/components/atoms/forms/fields/boolean-field/boolean-field.stories.tsx
+++ /dev/null
@@ -1,172 +0,0 @@
-import type { ComponentMeta, ComponentStory } from '@storybook/react';
-import { useCallback, useState } from 'react';
-import { BooleanField } from './boolean-field';
-
-/**
- * BooleanField - Storybook Meta
- */
-export default {
- title: 'Atoms/Forms/Fields',
- component: BooleanField,
- args: {
- isHidden: false,
- },
- argTypes: {
- 'aria-labelledby': {
- control: {
- type: 'text',
- },
- description: 'One or more ids that refers to the field name.',
- table: {
- category: 'Accessibility',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- className: {
- control: {
- type: 'text',
- },
- description: 'Set additional classnames to the field.',
- table: {
- category: 'Styles',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- id: {
- control: {
- type: 'text',
- },
- description: 'The field id.',
- type: {
- name: 'string',
- required: true,
- },
- },
- isChecked: {
- control: {
- type: null,
- },
- description: 'The field state: true if checked.',
- type: {
- name: 'boolean',
- required: true,
- },
- },
- isHidden: {
- control: {
- type: 'boolean',
- },
- description: 'Define if the field should be visually hidden.',
- table: {
- category: 'Options',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- name: {
- control: {
- type: 'text',
- },
- description: 'The field name.',
- type: {
- name: 'string',
- required: true,
- },
- },
- onChange: {
- control: {
- type: null,
- },
- description: 'A callback function to handle field state change.',
- table: {
- category: 'Events',
- },
- type: {
- name: 'function',
- required: true,
- },
- },
- onClick: {
- control: {
- type: null,
- },
- description: 'A callback function to handle click on field.',
- table: {
- category: 'Events',
- },
- type: {
- name: 'function',
- required: false,
- },
- },
- type: {
- control: {
- type: 'select',
- },
- description: 'The field type. Either checkbox or radio.',
- options: ['checkbox', 'radio'],
- type: {
- name: 'string',
- required: true,
- },
- },
- value: {
- control: {
- type: 'text',
- },
- description: 'The field value.',
- type: {
- name: 'string',
- required: true,
- },
- },
- },
-} as ComponentMeta<typeof BooleanField>;
-
-const Template: ComponentStory<typeof BooleanField> = ({
- isChecked: checked,
- onChange: _onChange,
- ...args
-}) => {
- const [isChecked, setIsChecked] = useState(checked);
- const handleChange = useCallback(() => {
- setIsChecked((prev) => !prev);
- }, []);
-
- return (
- <BooleanField isChecked={isChecked} onChange={handleChange} {...args} />
- );
-};
-
-/**
- * Checkbox Story
- */
-export const Checkbox = Template.bind({});
-Checkbox.args = {
- id: 'checkbox',
- isChecked: false,
- name: 'checkbox',
- type: 'checkbox',
- value: 'checkbox',
-};
-
-/**
- * Radio Story
- */
-export const Radio = Template.bind({});
-Radio.args = {
- id: 'radio',
- isChecked: false,
- name: 'radio',
- type: 'radio',
- value: 'radio',
-};
diff --git a/src/components/atoms/forms/fields/checkbox/checkbox.stories.ts b/src/components/atoms/forms/fields/checkbox/checkbox.stories.ts
new file mode 100644
index 0000000..e815b91
--- /dev/null
+++ b/src/components/atoms/forms/fields/checkbox/checkbox.stories.ts
@@ -0,0 +1,20 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { Checkbox as CheckboxComponent } from './checkbox';
+
+const meta = {
+ component: CheckboxComponent,
+ title: 'Atoms/Forms/Fields',
+} satisfies Meta<typeof CheckboxComponent>;
+
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+export const Checkbox: Story = {
+ args: {
+ id: 'checkbox',
+ isChecked: false,
+ name: 'checkbox',
+ value: 'checkbox',
+ },
+};
diff --git a/src/components/atoms/forms/fields/input/input.stories.tsx b/src/components/atoms/forms/fields/input/input.stories.tsx
index 4744bc5..af1ca60 100644
--- a/src/components/atoms/forms/fields/input/input.stories.tsx
+++ b/src/components/atoms/forms/fields/input/input.stories.tsx
@@ -1,237 +1,231 @@
-import type { ComponentMeta, ComponentStory } from '@storybook/react';
-import { type ChangeEvent, useCallback, useState } from 'react';
-import { Input } from './input';
-
-/**
- * Input - Storybook Meta
- */
-export default {
- title: 'Atoms/Forms/Fields',
+import { useArgs } from '@storybook/client-api';
+import type { Meta, StoryObj } from '@storybook/react';
+import { type ChangeEvent, useCallback } from 'react';
+import { Input, type InputProps } from './input';
+
+const meta = {
component: Input,
+ title: 'Atoms/Forms/Fields/Input',
+ excludeStories: /Controlled.*$/,
+} satisfies Meta<typeof Input>;
+
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+export const ControlledInput = ({ value, ...args }: InputProps) => {
+ const [_, updateArgs] = useArgs<InputProps>();
+
+ const handleChange = useCallback(
+ (e: ChangeEvent<HTMLInputElement>) => {
+ updateArgs({ ...args, value: e.target.value });
+ },
+ [args, updateArgs]
+ );
+
+ return <Input {...args} onChange={handleChange} value={value} />;
+};
+
+const InputTemplate: Story = {
args: {
+ id: 'default',
isDisabled: false,
+ isReadOnly: false,
isRequired: false,
+ name: 'default',
+ type: 'text',
+ value: '',
},
- argTypes: {
- 'aria-labelledby': {
- control: {
- type: 'text',
- },
- description: 'One or more ids that refers to the field name.',
- table: {
- category: 'Accessibility',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- className: {
- control: {
- type: 'text',
- },
- description: 'Add classnames to the field.',
- table: {
- category: 'Styles',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- id: {
- control: {
- type: 'text',
- },
- description: 'Input id.',
- type: {
- name: 'string',
- required: true,
- },
- },
- isDisabled: {
- control: {
- type: 'boolean',
- },
- description: 'Input state: either enabled or disabled.',
- table: {
- category: 'Options',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- isRequired: {
- control: {
- type: 'boolean',
- },
- description: 'Determine if the field is required.',
- table: {
- category: 'Options',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- max: {
- control: {
- type: 'number',
- },
- description: 'Maximum value.',
- table: {
- category: 'Options',
- },
- type: {
- name: 'number',
- required: false,
- },
- },
- min: {
- control: {
- type: 'number',
- },
- description: 'Minimum value.',
- table: {
- category: 'Options',
- },
- type: {
- name: 'number',
- required: false,
- },
- },
- name: {
- control: {
- type: 'text',
- },
- description: 'Input name.',
- type: {
- name: 'string',
- required: true,
- },
- },
- placeholder: {
- control: {
- type: 'text',
- },
- description: 'A placeholder value.',
- table: {
- category: 'Options',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- step: {
- control: {
- type: 'number',
- },
- description: 'Input incremental values that are valid.',
- table: {
- category: 'Options',
- },
- type: {
- name: 'number',
- required: false,
- },
- },
- type: {
- control: {
- type: 'select',
- },
- description: 'Input type: input type or textarea.',
- options: [
- 'datetime-local',
- 'email',
- 'number',
- 'search',
- 'tel',
- 'text',
- 'textarea',
- 'time',
- 'url',
- ],
- type: {
- name: 'string',
- required: true,
- },
- },
- value: {
- control: {
- type: null,
- },
- description: 'Input value.',
- type: {
- name: 'string',
- required: true,
- },
- },
+ render: ControlledInput,
+};
+
+export const IsEditable: Story = {
+ ...InputTemplate,
+ name: 'State: Editable',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of an editable input field',
+ id: 'editable-input',
+ name: 'editable',
+ },
+};
+
+export const IsDisabled: Story = {
+ ...InputTemplate,
+ name: 'State: Disabled',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a disabled input field',
+ id: 'disabled-input',
+ isDisabled: true,
+ name: 'disabled',
+ },
+};
+
+export const IsReadOnly: Story = {
+ ...InputTemplate,
+ name: 'State: Readonly',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a read-only input field',
+ id: 'readonly-input',
+ isReadOnly: true,
+ name: 'readonly',
+ },
+};
+
+export const IsRequired: Story = {
+ ...InputTemplate,
+ name: 'State: Required',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a required input field',
+ id: 'required-input',
+ isRequired: true,
+ name: 'required',
+ },
+};
+
+export const DateInput: Story = {
+ ...InputTemplate,
+ name: 'Type: Date',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a date field',
+ id: 'date',
+ name: 'date',
+ type: 'date',
+ },
+};
+
+export const DatetimeInput: Story = {
+ ...InputTemplate,
+ name: 'Type: Datetime',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a datetime field',
+ id: 'datetime',
+ name: 'datetime',
+ type: 'datetime-local',
+ },
+};
+
+export const EmailInput: Story = {
+ ...InputTemplate,
+ name: 'Type: Email',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of an email field',
+ id: 'email',
+ name: 'email',
+ type: 'email',
+ },
+};
+
+export const MonthInput: Story = {
+ ...InputTemplate,
+ name: 'Type: Month',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a month field',
+ id: 'month',
+ name: 'month',
+ type: 'month',
+ },
+};
+
+export const NumberInput: Story = {
+ ...InputTemplate,
+ name: 'Type: Number',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a number field',
+ id: 'number',
+ name: 'number',
+ type: 'number',
+ },
+};
+
+export const PasswordInput: Story = {
+ ...InputTemplate,
+ name: 'Type: Password',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a password field',
+ id: 'password',
+ name: 'password',
+ type: 'password',
+ },
+};
+
+export const SearchInput: Story = {
+ ...InputTemplate,
+ name: 'Type: Search',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a search field',
+ id: 'search',
+ name: 'search',
+ type: 'search',
+ },
+};
+
+export const TelInput: Story = {
+ ...InputTemplate,
+ name: 'Type: Tel',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a tel field',
+ id: 'tel',
+ name: 'tel',
+ type: 'tel',
+ },
+};
+
+export const TextInput: Story = {
+ ...InputTemplate,
+ name: 'Type: Text',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a text field',
+ id: 'text',
+ name: 'text',
+ type: 'text',
+ },
+};
+
+export const TimeInput: Story = {
+ ...InputTemplate,
+ name: 'Type: Time',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a time field',
+ id: 'time',
+ name: 'time',
+ type: 'time',
+ },
+};
+
+export const UrlInput: Story = {
+ ...InputTemplate,
+ name: 'Type: Url',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of an url field',
+ id: 'url',
+ name: 'url',
+ type: 'url',
+ },
+};
+
+export const WeekInput: Story = {
+ ...InputTemplate,
+ name: 'Type: Week',
+ args: {
+ ...InputTemplate.args,
+ 'aria-label': 'Example of a week field',
+ id: 'week',
+ name: 'week',
+ type: 'week',
},
-} as ComponentMeta<typeof Input>;
-
-const Template: ComponentStory<typeof Input> = ({
- value: initialValue,
- onChange: _onChange,
- ...args
-}) => {
- const [value, setValue] = useState(initialValue);
- const updateValue = useCallback((e: ChangeEvent<HTMLInputElement>) => {
- setValue(e.target.value);
- }, []);
-
- return <Input value={value} onChange={updateValue} {...args} />;
-};
-
-/**
- * Input Story - DateTimeField
- */
-export const DateTimeField = Template.bind({});
-DateTimeField.args = {
- id: 'field-storybook',
- name: 'field-storybook',
- type: 'datetime-local',
-};
-
-/**
- * Input Story - EmailField
- */
-export const EmailField = Template.bind({});
-EmailField.args = {
- id: 'field-storybook',
- name: 'field-storybook',
- type: 'email',
-};
-
-/**
- * Input Story - NumericField
- */
-export const NumericField = Template.bind({});
-NumericField.args = {
- id: 'field-storybook',
- name: 'field-storybook',
- type: 'number',
-};
-
-/**
- * Input Story - TextField
- */
-export const TextField = Template.bind({});
-TextField.args = {
- id: 'field-storybook',
- name: 'field-storybook',
- type: 'text',
-};
-
-/**
- * Input Story - TimeField
- */
-export const TimeField = Template.bind({});
-TimeField.args = {
- id: 'field-storybook',
- name: 'field-storybook',
- type: 'time',
};
diff --git a/src/components/atoms/forms/fields/radio/radio.stories.ts b/src/components/atoms/forms/fields/radio/radio.stories.ts
new file mode 100644
index 0000000..c1f5eed
--- /dev/null
+++ b/src/components/atoms/forms/fields/radio/radio.stories.ts
@@ -0,0 +1,20 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { Radio as RadioComponent } from './radio';
+
+const meta = {
+ component: RadioComponent,
+ title: 'Atoms/Forms/Fields',
+} satisfies Meta<typeof RadioComponent>;
+
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+export const Radio: Story = {
+ args: {
+ id: 'radio',
+ isChecked: false,
+ name: 'radio',
+ value: 'radio',
+ },
+};
diff --git a/src/components/atoms/forms/fields/select/select.stories.tsx b/src/components/atoms/forms/fields/select/select.stories.tsx
index fddf354..7884cfb 100644
--- a/src/components/atoms/forms/fields/select/select.stories.tsx
+++ b/src/components/atoms/forms/fields/select/select.stories.tsx
@@ -1,143 +1,91 @@
-import type { ComponentMeta, ComponentStory } from '@storybook/react';
-import { type ChangeEvent, useCallback, useState } from 'react';
-import { Select as SelectComponent } from './select';
+import type { Meta, StoryObj } from '@storybook/react';
+import { type ChangeEvent, useState, useCallback } from 'react';
+import { Select, type SelectOptions, type SelectProps } from './select';
-const selectOptions = [
- { id: 'option1', name: 'Option 1', value: 'option1' },
- { id: 'option2', name: 'Option 2', value: 'option2' },
- { id: 'option3', name: 'Option 3', value: 'option3' },
-];
+const meta = {
+ component: Select,
+ title: 'Atoms/Forms/Fields/Select',
+ excludeStories: /Controlled.*$/,
+} satisfies Meta<typeof Select>;
-/**
- * Select - Storybook Meta
- */
-export default {
- title: 'Atoms/Forms/Fields',
- component: SelectComponent,
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+export const ControlledSelect = ({ multiple, ...args }: SelectProps) => {
+ const [selected, setSelected] = useState(multiple === true ? [''] : '');
+ const handler = useCallback(
+ (e: ChangeEvent<HTMLSelectElement>) => {
+ if (multiple)
+ setSelected(
+ Array.from(e.target.selectedOptions, (option) => option.value)
+ );
+ else setSelected(e.target.value);
+ },
+ [multiple]
+ );
+
+ return (
+ <Select {...args} multiple={multiple} onChange={handler} value={selected} />
+ );
+};
+
+const options = [
+ { id: 'option-1', name: 'Option 1', value: 'option-1' },
+ { id: 'option-2', name: 'Option 2', value: 'option-2' },
+ { id: 'option-3', name: 'Option 3', value: 'option-3' },
+ { id: 'option-4', name: 'Option 4', value: 'option-4' },
+ { id: 'option-5', name: 'Option 5', value: 'option-5' },
+] satisfies SelectOptions[];
+
+const SelectTemplate: Story = {
args: {
isDisabled: false,
isRequired: false,
+ multiple: false,
+ options,
+ value: '',
},
- argTypes: {
- 'aria-labelledby': {
- control: {
- type: 'text',
- },
- description: 'One or more ids that refers to the select field name.',
- table: {
- category: 'Accessibility',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- className: {
- control: {
- type: 'text',
- },
- description: 'Add classnames to the select field.',
- table: {
- category: 'Styles',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- id: {
- control: {
- type: 'text',
- },
- description: 'Field id.',
- type: {
- name: 'string',
- required: true,
- },
- },
- isDisabled: {
- control: {
- type: 'boolean',
- },
- description: 'Field state: either enabled or disabled.',
- table: {
- category: 'Options',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- isRequired: {
- control: {
- type: 'boolean',
- },
- description: 'Determine if the field is required.',
- table: {
- category: 'Options',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- name: {
- control: {
- type: 'text',
- },
- description: 'Field name.',
- type: {
- name: 'string',
- required: true,
- },
- },
- options: {
- description: 'Select options.',
- type: {
- name: 'array',
- required: true,
- value: {
- name: 'string',
- },
- },
- },
- value: {
- control: {
- type: null,
- },
- description: 'Field value.',
- type: {
- name: 'string',
- required: true,
- },
- },
+ render: ControlledSelect,
+};
+
+export const SingleChoice: Story = {
+ ...SelectTemplate,
+ args: {
+ ...SelectTemplate.args,
+ 'aria-label': 'Example of a default select field',
+ options,
},
-} as ComponentMeta<typeof SelectComponent>;
+};
-const Template: ComponentStory<typeof SelectComponent> = ({
- onChange: _onChange,
- value,
- ...args
-}) => {
- const [selected, setSelected] = useState(value);
- const updateSelection = useCallback((e: ChangeEvent<HTMLSelectElement>) => {
- setSelected(e.target.value);
- }, []);
+export const MultipleChoices: Story = {
+ ...SelectTemplate,
+ args: {
+ ...SelectTemplate.args,
+ 'aria-label': 'Example of a select field with multiple choices',
+ multiple: true,
+ options,
+ },
+};
- return (
- <SelectComponent {...args} onChange={updateSelection} value={selected} />
- );
+export const IsDisabled: Story = {
+ ...SelectTemplate,
+ name: 'State: Disabled',
+ args: {
+ ...SelectTemplate.args,
+ 'aria-label': 'Example of a disabled select field',
+ isDisabled: true,
+ options,
+ },
};
-/**
- * Select Story
- */
-export const Select = Template.bind({});
-Select.args = {
- id: 'storybook-select',
- name: 'storybook-select',
- options: selectOptions,
- value: 'option2',
+export const IsRequired: Story = {
+ ...SelectTemplate,
+ name: 'State: Required',
+ args: {
+ ...SelectTemplate.args,
+ 'aria-label': 'Example of a required select field',
+ isRequired: true,
+ options,
+ },
};
diff --git a/src/components/atoms/forms/fields/text-area/text-area.stories.tsx b/src/components/atoms/forms/fields/text-area/text-area.stories.tsx
index 21214bd..d98dfe3 100644
--- a/src/components/atoms/forms/fields/text-area/text-area.stories.tsx
+++ b/src/components/atoms/forms/fields/text-area/text-area.stories.tsx
@@ -1,136 +1,86 @@
-import type { ComponentMeta, ComponentStory } from '@storybook/react';
-import { type ChangeEvent, useCallback, useState } from 'react';
-import { TextArea as TextAreaComponent } from './text-area';
+import { useArgs } from '@storybook/client-api';
+import type { Meta, StoryObj } from '@storybook/react';
+import { type ChangeEvent, useCallback } from 'react';
+import { TextArea, type TextAreaProps } from './text-area';
-/**
- * TextArea - Storybook Meta
- */
-export default {
- title: 'Atoms/Forms/Fields',
- component: TextAreaComponent,
+const meta = {
+ component: TextArea,
+ title: 'Atoms/Forms/Fields/TextArea',
+ excludeStories: /Controlled.*$/,
+} satisfies Meta<typeof TextArea>;
+
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+export const ControlledTextArea = ({ value, ...args }: TextAreaProps) => {
+ const [_, updateArgs] = useArgs<TextAreaProps>();
+
+ const handleChange = useCallback(
+ (e: ChangeEvent<HTMLTextAreaElement>) => {
+ updateArgs({ ...args, value: e.target.value });
+ },
+ [args, updateArgs]
+ );
+
+ return <TextArea {...args} onChange={handleChange} value={value} />;
+};
+
+const TextAreaTemplate: Story = {
args: {
+ id: 'default',
isDisabled: false,
+ isReadOnly: false,
isRequired: false,
+ name: 'default',
+ value: '',
},
- argTypes: {
- 'aria-labelledby': {
- control: {
- type: 'text',
- },
- description: 'One or more ids that refers to the field name.',
- table: {
- category: 'Accessibility',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- className: {
- control: {
- type: 'text',
- },
- description: 'Add classnames to the field.',
- table: {
- category: 'Styles',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- id: {
- control: {
- type: 'text',
- },
- description: 'TextArea id.',
- type: {
- name: 'string',
- required: true,
- },
- },
- isDisabled: {
- control: {
- type: 'boolean',
- },
- description: 'TextArea state: either enabled or disabled.',
- table: {
- category: 'Options',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- isRequired: {
- control: {
- type: 'boolean',
- },
- description: 'Determine if the field is required.',
- table: {
- category: 'Options',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- name: {
- control: {
- type: 'text',
- },
- description: 'TextArea name.',
- type: {
- name: 'string',
- required: true,
- },
- },
- placeholder: {
- control: {
- type: 'text',
- },
- description: 'A placeholder value.',
- table: {
- category: 'Options',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- value: {
- control: {
- type: null,
- },
- description: 'TextArea value.',
- type: {
- name: 'string',
- required: true,
- },
- },
+ render: ControlledTextArea,
+};
+
+export const IsEditable: Story = {
+ ...TextAreaTemplate,
+ name: 'State: Editable',
+ args: {
+ ...TextAreaTemplate.args,
+ 'aria-label': 'Example of a default text area',
+ id: 'disabled',
+ name: 'disabled',
},
-} as ComponentMeta<typeof TextAreaComponent>;
+};
-const Template: ComponentStory<typeof TextAreaComponent> = ({
- value: initialValue,
- onChange: _onChange,
- ...args
-}) => {
- const [value, setValue] = useState(initialValue);
- const updateValue = useCallback((e: ChangeEvent<HTMLTextAreaElement>) => {
- setValue(e.target.value);
- }, []);
+export const IsDisabled: Story = {
+ ...TextAreaTemplate,
+ name: 'State: Disabled',
+ args: {
+ ...TextAreaTemplate.args,
+ 'aria-label': 'Example of a disabled text area',
+ id: 'disabled',
+ isDisabled: true,
+ name: 'disabled',
+ },
+};
- return <TextAreaComponent value={value} onChange={updateValue} {...args} />;
+export const IsReadOnly: Story = {
+ ...TextAreaTemplate,
+ name: 'State: Readonly',
+ args: {
+ ...TextAreaTemplate.args,
+ 'aria-label': 'Example of a read-only text area',
+ id: 'readonly',
+ isReadOnly: true,
+ name: 'readonly',
+ },
};
-/**
- * TextArea Story - TextArea
- */
-export const TextArea = Template.bind({});
-TextArea.args = {
- id: 'field-storybook',
- name: 'field-storybook',
+export const IsRequired: Story = {
+ ...TextAreaTemplate,
+ name: 'State: Required',
+ args: {
+ ...TextAreaTemplate.args,
+ 'aria-label': 'Example of a required text area',
+ id: 'required',
+ isRequired: true,
+ name: 'required',
+ },
};
diff --git a/src/components/atoms/forms/fieldset/fieldset.stories.tsx b/src/components/atoms/forms/fieldset/fieldset.stories.tsx
index a7d665d..e3dd53e 100644
--- a/src/components/atoms/forms/fieldset/fieldset.stories.tsx
+++ b/src/components/atoms/forms/fieldset/fieldset.stories.tsx
@@ -1,61 +1,47 @@
-import type { ComponentMeta, ComponentStory } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react';
import { Input } from '../fields';
-import { Legend } from '../legend';
-import { Fieldset as FieldsetComponent } from './fieldset';
-
-/**
- * Fieldset - Storybook Meta
- */
-export default {
- title: 'Atoms/Forms',
- component: FieldsetComponent,
+import { Fieldset, type FieldsetProps } from './fieldset';
+
+const meta = {
+ component: Fieldset,
+ title: 'Atoms/Forms/Fieldset',
+} satisfies Meta<typeof Fieldset>;
+
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+export const Default: Story = {
+ args: {},
+};
+
+const FieldsetWithFields = ({
+ inputLabel,
+ ...props
+}: FieldsetProps & { inputLabel: string }) => (
+ <Fieldset {...props}>
+ <Input aria-label={inputLabel} id="field" name="field" type="text" />
+ </Fieldset>
+);
+
+type WithFieldStory = StoryObj<FieldsetProps & { inputLabel: string }>;
+
+export const Enabled: WithFieldStory = {
+ name: 'State: Enabled',
args: {
+ ...Default.args,
+ inputLabel: 'Example of a field inside an enabled fieldset',
isDisabled: false,
},
- argTypes: {
- isDisabled: {
- control: {
- type: 'boolean',
- },
- description:
- 'Define if the fields inside the fieldset should be disabled.',
- table: {
- category: 'Options',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- },
-} as ComponentMeta<typeof FieldsetComponent>;
-
-const Template: ComponentStory<typeof FieldsetComponent> = (args) => (
- <FieldsetComponent {...args}>
- <div>
- <Input
- aria-label="A field example"
- id="field1"
- name="field1"
- type="text"
- />
- </div>
- <div>
- <Input
- aria-label="Another field example"
- id="field2"
- name="field2"
- type="text"
- />
- </div>
- </FieldsetComponent>
-);
+ render: FieldsetWithFields,
+};
-/**
- * Fieldset Story
- */
-export const Fieldset = Template.bind({});
-Fieldset.args = {
- legend: <Legend>The fieldset legend</Legend>,
+export const Disabled: WithFieldStory = {
+ name: 'State: Disabled',
+ args: {
+ ...Default.args,
+ inputLabel: 'Example of a field inside a disabled fieldset',
+ isDisabled: true,
+ },
+ render: FieldsetWithFields,
};
diff --git a/src/components/atoms/forms/label/label.stories.ts b/src/components/atoms/forms/label/label.stories.ts
new file mode 100644
index 0000000..094a432
--- /dev/null
+++ b/src/components/atoms/forms/label/label.stories.ts
@@ -0,0 +1,48 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { Label } from './label';
+
+const meta = {
+ component: Label,
+ title: 'Atoms/Forms/Label',
+} satisfies Meta<typeof Label>;
+
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+export const Default: Story = {
+ args: {
+ children: 'A label',
+ },
+};
+
+export const VisuallyHidden: Story = {
+ args: {
+ children: 'A visually hidden label',
+ isHidden: true,
+ },
+};
+
+export const IsRequired: Story = {
+ name: 'State: Required',
+ args: {
+ ...Default.args,
+ isRequired: true,
+ },
+};
+
+export const SizeSM: Story = {
+ name: 'Size: Small',
+ args: {
+ ...Default.args,
+ size: 'sm',
+ },
+};
+
+export const SizeMD: Story = {
+ name: 'Size: Medium',
+ args: {
+ ...Default.args,
+ size: 'md',
+ },
+};
diff --git a/src/components/atoms/forms/label/label.stories.tsx b/src/components/atoms/forms/label/label.stories.tsx
deleted file mode 100644
index 195be97..0000000
--- a/src/components/atoms/forms/label/label.stories.tsx
+++ /dev/null
@@ -1,119 +0,0 @@
-import type { ComponentMeta, ComponentStory } from '@storybook/react';
-import { Label as LabelComponent } from './label';
-
-/**
- * Label - Storybook Meta
- */
-export default {
- title: 'Atoms/Forms',
- component: LabelComponent,
- args: {
- isHidden: false,
- isRequired: false,
- size: 'sm',
- },
- argTypes: {
- 'aria-label': {
- control: {
- type: 'text',
- },
- description: 'Define an accessible name.',
- table: {
- category: 'Accessibility',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- className: {
- control: {
- type: 'text',
- },
- description: 'Add classnames to the label.',
- table: {
- category: 'Styles',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- children: {
- control: {
- type: 'text',
- },
- description: 'The label body.',
- type: {
- name: 'string',
- required: true,
- },
- },
- htmlFor: {
- control: {
- type: 'text',
- },
- description: 'The field id.',
- type: {
- name: 'string',
- required: true,
- },
- },
- isHidden: {
- control: {
- type: 'boolean',
- },
- description: 'Set to true if the label should be visually hidden.',
- table: {
- category: 'Options',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- isRequired: {
- control: {
- type: 'boolean',
- },
- description: 'Set to true if the field is required.',
- table: {
- category: 'Options',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- size: {
- control: {
- type: 'select',
- },
- description: 'The label size.',
- options: ['md', 'sm'],
- table: {
- category: 'Options',
- defaultValue: { summary: 'sm' },
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- },
-} as ComponentMeta<typeof LabelComponent>;
-
-const Template: ComponentStory<typeof LabelComponent> = ({
- children,
- ...args
-}) => <LabelComponent {...args}>{children}</LabelComponent>;
-
-/**
- * Label Story
- */
-export const Label = Template.bind({});
-Label.args = {
- children: 'A label',
-};
diff --git a/src/components/atoms/forms/legend/legend.stories.tsx b/src/components/atoms/forms/legend/legend.stories.tsx
index b23d889..963fe33 100644
--- a/src/components/atoms/forms/legend/legend.stories.tsx
+++ b/src/components/atoms/forms/legend/legend.stories.tsx
@@ -1,27 +1,25 @@
-import type { ComponentMeta, ComponentStory } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react';
import { Fieldset } from '../fieldset';
-import { Legend as LegendComponent } from './legend';
+import { Legend, type LegendProps } from './legend';
-/**
- * Legend - Storybook Meta
- */
-export default {
- title: 'Atoms/Forms',
- component: LegendComponent,
- args: {},
- argTypes: {},
-} as ComponentMeta<typeof LegendComponent>;
-
-const Template: ComponentStory<typeof LegendComponent> = (args) => (
+const FieldsetWithLegend = (args: LegendProps) => (
<Fieldset>
- <LegendComponent {...args} />
+ <Legend {...args} />
</Fieldset>
);
-/**
- * Legend Story
- */
-export const Legend = Template.bind({});
-Legend.args = {
- children: 'A fieldset legend',
+const meta = {
+ component: Legend,
+ title: 'Atoms/Forms/Legend',
+ render: FieldsetWithLegend,
+} satisfies Meta<typeof Legend>;
+
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+export const Default: Story = {
+ args: {
+ children: 'A legend',
+ },
};