UI Components (@vppos/core/ui/react)
Tất cả shared UI components nằm trong @vppos/core/ui/react.
import { Button, Input, Select, Modal, Table, Toggle } from "@vppos/core/ui/react";
Storybook
Xem demo trực quan tất cả components trên Storybook.
pnpm --filter @vppos/core storybook # http://localhost:6006
Nếu docs site không host Storybook cùng domain, tránh dùng link tương đối như
/storybook/để không bị broken link khi build docs.
Danh sách components
Form Controls
| Component | Mô tả | Storybook |
|---|---|---|
Button | 7 variants (primary, secondary, warning, error, ghost, outline, dash), 3 sizes, loading, icons | ✅ |
Input | Input text với label, error, helper, icons, password toggle, clear | ✅ |
SearchInput | Input tìm kiếm (preset của Input) | ✅ |
Select | Dropdown select (single & multi), floating-ui, clear | ✅ |
Toggle | Switch on/off, 4 sizes (sm, md, lg, xl) | ✅ |
Checkbox | Checkbox với 3 sizes, indeterminate support | ✅ |
NumberInput | Input số với prefix/suffix, format VND tự động | ✅ |
TagInput | Input tags, thêm/xóa tag, Enter để thêm | ✅ |
ColorPicker | Chọn màu với Chrome picker, hex display | ✅ |
FileUpload | Upload file, kéo thả, progress bar, preview | ✅ |
DatePicker | Date picker với Calendar, min/max, footer | ✅ |
TimePicker | Time picker cuộn giờ/phút, step tuỳ chỉnh | ✅ |
RichTextEditor | WYSIWYG editor (react-quill), toolbar tuỳ chỉnh | ✅ |
FilterBar | Thanh bộ lọc nhanh với nhiều loại filter (select, range, date...) | ✅ |
FilterDrawer | Panel bộ lọc nâng cao tích hợp trong Drawer, hỗ trợ cấu hình filter linh hoạt | ✅ |
Data Display
| Component | Mô tả | Storybook |
|---|---|---|
Table | Bảng dữ liệu responsive, tự động chuyển sang card trên mobile; hỗ trợ renderMobileCard để tùy biến UI | ✅ |
TableMobileCard | Component nội bộ hiển thị card mobile (Mặc định: danh sách Label-Value; Tùy biến: Level 3 API) | ✅ |
Pagination | Phân trang có ellipsis, items-per-page | ✅ |
StatusBadge | Badge trạng thái (active, inactive, pending, draft, deleted) | ✅ |
Avatar | Avatar user, 7 sizes, circle/square, loading skeleton | ✅ |
ImageDisplay | Hiển thị ảnh với fallback icon, nhiều size/shape | ✅ |
Skeleton | Loading placeholder (shimmer animation) | ✅ |
EmptyState | Trạng thái trống (no data, no search results) | ✅ |
StatCards | Grid các thẻ thống kê (doanh thu, đơn hàng...) | ✅ |
OverviewStatCard | Thẻ tổng quan với trend badge, info badge | ✅ |
Table — Mobile mode
Table mặc định sẽ tự động chuyển sang dạng card (Label: Value) khi màn hình nhỏ. Để tùy biến hoàn toàn, dùng prop renderMobileCard:
// 1. Mặc định (Auto Columns) - không cần làm gì thêm
<Table columns={columns} data={data} />
// 2. Tùy biến (Custom Render) - dùng JSX riêng
<Table
columns={columns}
data={orders}
renderMobileCard={(order) => (
<div className="rounded-xl border border-gray-100 bg-white p-4 shadow-sm">
<div className="flex items-start justify-between gap-3">
<h3 className="text-lg font-medium">{order.customerName}</h3>
<Badge>{order.status}</Badge>
</div>
<p className="mt-2 text-sm text-gray-500">25/10/2025</p>
<div className="mt-4 flex items-center justify-between">
<span className="text-xl font-medium">{formatCurrency(order.total)}</span>
<div className="flex gap-2">
<Button onClick={() => handleEdit(order)}>Sửa</Button>
<Button variant="outline" onClick={() => handleDelete(order)}>Xóa</Button>
</div>
</div>
</div>
)}
/>
Feedback
| Component | Mô tả | Storybook |
|---|---|---|
Modal | Dialog modal, 6 sizes, 7 icon types | ✅ |
ConfirmDeleteModal | Modal xác nhận xóa (preset) | ✅ |
ConfirmLockModal | Modal xác nhận khoá (preset) | ✅ |
ConfirmUnlockModal | Modal xác nhận mở khoá (preset) | ✅ |
Drawer | Panel trượt từ cạnh (left/right), nhiều sizes | ✅ |
Tooltip | Tooltip dark/light, 4 positions, rich content | ✅ |
Dropdown | Menu dropdown (click trigger, floating-ui) | ✅ |
GlobalLoading | Loading overlay toàn màn hình, spinner + logo | ✅ |
UnderDevelopment | Trang "đang phát triển" với ảnh + action | ✅ |
Layout
| Component | Mô tả | Storybook |
|---|---|---|
Stepper | Step-by-step wizard, interactive, home button | ✅ |
TabPanel | Tabs điều hướng, responsive, dropdown overflow | 🔜 |
ColumnVisibilityModal | Ẩn/hiện cột table | 🔜 |
Quy tắc
- Luôn dùng component từ core — không tự tạo lại
- Nếu cần component mới → đề xuất trước → thêm vào core → export
- Không copy code vào từng app