Chuyển tới nội dung chính

<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 style display).
  • Giao diện đa dạng: Hỗ trợ 2 kiểu (line gạch chân, pills nút bo tròn) và 2 bố cục (ngang chuẩn, hoặc tabVertical dọ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 label dạ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ớiMô tả / Chú ý khi chuyển đổi
Quy tắc ID (T_pn_1)value / onChangeCũ: É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).
Textlabel (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 childrenCũ: 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.
hinhicon (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.
hamonChange / onClickCũ: 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ênKiểuMặc địnhCó thể cóMục đích
childrenReactNode<BSSTab.Pane>Các thẻ con. Bắt buộc phải là BSSTab.Pane.
valuestringID của PaneID của tab đang mở (Controlled mode).
defaultValuestringID của PaneID 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.
onChangefunction(id: string) => voidSự kiện bắn ra khi người dùng chuyển sang tab khác.
variantstring'line''line', 'pills'Kiểu giao diện. 'line' (chỉ có gạch chân), 'pills' (dạng khối màu).
sizestring'sm''sm', 'md'Kích thước của thanh header tab.
fullWidthboolfalsetrue / falseÉp các nút tab dàn trải đều toàn bộ chiều ngang (dùng flex-1).
tabVerticalboolfalsetrue / falseXoay dọc: Thanh chọn tab nằm bên trái, nội dung nằm bên phải.
classNamestring''Class CSS bổ sung cho container ngoài cùng.

Các thuộc tính của Panel con <BSSTab.Pane>​

TênKiểuBắt buộcMục đích
idstringCóĐịnh danh của tab. Khớp với value hoặc defaultValue của thẻ cha.
labelstring / ReactNodeCóChữ hiển thị trên nút tab. Nếu là chuỗi, hệ thống tự động dịch.
iconReactNodeIcon hiển thị bên trái chữ.
badgeReactNodeNhãn đếm số lượng (Ví dụ: 150) hiển thị bên phải chữ.
disabledboolNếu true, nút tab bị làm mờ, không thể click và bỏ qua khi bấm phím tắt.
onClickfunctionHàm gọi khi tab này được click.
childrenReactNodeNội dung của panel.

Hoạt động phía Client​

  • Bóc tách tự động: Khi render, BSSTab dùng React.Children duyệt qua tất cả các thẻ BSSTab.Pane con để trích xuất id, label, icon... nhằm vẽ lên thanh header tab (Tab List). Phần children bên trong Pane sẽ đượ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 ArrowRight hoặc ArrowDown: Chuyển sang tab kế tiếp.
    • Phím ArrowLeft hoặc ArrowUp: 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.
  • 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 hidden củ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>