aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/molecules/forms
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-12-15 18:35:16 +0100
committerArmand Philippot <git@armandphilippot.com>2023-12-15 18:49:49 +0100
commit0f936ec0e7606cb79434d94096b6e113a7ce78eb (patch)
tree465ec7f66ac9459be6a18ac046e10357814c7b92 /src/components/molecules/forms
parent4e4d2eb25365be861e19f9756cf334ba2faa6911 (diff)
refactor(stories): migrate stories to CSF3 format
Diffstat (limited to 'src/components/molecules/forms')
-rw-r--r--src/components/molecules/forms/labelled-field/labelled-field.stories.tsx386
-rw-r--r--src/components/molecules/forms/radio-group/radio-group.stories.tsx140
-rw-r--r--src/components/molecules/forms/switch/switch.stories.tsx99
3 files changed, 406 insertions, 219 deletions
diff --git a/src/components/molecules/forms/labelled-field/labelled-field.stories.tsx b/src/components/molecules/forms/labelled-field/labelled-field.stories.tsx
index 1d1af70..47ded7b 100644
--- a/src/components/molecules/forms/labelled-field/labelled-field.stories.tsx
+++ b/src/components/molecules/forms/labelled-field/labelled-field.stories.tsx
@@ -1,130 +1,270 @@
-import type { ComponentMeta, ComponentStory } from '@storybook/react';
-import { type ChangeEvent, useState, useCallback } from 'react';
-import { Input, Label } from '../../../atoms';
+import type { Meta, StoryObj } from '@storybook/react';
+import { type ChangeEvent, useCallback, useState } from 'react';
+import {
+ Checkbox,
+ type CheckboxProps,
+ Radio,
+ type RadioProps,
+ Input,
+ type InputProps,
+ type TextAreaProps,
+ TextArea,
+ Label,
+} from '../../../atoms';
+import { ControlledSelect } from '../../../atoms/forms/fields/select/select.stories';
import { LabelledField } from './labelled-field';
-/**
- * LabelledField - Storybook Meta
- */
-export default {
- title: 'Molecules/Forms/Field',
+const meta = {
+ title: 'Molecules/Forms/Labelled Field',
component: LabelledField,
- argTypes: {
- className: {
- control: {
- type: 'text',
- },
- description: 'Set additional classnames to the field.',
- table: {
- category: 'Styles',
- },
- type: {
- name: 'string',
- required: false,
- },
- },
- field: {
- control: {
- type: null,
- },
- description: 'A component: Checkbox, Input, Select, Radio or TextArea.',
- type: {
- name: 'function',
- required: true,
- },
- },
- label: {
- control: {
- type: null,
- },
- description: 'A Label component.',
- type: {
- name: 'function',
- required: true,
- },
- },
- isInline: {
- control: {
- type: 'boolean',
- },
- description: 'Should the label and the field be inlined?',
- table: {
- category: 'Options',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- isReversedOrder: {
- control: {
- type: 'boolean',
- },
- description: 'Should the label and the field be reversed?',
- table: {
- category: 'Options',
- defaultValue: { summary: false },
- },
- type: {
- name: 'boolean',
- required: false,
- },
- },
- },
-} as ComponentMeta<typeof LabelledField>;
-
-const Template: ComponentStory<typeof LabelledField> = ({ ...args }) => {
- const id = 'sunt';
- const [value, setValue] = useState<string>('');
- const updateValue = useCallback((e: ChangeEvent<HTMLInputElement>) => {
+} satisfies Meta<typeof LabelledField>;
+
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+const ControlledCheckbox = ({
+ isChecked: checked = false,
+ ...args
+}: CheckboxProps) => {
+ const [isChecked, setIsChecked] = useState<boolean>(checked);
+
+ const handleChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
+ setIsChecked(e.target.checked);
+ }, []);
+
+ return <Checkbox {...args} isChecked={isChecked} onChange={handleChange} />;
+};
+
+const ControlledInput = ({ value: defaultValue, ...args }: InputProps) => {
+ const [value, setValue] = useState(defaultValue);
+
+ const handleChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
+ setValue(e.target.value);
+ }, []);
+
+ return <Input {...args} onChange={handleChange} value={value} />;
+};
+
+const ControlledRadio = ({
+ isChecked: checked = false,
+ ...args
+}: RadioProps) => {
+ const [isChecked, setIsChecked] = useState<boolean>(checked);
+
+ const handleChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
+ setIsChecked(e.target.checked);
+ }, []);
+
+ return <Radio {...args} isChecked={isChecked} onChange={handleChange} />;
+};
+
+const ControlledTextArea = ({
+ value: defaultValue,
+ ...args
+}: TextAreaProps) => {
+ const [value, setValue] = useState(defaultValue);
+
+ const handleChange = useCallback((e: ChangeEvent<HTMLTextAreaElement>) => {
setValue(e.target.value);
}, []);
- return (
- <LabelledField
- {...args}
- field={
- <Input
- id={id}
- name={id}
- onChange={updateValue}
- type="text"
- value={value}
- />
- }
- label={<Label htmlFor={id}>A label</Label>}
- />
- );
-};
-
-/**
- * Labelled Field Stories - Left
- */
-export const Left = Template.bind({});
-Left.args = {
- isInline: true,
-};
-
-/**
- * Labelled Field Stories - Right
- */
-export const Right = Template.bind({});
-Right.args = {
- isInline: true,
- isReversedOrder: true,
-};
-
-/**
- * Labelled Field Stories - Top
- */
-export const Top = Template.bind({});
-Top.args = {};
-
-/**
- * Labelled Field Stories - Bottom
- */
-export const Bottom = Template.bind({});
-Bottom.args = {
- isReversedOrder: true,
+ return <TextArea {...args} onChange={handleChange} value={value} />;
+};
+
+export const Default: Story = {
+ args: {
+ field: (
+ <ControlledInput id="default-field" name="default-field" type="text" />
+ ),
+ label: <Label>A field label</Label>,
+ },
+};
+
+export const LabelledCheckbox: Story = {
+ name: 'Field: Checkbox',
+ args: {
+ ...Default.args,
+ field: (
+ <ControlledCheckbox
+ id="checkbox-field"
+ name="checkbox-field"
+ value="checkbox-field"
+ />
+ ),
+ },
+};
+
+export const LabelledRadio: Story = {
+ name: 'Field: Radio',
+ args: {
+ ...Default.args,
+ field: (
+ <ControlledRadio
+ id="radio-field"
+ name="radio-field"
+ value="radio-field"
+ />
+ ),
+ },
+};
+
+export const LabelledDateField: Story = {
+ name: 'Field: Date',
+ args: {
+ ...Default.args,
+ field: <ControlledInput id="date-field" name="date-field" type="date" />,
+ },
+};
+
+export const LabelledDateTimeField: Story = {
+ name: 'Field: Datetime',
+ args: {
+ ...Default.args,
+ field: (
+ <ControlledInput
+ id="datetime-field"
+ name="datetime-field"
+ type="datetime-local"
+ />
+ ),
+ },
+};
+
+export const LabelledEmailField: Story = {
+ name: 'Field: Email',
+ args: {
+ ...Default.args,
+ field: <ControlledInput id="email-field" name="email-field" type="email" />,
+ },
+};
+
+export const LabelledMonthField: Story = {
+ name: 'Field: Month',
+ args: {
+ ...Default.args,
+ field: <ControlledInput id="month-field" name="month-field" type="month" />,
+ },
+};
+
+export const LabelledNumberField: Story = {
+ name: 'Field: Number',
+ args: {
+ ...Default.args,
+ field: (
+ <ControlledInput id="number-field" name="number-field" type="number" />
+ ),
+ },
+};
+
+export const LabelledPasswordField: Story = {
+ name: 'Field: Password',
+ args: {
+ ...Default.args,
+ field: (
+ <ControlledInput
+ id="password-field"
+ name="password-field"
+ type="password"
+ />
+ ),
+ },
+};
+
+export const LabelledSearchField: Story = {
+ name: 'Field: Search',
+ args: {
+ ...Default.args,
+ field: (
+ <ControlledInput id="search-field" name="search-field" type="search" />
+ ),
+ },
+};
+
+export const LabelledSelect: Story = {
+ name: 'Field: Select',
+ args: {
+ ...Default.args,
+ field: (
+ <ControlledSelect
+ id="select-field"
+ name="select-field"
+ options={[]}
+ value=""
+ />
+ ),
+ },
+};
+
+export const LabelledTelField: Story = {
+ name: 'Field: Tel',
+ args: {
+ ...Default.args,
+ field: <ControlledInput id="tel-field" name="tel-field" type="tel" />,
+ },
+};
+
+export const LabelledTextField: Story = {
+ name: 'Field: Text',
+ args: {
+ ...Default.args,
+ },
+};
+
+export const LabelledTextArea: Story = {
+ name: 'Field: Textarea',
+ args: {
+ ...Default.args,
+ field: <ControlledTextArea id="textarea-field" name="textarea-field" />,
+ },
+};
+
+export const LabelledTimeField: Story = {
+ name: 'Field: Time',
+ args: {
+ ...Default.args,
+ field: <ControlledInput id="time-field" name="time-field" type="time" />,
+ },
+};
+
+export const LabelledUrlField: Story = {
+ name: 'Field: Url',
+ args: {
+ ...Default.args,
+ field: <ControlledInput id="url-field" name="url-field" type="url" />,
+ },
+};
+
+export const LayoutColumn: Story = {
+ name: 'Layout: Column',
+ args: {
+ ...LabelledCheckbox.args,
+ isInline: false,
+ },
+};
+
+export const LayoutReversedColumn: Story = {
+ name: 'Layout: Reversed column',
+ args: {
+ ...LabelledCheckbox.args,
+ isInline: false,
+ isReversedOrder: true,
+ },
+};
+
+export const LayoutRow: Story = {
+ name: 'Layout: Row',
+ args: {
+ ...LabelledCheckbox.args,
+ isInline: true,
+ },
+};
+
+export const LayoutReversedRow: Story = {
+ name: 'Layout: Reversed row',
+ args: {
+ ...LabelledCheckbox.args,
+ isInline: true,
+ isReversedOrder: true,
+ },
};
diff --git a/src/components/molecules/forms/radio-group/radio-group.stories.tsx b/src/components/molecules/forms/radio-group/radio-group.stories.tsx
index 4b92c34..2917efb 100644
--- a/src/components/molecules/forms/radio-group/radio-group.stories.tsx
+++ b/src/components/molecules/forms/radio-group/radio-group.stories.tsx
@@ -1,55 +1,9 @@
-import type { ComponentMeta, ComponentStory } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react';
import { type ChangeEventHandler, useCallback, useState } from 'react';
import { Legend } from '../../../atoms';
-import { RadioGroup as RadioGroupComponent } from './radio-group';
-import { getOptions, initialChoice } from './radio-group.fixture';
+import { RadioGroup, type RadioGroupProps } from './radio-group';
-/**
- * RadioGroup - Storybook Meta
- */
-export default {
- title: 'Molecules/Forms',
- component: RadioGroupComponent,
- args: {},
- argTypes: {
- onChange: {
- control: {
- type: null,
- },
- description: 'A callback function to handle selected option change.',
- table: {
- category: 'Events',
- },
- type: {
- name: 'function',
- required: false,
- },
- },
- options: {
- description: 'An array of radio option object.',
- type: {
- name: 'object',
- required: true,
- value: {},
- },
- },
- value: {
- control: {
- type: 'text',
- },
- description: 'The default selected option id.',
- type: {
- name: 'string',
- required: true,
- },
- },
- },
-} as ComponentMeta<typeof RadioGroupComponent>;
-
-const Template: ComponentStory<typeof RadioGroupComponent> = ({
- value,
- ...args
-}) => {
+const ControlledRadioGroup = ({ value, ...props }: RadioGroupProps) => {
const [selection, setSelection] = useState(value);
const handleChange: ChangeEventHandler<HTMLInputElement> = useCallback(
@@ -59,17 +13,83 @@ const Template: ComponentStory<typeof RadioGroupComponent> = ({
[]
);
- return (
- <RadioGroupComponent {...args} onSwitch={handleChange} value={selection} />
- );
+ return <RadioGroup {...props} onSwitch={handleChange} value={selection} />;
};
-/**
- * Radio Group Story
- */
-export const RadioGroup = Template.bind({});
-RadioGroup.args = {
- legend: <Legend>Options:</Legend>,
- options: getOptions('group1'),
- value: initialChoice,
+const meta = {
+ title: 'Molecules/Forms/Radio Group',
+ component: RadioGroup,
+ render: ControlledRadioGroup,
+} satisfies Meta<typeof RadioGroup>;
+
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+export const Example: Story = {
+ args: {
+ legend: <Legend>Select your preferred option:</Legend>,
+ name: 'example',
+ options: [
+ { id: 'example-1', label: 'Option 1', value: 'example-1' },
+ { id: 'example-2', label: 'Option 2', value: 'example-2' },
+ { id: 'example-3', label: 'Option 3', value: 'example-3' },
+ ],
+ },
+};
+
+export const Inline: Story = {
+ args: {
+ ...Example.args,
+ isInline: true,
+ name: 'inline',
+ options: [
+ { id: 'inline-1', label: 'Option 1', value: 'inline-1' },
+ { id: 'inline-2', label: 'Option 2', value: 'inline-2' },
+ { id: 'inline-3', label: 'Option 3', value: 'inline-3' },
+ ],
+ },
+};
+
+export const DisabledGroup: Story = {
+ args: {
+ ...Example.args,
+ isDisabled: true,
+ name: 'disabled',
+ options: [
+ { id: 'disabled-1', label: 'Option 1', value: 'disabled-1' },
+ { id: 'disabled-2', label: 'Option 2', value: 'disabled-2' },
+ { id: 'disabled-3', label: 'Option 3', value: 'disabled-3' },
+ ],
+ },
+};
+
+export const DisabledOption: Story = {
+ args: {
+ ...Example.args,
+ name: 'disabled-option',
+ options: [
+ { id: 'option-1', label: 'Option 1', value: 'option-1' },
+ {
+ id: 'option-2',
+ isDisabled: true,
+ label: 'Option 2',
+ value: 'option-2',
+ },
+ { id: 'option-3', label: 'Option 3', value: 'option-3' },
+ ],
+ },
+};
+
+export const DefaultValue: Story = {
+ args: {
+ ...Example.args,
+ name: 'default-value',
+ options: [
+ { id: 'value-1', label: 'Option 1', value: 'value-1' },
+ { id: 'value-2', label: 'Option 2', value: 'value-2' },
+ { id: 'value-3', label: 'Option 3', value: 'value-3' },
+ ],
+ value: 'value-2',
+ },
};
diff --git a/src/components/molecules/forms/switch/switch.stories.tsx b/src/components/molecules/forms/switch/switch.stories.tsx
index a88e6ab..9a59b83 100644
--- a/src/components/molecules/forms/switch/switch.stories.tsx
+++ b/src/components/molecules/forms/switch/switch.stories.tsx
@@ -1,25 +1,14 @@
-import type { ComponentMeta, ComponentStory } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react';
import { type ChangeEventHandler, useCallback, useState } from 'react';
-import { Legend } from '../../../atoms';
-import { Switch as SwitchComponent, type SwitchOption } from './switch';
-
-/**
- * Switch - Storybook Meta
- */
-export default {
- title: 'Molecules/Forms',
- component: SwitchComponent,
- args: {},
- argTypes: {},
-} as ComponentMeta<typeof SwitchComponent>;
-
-const Template: ComponentStory<typeof SwitchComponent> = ({
- value,
- ...args
-}) => {
- const [selection, setSelection] = useState(value);
-
- const handleChange: ChangeEventHandler<HTMLInputElement> = useCallback(
+import { Icon } from '../../../atoms';
+import { Switch, type SwitchProps } from './switch';
+
+type ControlledSwitchProps = Omit<SwitchProps, 'onSwitch' | 'selectedItem'>;
+
+const ControlledSwitch = ({ items, ...props }: ControlledSwitchProps) => {
+ const [selection, setSelection] = useState(items[0].value);
+
+ const handleSwitch: ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
setSelection(e.target.value);
},
@@ -27,22 +16,60 @@ const Template: ComponentStory<typeof SwitchComponent> = ({
);
return (
- <SwitchComponent {...args} onSwitch={handleChange} value={selection} />
+ <Switch
+ {...props}
+ items={items}
+ onSwitch={handleSwitch}
+ value={selection}
+ />
);
};
-const items: [SwitchOption, SwitchOption] = [
- { id: 'option-1', label: 'Choice 1', value: 'option-1' },
- { id: 'option-2', label: 'Choice 2', value: 'option-2' },
-];
-
-/**
- * Radio Group Story
- */
-export const Switch = Template.bind({});
-Switch.args = {
- items,
- legend: <Legend>Choose the best option:</Legend>,
- name: 'example',
- value: items[0].value,
+const meta = {
+ title: 'Molecules/Forms/Switch',
+ component: Switch,
+ render: ControlledSwitch,
+} satisfies Meta<typeof Switch>;
+
+export default meta;
+
+type Story = StoryObj<typeof ControlledSwitch>;
+
+export const Example: Story = {
+ args: {
+ items: [
+ { id: 'item-1', label: 'Item 1', value: 'item-1' },
+ { id: 'item-2', label: 'Item 2', value: 'item-2' },
+ ],
+ name: 'example',
+ },
+};
+
+export const Disabled: Story = {
+ args: {
+ isDisabled: true,
+ items: [
+ { id: 'disabled-item-1', label: 'Item 1', value: 'item-1' },
+ { id: 'disabled-item-2', label: 'Item 2', value: 'item-2' },
+ ],
+ name: 'disabled',
+ },
+};
+
+export const Icons: Story = {
+ args: {
+ items: [
+ {
+ id: 'light-theme',
+ label: <Icon aria-label="Light theme" shape="sun" size="xs" />,
+ value: 'light-theme',
+ },
+ {
+ id: 'dark-theme',
+ label: <Icon aria-label="Dark theme" shape="moon" size="xs" />,
+ value: 'dark-theme',
+ },
+ ],
+ name: 'theme',
+ },
};