react-data-entry
v2.0.5
Published
React data entry components library
Maintainers
Readme
React Data Entry
Thư viện React components chuyên dụng cho việc nhập liệu dữ liệu (data entry), được tích hợp sẵn với React Hook Form và Ant Design, cung cấp các component tối ưu cho form validation và UI/UX hiện đại.
✨ Tính năng
- 🎯 16+ Components nhập liệu đa dạng và chuyên biệt
- 🔗 Tích hợp React Hook Form sẵn có với validation
- 🎨 Ant Design UI đẹp mắt và nhất quán
- 📱 Responsive hỗ trợ mọi kích thước màn hình
- ⚡ Performance tối ưu với React.memo và useCallback
- 🛡️ TypeScript hỗ trợ đầy đủ với type safety
- 🎛️ Flexible cấu hình linh hoạt cho mọi use case
- 🔧 Error Handling xử lý lỗi tự động và fallback UI
📦 Cài đặt
npm install react-data-entryyarn add react-data-entrypnpm add react-data-entryPeer Dependencies
Thư viện yêu cầu các dependencies sau:
npm install react react-dom react-hook-form🚀 Sử dụng cơ bản
Cách 1: Sử dụng RenderDataEntry (Khuyên dùng)
Component chính RenderDataEntry cung cấp cách sử dụng thống nhất cho tất cả các loại input:
import React from "react";
import { useForm } from "react-hook-form";
import { RenderDataEntry, KeyEditType } from "react-data-entry";
const MyForm = () => {
const hookForm = useForm();
const fieldConfig: KeyEditType = {
type: "text",
key: "username",
label: "Tên đăng nhập",
placeholder: "Nhập tên đăng nhập",
rules: { required: "Vui lòng nhập tên đăng nhập" },
width: "300px",
};
return (
<form onSubmit={hookForm.handleSubmit(console.log)}>
<RenderDataEntry data={fieldConfig} hookForm={hookForm} size="large" />
<button type="submit">Gửi</button>
</form>
);
};Cách 2: Sử dụng từng Component riêng lẻ
import React from "react";
import { useForm, Controller } from "react-hook-form";
import { CTextfield, CCalendar, CSelector } from "react-data-entry";
const MyForm = () => {
const { control, handleSubmit } = useForm();
return (
<form onSubmit={handleSubmit(console.log)}>
<Controller
name="username"
control={control}
rules={{ required: "Vui lòng nhập tên" }}
render={({ field, fieldState: { error } }) => (
<CTextfield
data={{
label: "Tên đăng nhập",
placeholder: "Nhập tên đăng nhập",
required: true,
message: error?.message,
}}
field={field}
size="large"
/>
)}
/>
</form>
);
};📋 Danh sách Components
| Component | Type | Mô tả |
| ---------------- | ------------ | ------------------------------------ |
| CTextfield | text | Input text cơ bản |
| CInputNumber | number | Input số với validation |
| CTextarea | textarea | Textarea nhiều dòng |
| CPassword | password | Input mật khẩu với toggle visibility |
| CSwitch | switch | Switch on/off |
| CCalendar | date | Date picker |
| CRangeCalendar | range-date | Date range picker |
| CTime | time | Time picker |
| CSelector | select | Dropdown select (single/multiple) |
| CCurrency | currency | Input tiền tệ với format |
| CEditor | editor | Rich text editor (Quill) |
| CUpload | upload | File upload với preview |
| CRadio | radio | Radio button group |
| CLink | link | Link input với validation URL |
| CColorPicker | color | Color picker |
🔧 Cấu hình Field Data
Interface KeyEditType
interface KeyEditType {
type: RenderDataEntryType; // Loại component
key: string; // Field name
label: string; // Nhãn hiển thị
role?: any[] | null; // Phân quyền (nếu có)
width?: string; // Chiều rộng
placeholder?: string; // Placeholder text
direction?: "row" | "column"; // Hướng layout
labelWidth?: string; // Chiều rộng label
rules?: any; // Validation rules
disabled?: boolean; // Vô hiệu hóa
defaultValue?: any; // Giá trị mặc định
// Cho số và currency
max?: number;
min?: number;
suffix?: string;
// Cho date
min_date?: string;
max_date?: string;
picker?: "week" | "month" | "year" | "quarter";
formatCalendar?: string;
// Cho select
type_select?: "multiple" | "single";
options?: any[];
// Cho textfield
type_text?: "text" | "number";
// Cho upload
uploadImage?: any;
length_img?: number;
}📝 Ví dụ chi tiết
1. Text Input với Validation
const textConfig: KeyEditType = {
type: "text",
key: "fullName",
label: "Họ và tên",
placeholder: "Nhập họ và tên đầy đủ",
rules: {
required: "Vui lòng nhập họ và tên",
minLength: {
value: 2,
message: "Tên phải có ít nhất 2 ký tự",
},
},
width: "100%",
direction: "column",
};2. Number Input với Min/Max
const numberConfig: KeyEditType = {
type: "number",
key: "age",
label: "Tuổi",
placeholder: "Nhập tuổi",
min: 18,
max: 100,
rules: {
required: "Vui lòng nhập tuổi",
min: { value: 18, message: "Tuổi phải từ 18 trở lên" },
},
};3. Date Picker với Range
const dateConfig: KeyEditType = {
type: "date",
key: "birthDate",
label: "Ngày sinh",
picker: "date",
formatCalendar: "DD/MM/YYYY",
min_date: "1900-01-01",
max_date: new Date().toISOString().split("T")[0],
rules: { required: "Vui lòng chọn ngày sinh" },
};4. Select với Options
const selectConfig: KeyEditType = {
type: "select",
key: "skills",
label: "Kỹ năng",
type_select: "multiple",
options: [
{ label: "React", value: "react" },
{ label: "Vue", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Node.js", value: "nodejs" },
],
placeholder: "Chọn kỹ năng của bạn",
};5. Currency Input
const currencyConfig: KeyEditType = {
type: "currency",
key: "salary",
label: "Mức lương mong muốn",
suffix: "VNĐ",
min: 0,
max: 100000000,
placeholder: "Nhập mức lương",
};6. Rich Text Editor
const editorConfig: KeyEditType = {
type: "editor",
key: "description",
label: "Mô tả chi tiết",
placeholder: "Nhập mô tả...",
rules: {
required: "Vui lòng nhập mô tả",
validate: (value: string) => {
const textLength = value.replace(/<[^>]*>/g, "").length;
if (textLength < 10) return "Mô tả phải có ít nhất 10 ký tự";
return true;
},
},
};7. File Upload
const uploadConfig: KeyEditType = {
type: "upload",
key: "avatar",
label: "Ảnh đại diện",
length_img: 1,
uploadImage: {
accept: "image/*",
maxSize: 5 * 1024 * 1024, // 5MB
listType: "picture-card",
},
};🎨 Styling và Customization
Custom CSS Classes
/* Custom styles */
.custom-form-field {
margin-bottom: 16px;
}
.custom-form-field .ant-form-item-label {
font-weight: 600;
}
.custom-form-field .ant-input {
border-radius: 8px;
}Sử dụng className
const fieldConfig: KeyEditType = {
type: "text",
key: "username",
label: "Username",
// className sẽ được áp dụng cho field container
};🌟 Form hoàn chỉnh
import React from "react";
import { useForm } from "react-hook-form";
import { RenderDataEntry, KeyEditType } from "react-data-entry";
const UserRegistrationForm = () => {
const hookForm = useForm();
const formFields: KeyEditType[] = [
{
type: "text",
key: "username",
label: "Tên đăng nhập",
placeholder: "Nhập tên đăng nhập",
rules: { required: "Vui lòng nhập tên đăng nhập" },
},
{
type: "password",
key: "password",
label: "Mật khẩu",
placeholder: "Nhập mật khẩu",
rules: {
required: "Vui lòng nhập mật khẩu",
minLength: { value: 6, message: "Mật khẩu ít nhất 6 ký tự" },
},
},
{
type: "text",
key: "email",
label: "Email",
placeholder: "Nhập email",
rules: {
required: "Vui lòng nhập email",
pattern: {
value: /^\S+@\S+$/i,
message: "Email không hợp lệ",
},
},
},
{
type: "date",
key: "birthDate",
label: "Ngày sinh",
picker: "date",
rules: { required: "Vui lòng chọn ngày sinh" },
},
{
type: "select",
key: "gender",
label: "Giới tính",
type_select: "single",
options: [
{ label: "Nam", value: "male" },
{ label: "Nữ", value: "female" },
{ label: "Khác", value: "other" },
],
},
];
const onSubmit = (data: any) => {
console.log("Form Data:", data);
};
return (
<form onSubmit={hookForm.handleSubmit(onSubmit)}>
<div style={{ display: "grid", gap: "16px", maxWidth: "600px" }}>
{formFields.map((field) => (
<RenderDataEntry
key={field.key}
data={field}
hookForm={hookForm}
size="large"
/>
))}
</div>
<div style={{ marginTop: "24px" }}>
<button
type="submit"
style={{
padding: "12px 24px",
backgroundColor: "#1890ff",
color: "white",
border: "none",
borderRadius: "6px",
cursor: "pointer",
}}
>
Đăng ký
</button>
</div>
</form>
);
};
export default UserRegistrationForm;🔧 Props Reference
RenderDataEntry Props
| Prop | Type | Default | Mô tả |
| ---------------- | -------------------------------- | --------- | ------------------------ |
| data | KeyEditType | - | Cấu hình field |
| hookForm | object | - | React Hook Form instance |
| disabled | boolean | false | Vô hiệu hóa field |
| size | 'large' \| 'middle' \| 'small' | 'large' | Kích thước component |
| customOnChange | function | - | Custom onChange handler |
Common Field Props
| Prop | Type | Default | Mô tả |
| ------------- | ------------------- | ---------- | ------------------ |
| label | string | - | Nhãn field |
| placeholder | string | - | Placeholder text |
| width | string | '100%' | Chiều rộng |
| direction | 'row' \| 'column' | 'column' | Layout direction |
| labelWidth | string | - | Chiều rộng label |
| disabled | boolean | false | Trạng thái disable |
| required | boolean | false | Bắt buộc nhập |
🚨 Error Handling
Thư viện có hệ thống xử lý lỗi tự động:
// Error Boundary tự động bắt lỗi render
<ErrorBoundary fallback={<div>Có lỗi xảy ra</div>}>
<RenderDataEntry data={fieldConfig} hookForm={hookForm} />
</ErrorBoundary>;
// Validation errors từ React Hook Form
const rules = {
required: "Trường này bắt buộc",
validate: (value) => {
if (!value) return "Giá trị không hợp lệ";
return true;
},
};🏗️ Development
Build từ source
# Clone repository
git clone https://github.com/HiNT89/react-data-entry.git
cd react-data-entry
# Install dependencies
npm install
# Build
npm run build
# Pack for testing
npm run pack:localProject Structure
src/
├── components/ # Shared components
├── types/ # TypeScript definitions
├── utils/ # Utility functions
├── *.tsx # Main components
├── styles.css # Global styles
└── index.tsx # Main exports📄 License
ISC License - xem file LICENSE để biết thêm chi tiết.
🤝 Contributing
Contributions are welcome! Vui lòng đọc CONTRIBUTING.md để biết hướng dẫn chi tiết.
📞 Support
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
- 📧 Email: [email protected]
Được phát triển bởi HiNT với ❤️
