تخطّي إلى المحتوى الرئيسي

نموذج Form

مكوّن مركّب من LhForm + LhFormItem، يوفّر التحقق من البيانات وعرض الأخطاء ومحاذاة العلامات وغيرها من القدرات.

الاستخدام الأساسي​

نموذج بالتحقق
import { useRef, useState } from 'react'
import { LhButton, LhForm, LhFormItem, LhInput, LhSelect } from '@lh-ui/react'
import type { LhFormInstance, LhFormRule } from '@lh-ui/react'

interface FormData {
name: string
style: string
}

const rules: Record<string, LhFormRule[]> = {
name: [{ required: true, message: 'يرجى إدخال اسم العمل', trigger: 'blur' }],
style: [{ required: true, message: 'يرجى اختيار أسلوب الرسم', trigger: 'change' }],
}

export default function Demo() {
const [formData, setFormData] = useState<FormData>({ name: '', style: '' })
const formRef = useRef<LhFormInstance>(null)

const handleSubmit = async () => {
const valid = await formRef.current?.validate()
if (valid) alert(`تم الإرسال بنجاح: ${formData.name} / ${formData.style}`)
}

const handleReset = () => {
formRef.current?.resetFields()
setFormData({ name: '', style: '' })
}

return (
<LhForm ref={formRef} model={formData} rules={rules} labelWidth="80px">
<LhFormItem label="اسم العمل" prop="name">
<LhInput
value={formData.name}
onChange={(val) => setFormData((prev) => ({ ...prev, name: val }))}
/>
</LhFormItem>
<LhFormItem label="أسلوب الرسم" prop="style">
<LhSelect
value={formData.style}
onChange={(val) => setFormData((prev) => ({ ...prev, style: val as string }))}
options={[{ label: 'رسم الحبر', value: 'ink' }]}
/>
</LhFormItem>
<LhFormItem>
<LhButton type="primary" onClick={handleSubmit}>إرسال</LhButton>
<LhButton onClick={handleReset}>إعادة تعيين</LhButton>
</LhFormItem>
</LhForm>
)
}

خصائص Form​

خاصيةالوصفالنوعالافتراضي
modelكائن بيانات النموذج (مطلوب)Record<string, unknown>—
rulesقواعد التحقق، ومفاتيحها هي أسماء الحقولRecord<string, LhFormRule[]>—
labelWidthعرض العلامةstring | number—
labelPositionموضع العلامة'left' | 'right' | 'top''right'
inlineتخطيط سطريbooleanfalse
disabledتعطيل جميع العناصر الفرعيةbooleanfalse
sizeحجم العناصر الفرعية'large' | 'middle' | 'small'يتبع ConfigProvider
onSubmitحدث الإرسال الأصلي (مع تطبيق preventDefault)(event: FormEvent) => void—

خصائص FormItem​

خاصيةالوصفالنوعالافتراضي
labelنص العلامةstring—
propاسم الحقل (يدعم مسار النقاط، ويقابل مفتاحًا في model)string—
rulesقواعد على مستوى العنصر (تتجاوز قواعد مستوى form عند تطابق الاسم)LhFormRule[]—
requiredنجمة الحقل المطلوب (تعرض العلامة فقط، بينما تأتي دلالة التحقق من rules)booleanfalse
labelWidthتتجاوز عرض العلامة على مستوى formstring | number—
errorMessageرسالة خطأ مخصصةstring—
showMessageإظهار رسالة الخطأbooleantrue

LhFormRule​

خاصيةالوصفالنوع
requiredهل الحقل مطلوبboolean
messageرسالة فشل التحققstring
triggerطريقة التشغيل'blur' | 'change'
validatorدالة تحقق مخصصة (يمكن أن تُرجع Promise، وينتظر التحقق غير المتزامن بشكل صحيح)(value, model) => string | undefined | Promise<string | undefined>
min / maxالحد الأدنى / الأقصى (قيمة رقمية أو طول)number
patternتحقق بالتعبير النمطيRegExp

دوال ref الخاصة بـ Form​

LhFormInstance (تُكشف عبر forwardRef + useImperativeHandle):

دالةالوصفالقيمة المعادة
validateالتحقق من جميع الحقولPromise<boolean>
validateFieldالتحقق من حقل واحدPromise<boolean>
resetFieldsإعادة تعيين جميع الحقول إلى قيمها الأوليةvoid
resetFieldإعادة تعيين حقل واحدvoid
const formRef = useRef<LhFormInstance>(null)
const ok = await formRef.current?.validate()
التحقق غير المتزامن

صحّحت هذه المكتبة عيوب التحقق غير المتزامن في plus: فدالة validateField في plus تستخدم Promise.resolve(!message) ولا تنتظر Promise الخاص بالمدقق غير المتزامن، فيُرجع التحقق غير المتزامن true دائمًا. أما نسخة React فتنتظر صراحة اكتمال الـ thenable قبل الحكم. راجع دليل الترحيل.

تسجيل الحقول

يُسجّل LhFormItem المُدقّق في form داخل useEffect، ويُلغى تسجيله تلقائيًا عند إلغاء التركيب. ولا حاجة للتصريح المسبق بالحقول في rules — فالحقول الموجودة في model دون rules تُلتقط قيمها الأولية عند التسجيل.

دلالة trigger (تحسين React)

لا تفسر validateFormField في share قيمة trigger، بل يتولى هذا المستوى تحديد وقت التشغيل: فقيمة trigger: 'blur' (الافتراضية) تُجري التحقق عند فقدان التركيز على FormItem، وقيمة trigger: 'change' عند تغيّر منطقة المحتوى. أما القواعد التي لا تحمل trigger فتُشغَّل فقط عند فقد التركيز وعند استدعاء validate()، ولا تظهر الأخطاء بشكل متكرر أثناء الإدخال.

ويأخذ التحقق عند change القيمة الجديدة لهدف الحدث وليس لقطة model — فتحديثات الحالة وإرسال الأحداث في React لا تحدث في الدورة نفسها، والرجوع إلى model سيتأخر دورة واحدة. وتُلتقط أحداث change الخاصة بعناصر التحكم الأصلية (input / textarea / select الأصلي) عند صعودها إلى منطقة المحتوى؛ أما عناصر التحكم المخصصة فلا تمتلك حدث change أصليًا (نقر خيار LhSelect يُنتج click فقط)، لذلك يُطلَق validateChange(value) عبر سياق FormItem حاملًا القيمة الجديدة صراحة.

مسح الأخطاء عند إعادة التعيين (تحسين React)

بالإضافة إلى إعادة model إلى لقطة قيمه الأولية، تُزيد resetFields() العدّاد الداخلي resetVersion، فيُلاحظ كل FormItem تغيّر الإصدار ويمسح حالة الخطأ الخاصة به. ولا تزال الحالة المُتحكم بها الخارجية بحاجة إلى المزامنة يدويًا (مثل setFormData(initial) في العرض التوضيحي) — فـ React لا يستطيع كتابة model نيابة عنك كما يفعل سلسلة reactive في Vue.

الأنماط​

import '@lh-ui/react/style/form'