<Cthuvien:tab> - <BSSTab>
Mô tả
BSSTab là component UI điều hướng dạng tab, thay thế cho <Cthuvien:tab> cũ. Trong hệ thống cũ, để tạo tab, bạn phải tạo các thẻ <Cthuvien:tab> nằm rời rạc trong table, sau đó tạo các thẻ <div> nội dung bên dưới, và dùng hàm P_TAB() ghép nối chúng lại thông qua các quy tắc đặt tên ID rất phức tạp (T_pn_1, _pn_1).
Trong kiến trúc React mới, BSSTab sử dụng mô hình Compound Component (BSSTab bao bọc BSSTab.Pane). Bạn chỉ cần khai báo một cấu trúc duy nhất, gọn gàng. Component tự động trích xuất thông tin nhãn (label), icon, và nội dung (children) từ các thẻ Pane để sinh ra giao diện tab hoàn chỉnh.
Điểm nổi bật:
- Tự động quản lý State: Chuyển đổi tab bằng state React nội bộ (
internalValue), loại bỏ hoàn toàn việc can thiệp DOM thủ công (ẩn/hiện styledisplay). - Giao diện đa dạng: Hỗ trợ 2 kiểu (
linegạch chân,pillsnút bo tròn) và 2 bố cục (ngang chuẩn, hoặctabVerticaldọc). - Trải nghiệm phím tắt (A11y): Hỗ trợ dùng phím mũi tên
←→↑↓để chuyển qua lại giữa các tab (bỏ qua các tab bịdisabled). - Tự động dịch thuật: Thuộc tính
labeldạng chuỗi sẽ được tự động dịch sang đa ngôn ngữ.
Thuộc tính
So sánh cơ chế cũ và mới
| <Cthuvien:tab> Cũ | <BSSTab> Mới | Mô tả / Chú ý khi chuyển đổi |
|---|---|---|
Quy tắc ID (T_pn_1) | value / onChange | Cũ: Ép buộc đặt ID theo quy tắc để auto-resolve nhóm tab. Mới: Dùng React state (Controlled) hoặc để component tự quản lý (Uncontrolled). |
Text | label (trên Pane) | Cũ: Gán text lên từng control tab. Mới: Truyền label vào từng thẻ BSSTab.Pane. |
paId (ID panel) | Component children | Cũ: Phải tạo div nội dung riêng và trỏ paId. Mới: Nhét trực tiếp nội dung vào trong lòng thẻ BSSTab.Pane. |
hinh | icon (trên Pane) | Cũ: Đường dẫn ảnh nền tab. Mới: Render icon SVG trực tiếp bằng các thư viện như lucide-react. |
ham | onChange / onClick | Cũ: Chuỗi tên hàm JS. Mới: Callback onChange(id) trên thẻ cha hoặc onClick trên từng thẻ con. |
Các thuộc tính của Container <BSSTab>
| Tên | Kiểu | Mặc định | Có thể có | Mục đích |
|---|---|---|---|---|
children | ReactNode | <BSSTab.Pane> | Các thẻ con. Bắt buộc phải là BSSTab.Pane. | |
value | string | ID của Pane | ID của tab đang mở (Controlled mode). | |
defaultValue | string | ID của Pane | ID của tab mở mặc định lúc ban đầu (Uncontrolled mode). Nếu không truyền, tự mở tab đầu tiên không bị disabled. | |
onChange | function | (id: string) => void | Sự kiện bắn ra khi người dùng chuyển sang tab khác. | |
variant | string | 'line' | 'line', 'pills' | Kiểu giao diện. 'line' (chỉ có gạch chân), 'pills' (dạng khối màu). |
size | string | 'sm' | 'sm', 'md' | Kích thước của thanh header tab. |
fullWidth | bool | false | true / false | Ép các nút tab dàn trải đều toàn bộ chiều ngang (dùng flex-1). |
tabVertical | bool | false | true / false | Xoay dọc: Thanh chọn tab nằm bên trái, nội dung nằm bên phải. |
className | string | '' | Class CSS bổ sung cho container ngoài cùng. |
Các thuộc tính của Panel con <BSSTab.Pane>
| Tên | Kiểu | Bắt buộc | Mục đích |
|---|---|---|---|
id | string | Có | Định danh của tab. Khớp với value hoặc defaultValue của thẻ cha. |
label | string / ReactNode | Có | Chữ hiển thị trên nút tab. Nếu là chuỗi, hệ thống tự động dịch. |
icon | ReactNode | Icon hiển thị bên trái chữ. | |
badge | ReactNode | Nhãn đếm số lượng (Ví dụ: 150) hiển thị bên phải chữ. | |
disabled | bool | Nếu true, nút tab bị làm mờ, không thể click và bỏ qua khi bấm phím tắt. | |
onClick | function | Hàm gọi khi tab này được click. | |
children | ReactNode | Nội dung của panel. |
Hoạt động phía Client
- Bóc tách tự động: Khi render,
BSSTabdùngReact.Childrenduyệt qua tất cả các thẻBSSTab.Panecon để trích xuấtid,label,icon... nhằm vẽ lên thanh header tab (Tab List). Phầnchildrenbên trongPanesẽ được gom lại thành nội dung (Tab Content). - Phím tắt điều hướng: Khi người dùng focus vào vùng tab header:
- Phím
ArrowRighthoặcArrowDown: Chuyển sang tab kế tiếp. - Phím
ArrowLefthoặcArrowUp: Quay về tab trước đó. - Hệ thống tự động bỏ qua (skip) các vòng lặp đối với các tab đang có cờ
disabled.
- Phím
- Render nội dung (ẩn/hiện): Nội dung của tất cả các tab vẫn luôn được mount trong DOM, nhưng những tab không active sẽ bị ẩn đi thông qua class
hiddencủa Tailwind (display: none). Điều này đảm bảo state của các form bên trong tab không bị mất khi chuyển qua chuyển lại.
Ví dụ
1. Tab cơ bản (Kiểu Line):
<BSSTab defaultValue="tab1" onChange={(id) => console.log('Đổi sang tab:', id)}>
<BSSTab.Pane id="tab1" label="Thông tin chung">
{/* Các BSSInput nhập liệu... */}
<FormThongTinChung />
</BSSTab.Pane>
<BSSTab.Pane id="tab2" label="Lương & phụ cấp">
<FormLuong />
</BSSTab.Pane>
<BSSTab.Pane id="tab3" label="Hồ sơ" disabled={true}>
{/* Bị vô hiệu hóa, không nhấn vào được */}
<div>Đang cập nhật...</div>
</BSSTab.Pane>
</BSSTab>
2. Tab dạng Pills (nút khối) với Icon và Badge báo số lượng:
import { List, Clock, Check } from 'lucide-react';
<BSSTab variant="pills" size="md" fullWidth={true}>
<BSSTab.Pane id="all" label="Tất cả" icon={<List size={14} />} badge={150}>
<DanhSachTatCa />
</BSSTab.Pane>
<BSSTab.Pane id="pending" label="Chờ duyệt" icon={<Clock size={14} />} badge={12}>
<DanhSachChoDuyet />
</BSSTab.Pane>
<BSSTab.Pane id="approved" label="Đã duyệt" icon={<Check size={14} />} badge={138}>
<DanhSachDaDuyet />
</BSSTab.Pane>
</BSSTab>
3. Bố cục dọc (Vertical):
<BSSTab tabVertical={true} defaultValue="info">
<BSSTab.Pane id="info" label="Thông tin">
<div>Nội dung cột bên phải...</div>
</BSSTab.Pane>
<BSSTab.Pane id="history" label="Lịch sử">
<div>Nhật ký thay đổi...</div>
</BSSTab.Pane>
</BSSTab>