feat: enhance form item component with status handling and styling for error/warning states
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
// form-item.component.tsx
|
||||
import React, { ReactElement } from 'react';
|
||||
import { Field } from '@rc-component/form';
|
||||
import { FormItemProps } from '../types';
|
||||
@@ -9,35 +8,41 @@ export default function FormItem(props: FormItemProps) {
|
||||
return (
|
||||
<Field name={name} rules={rules} valuePropName={valuePropName} initialValue={initialValue}>
|
||||
{(control, meta) => {
|
||||
// Defensive check: tambahkan ?. untuk keamanan di versi baru
|
||||
// Defensive check
|
||||
const hasError = meta.errors && meta.errors.length > 0;
|
||||
const hasWarning = meta.warnings && meta.warnings.length > 0;
|
||||
|
||||
// Determine status
|
||||
const status = OverrideStatus ?? (hasError ? 'error' : hasWarning ? 'warning' : 'normal');
|
||||
|
||||
// Logic Clone Element
|
||||
const isValid = React.isValidElement(children);
|
||||
const childElement = isValid ? (children as ReactElement<{ status?: any }>) : null;
|
||||
|
||||
// Clone element logic tetap dipertahankan
|
||||
// Pass status to child (Input/Textarea) so their borders change color
|
||||
const childNode = childElement ? React.cloneElement(childElement, { ...control, status }) : children;
|
||||
|
||||
// Logic pengecekan 'required' pada rules
|
||||
// Note: Pastikan rule object memiliki properti 'required', karena Rule juga bisa berupa function.
|
||||
// Logic Required Check
|
||||
const isRequired = rules?.some((r: any) => r && typeof r === 'object' && r.required);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col mb-4 w-full">
|
||||
// Wrapper Div with status class
|
||||
<div className={`rc-form-item status-${status}`}>
|
||||
{/* LABEL SECTION */}
|
||||
{label && (
|
||||
<label className={`mb-1.5 text-sm font-medium ${hasError ? 'text-red-500' : 'text-gray-700'}`}>
|
||||
<label className="rc-form-item-label">
|
||||
{label}
|
||||
{isRequired && <span className="ml-1 text-red-500">*</span>}
|
||||
{isRequired && <span className="rc-form-item-required-mark">*</span>}
|
||||
</label>
|
||||
)}
|
||||
|
||||
<div className="relative">{childNode}</div>
|
||||
{/* INPUT CONTROL */}
|
||||
<div className="rc-form-item-control relative">{childNode}</div>
|
||||
|
||||
{hasError && <p className="mt-1.5 text-xs text-red-500">{meta.errors[0]}</p>}
|
||||
{hasWarning && <p className="mt-1.5 text-xs text-yellow-500">{meta.warnings[0]}</p>}
|
||||
{/* ERROR / WARNING MESSAGE */}
|
||||
{(hasError || hasWarning) && (
|
||||
<div className="rc-form-item-explain">{hasError ? meta.errors[0] : meta.warnings[0]}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
@layer components {
|
||||
/* Container Form Item */
|
||||
.rc-form-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
margin-bottom: var(--form-item-margin-bottom);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
LABEL
|
||||
========================= */
|
||||
.rc-form-item-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: var(--form-label-font-size);
|
||||
font-weight: var(--form-label-font-weight);
|
||||
color: var(--form-label-color);
|
||||
margin-bottom: var(--form-label-margin-bottom);
|
||||
line-height: 1.4;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
/* Required Asterisk (*) */
|
||||
.rc-form-item-required-mark {
|
||||
margin-left: 0.25rem;
|
||||
color: var(--color-error-500);
|
||||
font-family: SimSun, sans-serif; /* Standard font for asterisks agar vertical align bagus */
|
||||
}
|
||||
|
||||
/* =========================
|
||||
MESSAGE (ERROR / WARNING)
|
||||
========================= */
|
||||
.rc-form-item-explain {
|
||||
margin-top: var(--form-msg-margin-top);
|
||||
font-size: var(--form-msg-font-size);
|
||||
line-height: 1.4;
|
||||
min-height: 1.4em; /* Mencegah layout jumping jika error muncul/hilang */
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
STATUS MODIFIERS
|
||||
========================= */
|
||||
|
||||
/* --- ERROR STATE --- */
|
||||
.rc-form-item.status-error .rc-form-item-label {
|
||||
color: var(--color-error-600); /* Label jadi merah saat error (opsional UI pattern) */
|
||||
}
|
||||
.rc-form-item.status-error .rc-form-item-explain {
|
||||
color: var(--color-error-500);
|
||||
}
|
||||
|
||||
/* --- WARNING STATE --- */
|
||||
.rc-form-item.status-warning .rc-form-item-label {
|
||||
color: var(--color-warning-600);
|
||||
}
|
||||
.rc-form-item.status-warning .rc-form-item-explain {
|
||||
color: var(--color-warning-500);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
@import './form-item.style.css';
|
||||
@import './input.style.css';
|
||||
@import './input-number.style.css';
|
||||
|
||||
@import './textarea.style.css';
|
||||
|
||||
Reference in New Issue
Block a user