From 54f4572533ef5e256e98a7a12cd3027f9e5cef89 Mon Sep 17 00:00:00 2001 From: Hafid Nur Date: Thu, 27 Mar 2025 05:25:02 +0700 Subject: [PATCH] feat: Update InputForm component - Perbarui docs untuk component Input dan InputForm - Perbarui component InputForm agar bekerja dengan helper text, error, dan label/input --- libs/ui/src/atoms/input/input.stories.tsx | 8 -- libs/ui/src/atoms/input/input.tsx | 24 ++---- .../input-form/input-form.stories.tsx | 80 ++++++++++++++++--- .../src/molecules/input-form/input-form.tsx | 24 +++++- 4 files changed, 99 insertions(+), 37 deletions(-) diff --git a/libs/ui/src/atoms/input/input.stories.tsx b/libs/ui/src/atoms/input/input.stories.tsx index 7bea8f5..43ba621 100644 --- a/libs/ui/src/atoms/input/input.stories.tsx +++ b/libs/ui/src/atoms/input/input.stories.tsx @@ -61,11 +61,3 @@ export const Disabled: Story = { disabled: true, }, }; - -export const WithError: Story = { - args: { - size: 'md', - type: 'text', - error: 'This field is required', - }, -}; diff --git a/libs/ui/src/atoms/input/input.tsx b/libs/ui/src/atoms/input/input.tsx index 3a80d49..da288f5 100644 --- a/libs/ui/src/atoms/input/input.tsx +++ b/libs/ui/src/atoms/input/input.tsx @@ -15,7 +15,6 @@ type TInputProps = Omit< > & { type?: TInputType; size?: TInputSize; - error?: string; }; const sizeClasses: Record = { @@ -25,15 +24,12 @@ const sizeClasses: Record = { }; const disabledClass = 'opacity-50 hover:border-neutral-200 cursor-not-allowed'; -const errorClass = - 'border-danger-500 hover:border-danger-500 focus:outline-danger-500'; export const Input: FC = ({ size = 'md', - type, + type = 'text', placeholder = 'Placeholder', disabled, - error, className, ...rest }): ReactElement => { @@ -41,20 +37,16 @@ export const Input: FC = ({ 'px-[12px] py-[8px] text-neutral-800 placeholder:text-neutral-300 border border-neutral-200 hover:border-blue-300 focus:outline-1 focus:outline-blue-500 rounded-md font-bai-jamjuree', sizeClasses[size], disabled && disabledClass, - error && errorClass, className ); return ( - <> - - {error &&

{error}

} - + ); }; diff --git a/libs/ui/src/molecules/input-form/input-form.stories.tsx b/libs/ui/src/molecules/input-form/input-form.stories.tsx index e74538c..53dd42c 100644 --- a/libs/ui/src/molecules/input-form/input-form.stories.tsx +++ b/libs/ui/src/molecules/input-form/input-form.stories.tsx @@ -6,6 +6,25 @@ const meta = { component: InputForm, parameters: { layout: 'centered', + docs: { + description: { + component: ` +Komponen input form yang menggabungkan label dengan kolom input. + +## Aksesibilitas +Ketika prop \`htmlFor\` disediakan: +- Atribut \`htmlFor\` pada label akan diatur ke nilai tersebut +- Atribut \`id\` pada input akan otomatis diatur ke nilai yang sama +- Ini menciptakan asosiasi label-input yang tepat untuk aksesibilitas + +Cek dan inspect element pada story With HtmlFor untuk melihat hasilnya. + +## Helper Text dan Error +- Jika prop \`error\` disediakan, akan ditampilkan dalam warna merah di bawah input +- Jika prop \`helperText\` disediakan dan tidak ada error, akan ditampilkan dalam warna abu-abu di bawah input + `, + }, + }, }, tags: ['autodocs'], } satisfies Meta; @@ -13,6 +32,33 @@ const meta = { export default meta; type Story = StoryObj; +export const Large: Story = { + args: { + label: 'Description', + placeholder: 'Enter description', + type: 'text', + size: 'lg', + }, +}; + +export const Medium: Story = { + args: { + label: 'Address', + placeholder: 'Enter your address', + type: 'text', + size: 'md', + }, +}; + +export const Small: Story = { + args: { + label: 'Phone', + placeholder: 'Enter your phone number', + type: 'text', + size: 'sm', + }, +}; + export const Default: Story = { args: { label: 'Email', @@ -22,6 +68,25 @@ export const Default: Story = { }, }; +export const WithHelperText: Story = { + args: { + label: 'Email', + placeholder: 'Enter your email', + type: 'email', + size: 'md', + helperText: 'We will never share your email', + }, +}; + +export const WithoutHelperText: Story = { + args: { + label: 'Password', + placeholder: 'Enter your password', + type: 'text', + size: 'md', + }, +}; + export const WithError: Story = { args: { label: 'Username', @@ -32,20 +97,13 @@ export const WithError: Story = { }, }; -export const Large: Story = { +export const WithHtmlFor: Story = { args: { label: 'Full Name', placeholder: 'Enter your full name', type: 'text', - size: 'lg', - }, -}; - -export const Small: Story = { - args: { - label: 'Phone', - placeholder: 'Enter your phone number', - type: 'text', - size: 'sm', + size: 'md', + htmlFor: 'fullname-input', + helperText: 'Enter your legal full name', }, }; diff --git a/libs/ui/src/molecules/input-form/input-form.tsx b/libs/ui/src/molecules/input-form/input-form.tsx index 26d080e..1aa625c 100644 --- a/libs/ui/src/molecules/input-form/input-form.tsx +++ b/libs/ui/src/molecules/input-form/input-form.tsx @@ -5,6 +5,7 @@ import { ReactElement, } from 'react'; import { Input } from '../../atoms'; +import { cn } from '@imphnen-frontend-service/utils'; type TInputType = 'text' | 'email'; type TInputSize = 'sm' | 'md' | 'lg'; @@ -17,6 +18,8 @@ type TInputFormProps = Omit< type?: TInputType; size?: TInputSize; error?: string; + helperText?: string; + htmlFor?: string; }; export const InputForm: FC = ({ @@ -25,18 +28,35 @@ export const InputForm: FC = ({ type = 'text', size = 'md', error, + helperText, + htmlFor, + className, ...rest }): ReactElement => { return (
-
{label}
+ + {error ? ( +

{error}

+ ) : ( + helperText && ( +

{helperText}

+ ) + )}
); };